--- package/package.json (excerpt) ---
{
"name": "@mandujs/cli",
"version": "0.44.16",
"description": "Agent-Native Fullstack Framework - 에이전트가 코딩해도 아키텍처가 무너지지 않는 개발 OS",
"type": "module",
"main": "./src/main.ts",
"bin": {
"mandu": "src/main.ts"
},
"files": [
"src/**/*",
"templates/**/*",
"templates/**/.*",
"generated/**/*",
"scripts/generate-template-manifest.ts",
"scripts/build-binary.ts"
],
"scripts": {
"build:templates": "bun run scripts/generate-template-manifest.ts",
"build:binary": "bun run scripts/build-binary.ts"
},
"keywords": [
"ai",
"agent",
"framework",
"fullstack",
"bun",
"typescript",
"react",
"ssr",
"code-generation"
],
"repository": {
"type": "git",
"url": "git+https://github.com/konamgil/mandu.git",
"directory": "packages/cli"
},
"author": "konamgil",
"license": "MPL-2.0",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@mandujs/core": "^0.54.11",
"@mandujs/mcp": "^0.38.5",
"@mandujs/ate": "^0.26.1",
"@mandujs/edge": "^0.4.59",
"@mandujs/skills": "^0.20.1",
"cfonts": "^3.3.0"
},
"engines": {
"bun": ">=1.3.12"
}
}
--- package/templates/realtime-chat/src/server/application/chat-store.ts (excerpt) ---
import type { ChatMessage } from "@/shared/contracts/chat";
type ChatListener = (event: ChatMessageEvent) => void;
export interface ChatMessageEvent {
eventId: string;
message: ChatMessage;
}
type SubscriptionSnapshot = {
snapshot: ChatMessage[];
commit: () => () => void;
};
export interface ResumePlan {
mode: "catch-up" | "snapshot";
events: ChatMessageEvent[];
}
const listeners = new Set<ChatListener>();
const messages: ChatMessage[] = [];
const MAX_HISTORY_MESSAGES = 200;
const MAX_CATCH_UP_EVENTS = 500;
let storeVersion = 0;
let streamEventSeq = 0;
const catchUpEvents: ChatMessageEvent[] = [];
let testHookBeforeSubscribeCommit: (() => void) | undefined;
function createMessage(role: ChatMessage["role"], text: string): ChatMessage {
return {
id: crypto.randomUUID(),
role,
text,
createdAt: new Date().toISOString(),
};
}
function createEventId(nextSeq: number): string {
return `msg-${nextSeq}`;
}
function parseEventSeq(eventId: string | null | undefined): number | null {
if (!eventId) return null;
const match = /^msg-(\d+)$/.exec(eventId);
if (!match) return null;
const parsed = Number.parseInt(match[1]!, 10);
return Number.isFinite(parsed) ? parsed : null;
}
function pushCatchUpEvent(event: ChatMessageEvent): void {
catchUpEvents.push(event);
if (catchUpEvents.length > MAX_CATCH_UP_EVENTS) {
catchUpEvents.splice(0, catchUpEvents.length - MAX_CATCH_UP_EVENTS);
}
--- package/templates/auth-starter/src/lib/auth.ts (excerpt) ---
/**
* Auth wiring for the demo — session storage + CSRF token helpers.
*
* This module is the single source of truth for:
* 1. the session storage instance (cookie-backed, HMAC-signed)
* 2. the csrf middleware factory (double-submit cookie pattern)
* 3. session/csrf secrets (env-driven, with loud dev fallback)
* 4. `attachAuthContext(ctx)` — runs session() middleware and ensures a
* CSRF cookie/token exists, returning `{ userId, csrfToken }` to
* page loaders so they can embed the token in forms.
*
* Why a helper rather than `.use(csrf())` everywhere: page rendering runs
* the filling loader directly (`filling.executeLoader(ctx)` in server.ts),
* NOT the full handler pipeline, so `.use()` middleware does not execute
* for page GETs. API routes still use the real `session()` + `csrf()`
* middleware via `.use()` — the helper and the middleware share the same
* underlying primitives, so tokens/cookies round-trip cleanly.
*/
import {
createCookieSessionStorage,
type ManduContext,
type SessionStorage,
} from "@mandujs/core";
import { createSqliteSessionStorage } from "@mandujs/core/filling/session-sqlite";
import {
session as sessionMiddleware,
csrf as csrfMiddleware,
} from "@mandujs/core/middleware";
import { currentUserId } from "@mandujs/core/auth";
// Side-effect import: registers Phase 3.1 cron jobs (session GC).
// Every API route + page loader pulls `auth.ts` in, so this is the most
// reliable boo