theokit 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions-virtual-module-E6PU47GV.js +175 -0
- package/dist/actions-virtual-module-E6PU47GV.js.map +1 -0
- package/dist/actions-virtual-module-E7IELVHL.js +174 -0
- package/dist/actions-virtual-module-E7IELVHL.js.map +1 -0
- package/dist/app-typed-client-4L4L4BWD.js +289 -0
- package/dist/app-typed-client-4L4L4BWD.js.map +1 -0
- package/dist/app-typed-client-6PAT6VOL.js +289 -0
- package/dist/app-typed-client-6PAT6VOL.js.map +1 -0
- package/dist/{build-IQQYCA3B.js → build-EWZDEDT3.js} +37 -11
- package/dist/build-EWZDEDT3.js.map +1 -0
- package/dist/build-request-body-preview-EOP2Y4F3.js +52 -0
- package/dist/build-request-body-preview-EOP2Y4F3.js.map +1 -0
- package/dist/build-request-body-preview-II2235E6.js +54 -0
- package/dist/build-request-body-preview-II2235E6.js.map +1 -0
- package/dist/{chunk-GQSTRXXB.js → chunk-2BQYEBCK.js} +77 -68
- package/dist/chunk-2BQYEBCK.js.map +1 -0
- package/dist/{chunk-FRBYJANT.js → chunk-4W447H7M.js} +195 -41
- package/dist/chunk-4W447H7M.js.map +1 -0
- package/dist/chunk-7DHGV77J.js +140 -0
- package/dist/chunk-7DHGV77J.js.map +1 -0
- package/dist/{chunk-WQCPKA2L.js → chunk-C27AZN46.js} +570 -165
- package/dist/chunk-C27AZN46.js.map +1 -0
- package/dist/chunk-ERAZNHHR.js +73 -0
- package/dist/chunk-ERAZNHHR.js.map +1 -0
- package/dist/chunk-F3TG5FJV.js +97 -0
- package/dist/chunk-F3TG5FJV.js.map +1 -0
- package/dist/{chunk-OK2PJOLK.js → chunk-KJVEJILQ.js} +7 -3
- package/dist/chunk-KJVEJILQ.js.map +1 -0
- package/dist/{chunk-JBC7PFV4.js → chunk-M23FP2AS.js} +2 -2
- package/dist/chunk-M23FP2AS.js.map +1 -0
- package/dist/{chunk-S3JBIFKS.js → chunk-MG7H3LAW.js} +2 -2
- package/dist/chunk-MOT42NAH.js +165 -0
- package/dist/chunk-MOT42NAH.js.map +1 -0
- package/dist/{chunk-OEB3OIYP.js → chunk-OJHO2X7C.js} +497 -168
- package/dist/chunk-OJHO2X7C.js.map +1 -0
- package/dist/chunk-QLGES2HC.js +189 -0
- package/dist/chunk-QLGES2HC.js.map +1 -0
- package/dist/{chunk-JZ5WEG3S.js → chunk-SEVYARIU.js} +9 -5
- package/dist/chunk-SEVYARIU.js.map +1 -0
- package/dist/{chunk-ZK5JCE5J.js → chunk-TFECHXR5.js} +201 -43
- package/dist/chunk-TFECHXR5.js.map +1 -0
- package/dist/chunk-WSJKACWB.js +17 -0
- package/dist/chunk-WSJKACWB.js.map +1 -0
- package/dist/{chunk-3Q36SEDK.js → chunk-ZBWROIIO.js} +43 -2
- package/dist/{chunk-3Q36SEDK.js.map → chunk-ZBWROIIO.js.map} +1 -1
- package/dist/chunk-ZOXNJV2O.js +358 -0
- package/dist/chunk-ZOXNJV2O.js.map +1 -0
- package/dist/cli/index.js +22 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/client/index.d.ts +31 -1
- package/dist/client/index.js +100 -0
- package/dist/client/index.js.map +1 -1
- package/dist/{dev-VN6WS3CM.js → dev-74KPI5C5.js} +15 -7
- package/dist/dev-74KPI5C5.js.map +1 -0
- package/dist/dev-emit-3CHM73TV.js +390 -0
- package/dist/dev-emit-3CHM73TV.js.map +1 -0
- package/dist/dev-emit-I3CKOHML.js +44 -0
- package/dist/dev-emit-I3CKOHML.js.map +1 -0
- package/dist/devtools/entry.js +545 -181
- package/dist/devtools/entry.js.map +1 -1
- package/dist/{dispatcher-IK3FVMX5.js → dispatcher-AQJGI3HU.js} +2 -2
- package/dist/dispatcher-E6QV32BO.js +83 -0
- package/dist/dispatcher-E6QV32BO.js.map +1 -0
- package/dist/{dist-Q5VBFWVL.js → dist-R2Q7GVDW.js} +10357 -12068
- package/dist/dist-R2Q7GVDW.js.map +1 -0
- package/dist/{generate-SIO4JSKJ.js → generate-DT4IIAHF.js} +88 -22
- package/dist/generate-DT4IIAHF.js.map +1 -0
- package/dist/index.d.ts +108 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/{info-B3UOXFUF.js → info-VM7EK4JC.js} +3 -3
- package/dist/openapi-CBASKC7W.js +84 -0
- package/dist/openapi-CBASKC7W.js.map +1 -0
- package/dist/{registry-BB3UYAOG.js → registry-QGSNLJKJ.js} +2 -2
- package/dist/{routes-CAGFZKUK.js → routes-7O4NUDYS.js} +9 -7
- package/dist/{routes-CAGFZKUK.js.map → routes-7O4NUDYS.js.map} +1 -1
- package/dist/{schema-Cxq2qqwh.d.ts → schema-CjVly9c_.d.ts} +43 -1
- package/dist/{schema-MVB2FVK6.js → schema-JAKF23GR.js} +2 -2
- package/dist/server/cost/index.js +1 -1
- package/dist/server/index.d.ts +219 -47
- package/dist/server/index.js +35 -116
- package/dist/server/index.js.map +1 -1
- package/dist/{start-ZGWW5MOL.js → start-5JTFWF4T.js} +20 -14
- package/dist/start-5JTFWF4T.js.map +1 -0
- package/dist/{static-BH6JQNM2.js → static-6PZZBY7G.js} +4 -4
- package/dist/{upgrade-readiness-OHL36FQL.js → upgrade-readiness-Q46KTG2J.js} +6 -1
- package/dist/upgrade-readiness-Q46KTG2J.js.map +1 -0
- package/dist/vite-plugin/index.d.ts +25 -1
- package/dist/vite-plugin/index.js +5 -2
- package/dist/{vite-plugin-WA3G45YY.js → vite-plugin-3EQP2JYM.js} +7 -6
- package/package.json +4 -2
- package/dist/build-IQQYCA3B.js.map +0 -1
- package/dist/chunk-FRBYJANT.js.map +0 -1
- package/dist/chunk-GQSTRXXB.js.map +0 -1
- package/dist/chunk-JBC7PFV4.js.map +0 -1
- package/dist/chunk-JZ5WEG3S.js.map +0 -1
- package/dist/chunk-OEB3OIYP.js.map +0 -1
- package/dist/chunk-OK2PJOLK.js.map +0 -1
- package/dist/chunk-WQCPKA2L.js.map +0 -1
- package/dist/chunk-ZK5JCE5J.js.map +0 -1
- package/dist/dev-VN6WS3CM.js.map +0 -1
- package/dist/dist-Q5VBFWVL.js.map +0 -1
- package/dist/generate-SIO4JSKJ.js.map +0 -1
- package/dist/start-ZGWW5MOL.js.map +0 -1
- package/dist/upgrade-readiness-OHL36FQL.js.map +0 -1
- /package/dist/{chunk-S3JBIFKS.js.map → chunk-MG7H3LAW.js.map} +0 -0
- /package/dist/{dispatcher-IK3FVMX5.js.map → dispatcher-AQJGI3HU.js.map} +0 -0
- /package/dist/{info-B3UOXFUF.js.map → info-VM7EK4JC.js.map} +0 -0
- /package/dist/{registry-BB3UYAOG.js.map → registry-QGSNLJKJ.js.map} +0 -0
- /package/dist/{schema-MVB2FVK6.js.map → schema-JAKF23GR.js.map} +0 -0
- /package/dist/{static-BH6JQNM2.js.map → static-6PZZBY7G.js.map} +0 -0
- /package/dist/{vite-plugin-WA3G45YY.js.map → vite-plugin-3EQP2JYM.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/schema.ts"],"sourcesContent":["import { z } from 'zod'\n\nimport { servicesConfigSchema } from '../services/index.js'\n\n/**\n * Base bucket config — legacy shape preserved for backwards compatibility.\n */\nconst baseRateLimitSchema = z.object({\n windowMs: z.number().min(1),\n max: z.number().int().min(1),\n})\n\n/**\n * T2.2 — Per-route + per-user rate limit. The new shape adds `routes`\n * (path map), `keyBy`, and `cookieName`. The legacy flat shape is still\n * accepted via the union — see `createRouteRateLimiter` for normalization.\n */\nexport const rateLimitSchema = z.union([\n baseRateLimitSchema,\n z.object({\n default: baseRateLimitSchema.optional(),\n routes: z.record(z.string(), baseRateLimitSchema).optional(),\n keyBy: z\n .union([\n z.enum(['ip', 'session', 'user']),\n z.function().args(z.unknown()).returns(z.string()),\n ])\n .optional(),\n cookieName: z.string().min(1).optional(),\n }),\n])\n\nexport const uploadSchema = z.object({\n maxFileSize: z\n .number()\n .min(1)\n .default(10 * 1024 * 1024), // 10MB\n maxFiles: z.number().int().min(1).default(10),\n maxFieldSize: z\n .number()\n .min(1)\n .default(1 * 1024 * 1024), // 1MB\n})\n\nexport const loggingSchema = z.object({\n level: z.enum(['debug', 'info', 'warn', 'error', 'silent']).default('info'),\n})\n\n/**\n * Cache subsystem config (caching-and-revalidation-plan).\n * Default `cache: undefined` keeps the framework backward-compatible\n * (no engine initialized → no cache primitives available).\n *\n * Setting `cache: {}` opts in with all defaults.\n */\nconst routeRuleSchema = z.object({\n maxAge: z.number().nonnegative().finite().optional(),\n swr: z.number().nonnegative().finite().optional(),\n tags: z.array(z.string()).optional(),\n})\n\nexport const cacheSchema = z.object({\n enabled: z.boolean().default(true),\n /** 'memory' uses InMemoryCacheAdapter; otherwise pass a custom adapter instance. */\n storage: z.union([z.literal('memory'), z.custom<unknown>()]).default('memory'),\n maxEntries: z.number().int().positive().default(1000),\n defaults: z\n .object({\n maxAge: z.number().nonnegative().finite().default(1),\n swr: z.number().nonnegative().finite().optional(),\n cacheErrors: z.boolean().default(false),\n })\n .default({}),\n keyDerivation: z\n .object({\n excludeQuery: z.array(z.string()).optional(),\n sortQuery: z.boolean().default(true),\n lowercaseHost: z.boolean().default(true),\n })\n .default({}),\n routeRules: z.record(z.string(), routeRuleSchema).optional(),\n})\n\n/**\n * Phase 5 — CSRF warn-first (EC-1).\n *\n * 0.2.0 default: `warn`. Existing apps keep working but get structured\n * warnings about every state-mutating request that does not carry the\n * `X-Theo-Action: 1` header. 0.3.0 will flip the default to `strict`.\n *\n * Set explicitly to `strict` to opt into the future default early,\n * or `off` to disable CSRF entirely (only valid when you have another\n * defense — bearer auth, no session cookies, etc).\n */\n/**\n * Phase 6 — Default security headers (D4 / EC-2).\n *\n * 0.2.0 defaults:\n * - CSP in `report-only` mode (EC-2: don't break existing apps)\n * - X-Frame-Options: DENY · X-Content-Type-Options: nosniff\n * - Referrer-Policy: strict-origin-when-cross-origin\n * - HSTS in production only (no TLS on localhost)\n *\n * Users override individual headers, swap CSP to `enforce`, or disable\n * CSP entirely (`csp: false` / `cspMode: 'off'`).\n */\n/**\n * EC-3 — CWE-113 HTTP Response Splitting mitigation.\n *\n * Every string that becomes a header value must reject CR/LF. Apps that\n * derive header values from untrusted input (feature flags, tenant config,\n * URL params) would otherwise let attackers inject Set-Cookie / Location\n * headers via `\\r\\n`. Apply this refinement to every header-bound string\n * field: permissionsPolicy, csp, hsts, referrerPolicy.\n */\nconst headerSafeString = z\n .string()\n .refine((s) => !/[\\r\\n]/.test(s), { message: 'Header value must not contain CR/LF' })\n\nexport const securityHeadersSchema = z.object({\n csp: z.union([headerSafeString, z.literal(false)]).optional(),\n // T6.1 — default flipped from 'report-only' to 'enforce' for 0.3.0.\n // Users who want the old behaviour set `cspMode: 'report-only'`\n // explicitly. See docs/migrating/0.2-to-0.3.md.\n cspMode: z.enum(['enforce', 'report-only', 'off']).default('enforce'),\n hsts: z.union([headerSafeString, z.literal(false)]).optional(),\n frameOptions: z.enum(['DENY', 'SAMEORIGIN']).default('DENY'),\n contentTypeOptions: z.literal('nosniff').default('nosniff'),\n referrerPolicy: headerSafeString.default('strict-origin-when-cross-origin'),\n /**\n * T1.1 — Permissions-Policy directive string. EC-3-refined: rejects CR/LF.\n * Pass `false` to suppress the header.\n */\n permissionsPolicy: z.union([headerSafeString, z.literal(false)]).optional(),\n})\n\n/**\n * T5.1 — Disallowed-routes escalation pattern (Rails-inspired).\n *\n * `routes` accepts string (exact match — trailing slash matters) or\n * RegExp entries. Matched routes that would otherwise emit `csrf.warn`\n * dispatch through `disallowedBehavior` instead:\n * - `'warn'` : no-op vs the default warn-mode behavior\n * - `'raise'` : escalate to 403, even when global `csrf` mode is 'warn'\n *\n * Use to roll out strict mode per-route (e.g., flip /api/auth/* first)\n * without committing the entire surface to strict at once.\n */\nexport const disallowedConfigSchema = z.object({\n routes: z.array(z.union([z.string(), z.instanceof(RegExp)])),\n behavior: z.enum(['warn', 'raise']).default('raise'),\n})\n\n/**\n * T1.2 — CORS configuration.\n *\n * `origins` accepts a single value (`'*'`, string, RegExp, callback) OR an\n * array of (string | RegExp). The spec-violating `origins: '*'` +\n * `credentials: true` combination is rejected at parse time (browsers\n * ignore wildcards when credentials are sent).\n *\n * EC-3 — `allowedHeaders` and `exposedHeaders` entries go through the\n * header-safe refinement (CR/LF rejected — CWE-113 mitigation).\n */\nexport const corsSchema = z\n .object({\n origins: z.union([\n z.literal('*'),\n headerSafeString,\n z.instanceof(RegExp),\n z.array(z.union([headerSafeString, z.instanceof(RegExp)])),\n z.function().args(z.string()).returns(z.boolean()),\n ]),\n methods: z\n .array(z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD']))\n .optional(),\n allowedHeaders: z.array(headerSafeString).optional(),\n exposedHeaders: z.array(headerSafeString).optional(),\n credentials: z.boolean().default(false),\n maxAge: z.number().int().min(0).max(86400).default(600),\n })\n .refine((c) => !(c.origins === '*' && c.credentials), {\n message: 'CORS spec forbids origins:\"*\" with credentials:true — browsers ignore the wildcard',\n })\n\nexport const securitySchema = z.object({\n // T6.1 — default flipped from 'warn' to 'strict' for 0.3.0. Apps that\n // grep their warn-mode logs from 0.2.x already know which endpoints\n // break; opt back into 'warn' globally OR use disallowedRoutes for\n // surgical migration. See docs/migrating/0.2-to-0.3.md.\n csrf: z.enum(['off', 'warn', 'strict']).default('strict'),\n headers: securityHeadersSchema.optional(),\n /** T5.1 — per-route escalation (Rails disallowed_warnings pattern). */\n disallowed: disallowedConfigSchema.optional(),\n /** T1.2 — Cross-Origin Resource Sharing. Single global config; runs first in pipeline. */\n cors: corsSchema.optional(),\n})\n\n/**\n * StorageManager schemas (T1.1 / ADR-0007 D4).\n *\n * `theo.config.ts > storage` declares Postgres servers (credentials), the\n * databases on each server (TheoCloud / managed PG / self-host), and Redis\n * servers. The runtime `StorageManager` consumes this block; adapters\n * (PostgresJobBackend, PostgresConversationStorage, etc.) request pools by\n * database name and never see raw credentials at the call site.\n *\n * EC-1 (DOCUMENT in concept doc T4.1): Zod default strip-unknown mode\n * silently drops typo keys (`databasees` instead of `databases`). The\n * concept doc warns users to use exact names; runtime errors are still\n * actionable (`Database \"X\" not configured`).\n *\n * EC-2 (DEFERRED to use-time): `databases.X.server` references a key in\n * `servers`. Cross-field validation is intentionally NOT enforced at parse\n * time — `StorageManager.usePostgres()` throws an actionable error on the\n * first call with the dangling reference, matching Rails / Nitro behavior.\n */\nconst tlsConfigSchema = z.object({\n rejectUnauthorized: z.boolean().optional(),\n caCert: z.string().optional(),\n clientCert: z.string().optional(),\n clientKey: z.string().optional(),\n})\n\nconst serverConfigSchema = z.object({\n host: z.string().min(1),\n port: z.number().int().positive().max(65535).optional(),\n user: z.string().min(1),\n /** Password may be the empty string (some providers permit it). */\n password: z.string(),\n tls: tlsConfigSchema.optional(),\n})\n\nconst postgresPoolConfigSchema = z.object({\n min: z.number().int().nonnegative().optional(),\n max: z.number().int().positive().optional(),\n connectionTimeoutMillis: z.number().int().positive().optional(),\n idleTimeoutMillis: z.number().int().nonnegative().optional(),\n})\n\nconst postgresDatabaseConfigSchema = z.object({\n /** References a key in `storage.servers`. Resolved at `usePostgres()` call time. */\n server: z.string().min(1),\n database: z.string().min(1),\n pool: postgresPoolConfigSchema.optional(),\n})\n\nconst redisServerConfigSchema = serverConfigSchema.extend({\n db: z.number().int().nonnegative().optional(),\n maxRetriesPerRequest: z.number().int().nonnegative().optional(),\n})\n\nexport const storageSchema = z.object({\n servers: z.record(z.string(), serverConfigSchema).optional(),\n databases: z.record(z.string(), postgresDatabaseConfigSchema).optional(),\n redis: z.record(z.string(), redisServerConfigSchema).optional(),\n})\n\nexport type StorageConfig = z.infer<typeof storageSchema>\n\nexport const theoConfigSchema = z\n .object({\n appDir: z.string().default('app'),\n serverDir: z.string().default('server'),\n /**\n * T2.2 / EC-4 — Build output directory. Must be a relative path inside\n * the project root. Refused absolute or parent-relative paths to prevent\n * `cleanOutDir` from wiping arbitrary locations (defense-in-depth on\n * top of cleanOutDir's runtime EC-3 guard).\n */\n distDir: z\n .string()\n .default('.theo')\n .refine(\n (d) => !/^([A-Za-z]:)?[/\\\\]/.test(d) && !d.startsWith('..'),\n 'distDir must be a relative path inside the project root (e.g., \".theo\")',\n ),\n /**\n * Agent runtime configuration.\n *\n * - `maxRegistries` (T2.3, legacy): dev-mode cleanup of stale\n * `.theokit/agents/<id>/` dirs by mtime. Now superseded by SDK's\n * native registry GC but kept for backward-compat.\n * - `registry` (Phase 6, Production-Readiness #2): forwarded to\n * `Agent.registry.configure()` lazily on first request.\n * * `maxAgents` — LRU cap. MUST be ≥ max-concurrent-active-conversations\n * (EC-17 DOCUMENT): with maxAgents:1 and 2 concurrent chats, LRU evicts\n * mid-stream → SDK aborts with code:'aborted'. Default 100 covers\n * indie/small-team; tune up for high-traffic.\n * * `idleTimeoutMs` — auto-evict idle agents (default 30 min). 0 disables\n * idle eviction (LRU only).\n */\n agents: z\n .object({\n maxRegistries: z.number().int().positive().default(100),\n registry: z\n .object({\n /** LRU cap — MUST be ≥ max-concurrent-active-conversations. */\n maxAgents: z.number().int().positive().max(10_000).default(100),\n /** Idle eviction window in ms. 0 disables idle eviction (LRU only). */\n idleTimeoutMs: z\n .number()\n .int()\n .nonnegative()\n .default(30 * 60_000),\n })\n .optional(),\n })\n .optional(),\n port: z.number().int().min(1).max(65535).default(3000),\n ssr: z.boolean().default(false),\n /** When true (and ssr === true), use renderToPipeableStream with progressive\n * shell flush instead of single-shot renderToString. Opt-in for streaming\n * SSR; default false preserves the current behavior. */\n ssrStreaming: z.boolean().default(false),\n rateLimit: rateLimitSchema.optional(),\n upload: uploadSchema.optional(),\n logging: loggingSchema.optional(),\n security: securitySchema.optional(),\n serialization: z.enum(['json', 'superjson']).default('json'),\n // Plugins are validated structurally at runtime by createPluginRunnerFromConfig.\n // Zod only checks the shape minimally (must be array). Type-level safety is\n // provided through defineConfig at the user surface.\n plugins: z.array(z.unknown()).optional(),\n /** Enable client-side batching of theoFetch calls and the\n * /api/__theo_batch__ server endpoint. */\n batching: z\n .union([z.boolean(), z.object({ max: z.number().int().positive().optional() })])\n .optional(),\n /** T4.1 — Audit log. When `logger` is provided, framework events\n * (csrf.warn, rate-limit.exceeded, session.rotated, csp.violation) are\n * emitted to it. Default: noop. */\n audit: z\n .object({\n logger: z.unknown().optional(),\n })\n .optional(),\n /** TheoUI auto-wire (T2.1). `false` = opt-out; object = explicit theme/fonts;\n * undefined = enabled when @usetheo/ui is detected in node_modules. */\n ui: z\n .union([\n z.literal(false),\n z.object({\n theme: z.enum(['violet-forge', 'noir', 'paper']).optional(),\n fonts: z.enum(['bundled', 'cdn']).optional(),\n }),\n ])\n .optional(),\n /**\n * Cache subsystem (caching-and-revalidation-plan).\n * Default `undefined` keeps caching disabled (backward compatible).\n * Pass `cache: {}` to opt in with defaults.\n */\n cache: cacheSchema.optional(),\n /**\n * Devtools overlay (Phase 0.4.0+ — see docs/plans/devtools-plan.md).\n *\n * - `undefined` (default): devtools auto-injects in `pnpm dev`, NEVER in `vite build`.\n * - `false`: devtools disabled entirely (Vite plugin skips injection even in dev).\n * - `{ ... }`: devtools enabled with explicit defaults (position, theme).\n *\n * Tree-shaken to noop in prod via the dual-export pattern in\n * `packages/theo/src/devtools/index.ts` (EC-17 positive prod check).\n */\n devtools: z\n .union([\n z.literal(false),\n z.object({\n position: z.enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']).optional(),\n theme: z.enum(['light', 'dark', 'system']).optional(),\n }),\n ])\n .optional(),\n /**\n * Informative list of deploy adapters the app supports. Does NOT\n * trigger per-build translations — only the `--target` CLI flag does\n * (EC-201 / ADR D2). If `config.adapters` includes a target NOT\n * matching `--target`, `theokit build` emits a cross-reference note.\n */\n adapters: z.array(z.string()).optional(),\n /**\n * Jobs backend (ADR D3 + T2.1). When configured, every request gets\n * `ctx.queue.enqueue` auto-wired via the outbox lifecycle. Pass a\n * `JobBackend` instance (InMemoryJobBackend, PostgresJobBackend, etc.).\n */\n jobs: z\n .object({\n backend: z.custom<unknown>((v) => typeof v === 'object' && v !== null),\n })\n .optional(),\n /**\n * StorageManager configuration (T1.1 / ADR-0007).\n *\n * Declares Postgres servers + databases + Redis servers. Consumed by\n * `getStorageManager().configure()` at boot via `start.ts`.\n *\n * Default `undefined` means manager exists but is not configured — adapters\n * relying on the manager (PostgresJobBackend.fromStorageManager, etc.) will\n * throw with an actionable error on first use.\n */\n storage: storageSchema.optional(),\n /**\n * Wave 2 — Polyglot services orchestration (T1.1 / ADR-0012/0013/0014/0015).\n *\n * Declarative external sidecar processes (Python FastAPI / Node Hono)\n * that boot alongside the TheoKit TS app. Empty `services: {}` is the\n * default and preserves Wave 1 behavior.\n */\n services: servicesConfigSchema,\n })\n // EC-2 fix: cross-config refine — no service may share TheoKit's web port.\n .refine((cfg) => !Object.values(cfg.services).some((s) => s.port === cfg.port), {\n message: 'service.port collides with TheoKit web port — change one of them',\n path: ['services'],\n })\n\nexport type TheoConfig = z.infer<typeof theoConfigSchema>\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/config/schema.ts"],"sourcesContent":["import { z } from 'zod'\n\nimport { servicesConfigSchema } from '../services/index.js'\n\n/**\n * Base bucket config — legacy shape preserved for backwards compatibility.\n */\nconst baseRateLimitSchema = z.object({\n windowMs: z.number().min(1),\n max: z.number().int().min(1),\n})\n\n/**\n * T2.2 — Per-route + per-user rate limit. The new shape adds `routes`\n * (path map), `keyBy`, and `cookieName`. The legacy flat shape is still\n * accepted via the union — see `createRouteRateLimiter` for normalization.\n */\nexport const rateLimitSchema = z.union([\n baseRateLimitSchema,\n z.object({\n default: baseRateLimitSchema.optional(),\n routes: z.record(z.string(), baseRateLimitSchema).optional(),\n keyBy: z\n .union([\n z.enum(['ip', 'session', 'user']),\n z.function().args(z.unknown()).returns(z.string()),\n ])\n .optional(),\n cookieName: z.string().min(1).optional(),\n }),\n])\n\nexport const uploadSchema = z.object({\n maxFileSize: z\n .number()\n .min(1)\n .default(10 * 1024 * 1024), // 10MB\n maxFiles: z.number().int().min(1).default(10),\n maxFieldSize: z\n .number()\n .min(1)\n .default(1 * 1024 * 1024), // 1MB\n})\n\nexport const loggingSchema = z.object({\n level: z.enum(['debug', 'info', 'warn', 'error', 'silent']).default('info'),\n})\n\n/**\n * Cache subsystem config (caching-and-revalidation-plan).\n * Default `cache: undefined` keeps the framework backward-compatible\n * (no engine initialized → no cache primitives available).\n *\n * Setting `cache: {}` opts in with all defaults.\n */\nconst routeRuleSchema = z.object({\n maxAge: z.number().nonnegative().finite().optional(),\n swr: z.number().nonnegative().finite().optional(),\n tags: z.array(z.string()).optional(),\n})\n\nexport const cacheSchema = z.object({\n enabled: z.boolean().default(true),\n /** 'memory' uses InMemoryCacheAdapter; otherwise pass a custom adapter instance. */\n storage: z.union([z.literal('memory'), z.custom<unknown>()]).default('memory'),\n maxEntries: z.number().int().positive().default(1000),\n defaults: z\n .object({\n maxAge: z.number().nonnegative().finite().default(1),\n swr: z.number().nonnegative().finite().optional(),\n cacheErrors: z.boolean().default(false),\n })\n .default({}),\n keyDerivation: z\n .object({\n excludeQuery: z.array(z.string()).optional(),\n sortQuery: z.boolean().default(true),\n lowercaseHost: z.boolean().default(true),\n })\n .default({}),\n routeRules: z.record(z.string(), routeRuleSchema).optional(),\n})\n\n/**\n * Phase 5 — CSRF warn-first (EC-1).\n *\n * 0.2.0 default: `warn`. Existing apps keep working but get structured\n * warnings about every state-mutating request that does not carry the\n * `X-Theo-Action: 1` header. 0.3.0 will flip the default to `strict`.\n *\n * Set explicitly to `strict` to opt into the future default early,\n * or `off` to disable CSRF entirely (only valid when you have another\n * defense — bearer auth, no session cookies, etc).\n */\n/**\n * Phase 6 — Default security headers (D4 / EC-2).\n *\n * 0.2.0 defaults:\n * - CSP in `report-only` mode (EC-2: don't break existing apps)\n * - X-Frame-Options: DENY · X-Content-Type-Options: nosniff\n * - Referrer-Policy: strict-origin-when-cross-origin\n * - HSTS in production only (no TLS on localhost)\n *\n * Users override individual headers, swap CSP to `enforce`, or disable\n * CSP entirely (`csp: false` / `cspMode: 'off'`).\n */\n/**\n * EC-3 — CWE-113 HTTP Response Splitting mitigation.\n *\n * Every string that becomes a header value must reject CR/LF. Apps that\n * derive header values from untrusted input (feature flags, tenant config,\n * URL params) would otherwise let attackers inject Set-Cookie / Location\n * headers via `\\r\\n`. Apply this refinement to every header-bound string\n * field: permissionsPolicy, csp, hsts, referrerPolicy.\n */\nconst headerSafeString = z\n .string()\n .refine((s) => !/[\\r\\n]/.test(s), { message: 'Header value must not contain CR/LF' })\n\nexport const securityHeadersSchema = z.object({\n csp: z.union([headerSafeString, z.literal(false)]).optional(),\n // T6.1 — default flipped from 'report-only' to 'enforce' for 0.3.0.\n // Users who want the old behaviour set `cspMode: 'report-only'`\n // explicitly. See docs/migrating/0.2-to-0.3.md.\n cspMode: z.enum(['enforce', 'report-only', 'off']).default('enforce'),\n hsts: z.union([headerSafeString, z.literal(false)]).optional(),\n frameOptions: z.enum(['DENY', 'SAMEORIGIN']).default('DENY'),\n contentTypeOptions: z.literal('nosniff').default('nosniff'),\n referrerPolicy: headerSafeString.default('strict-origin-when-cross-origin'),\n /**\n * T1.1 — Permissions-Policy directive string. EC-3-refined: rejects CR/LF.\n * Pass `false` to suppress the header.\n */\n permissionsPolicy: z.union([headerSafeString, z.literal(false)]).optional(),\n})\n\n/**\n * T5.1 — Disallowed-routes escalation pattern (Rails-inspired).\n *\n * `routes` accepts string (exact match — trailing slash matters) or\n * RegExp entries. Matched routes that would otherwise emit `csrf.warn`\n * dispatch through `disallowedBehavior` instead:\n * - `'warn'` : no-op vs the default warn-mode behavior\n * - `'raise'` : escalate to 403, even when global `csrf` mode is 'warn'\n *\n * Use to roll out strict mode per-route (e.g., flip /api/auth/* first)\n * without committing the entire surface to strict at once.\n */\nexport const disallowedConfigSchema = z.object({\n routes: z.array(z.union([z.string(), z.instanceof(RegExp)])),\n behavior: z.enum(['warn', 'raise']).default('raise'),\n})\n\n/**\n * T1.2 — CORS configuration.\n *\n * `origins` accepts a single value (`'*'`, string, RegExp, callback) OR an\n * array of (string | RegExp). The spec-violating `origins: '*'` +\n * `credentials: true` combination is rejected at parse time (browsers\n * ignore wildcards when credentials are sent).\n *\n * EC-3 — `allowedHeaders` and `exposedHeaders` entries go through the\n * header-safe refinement (CR/LF rejected — CWE-113 mitigation).\n */\nexport const corsSchema = z\n .object({\n origins: z.union([\n z.literal('*'),\n headerSafeString,\n z.instanceof(RegExp),\n z.array(z.union([headerSafeString, z.instanceof(RegExp)])),\n z.function().args(z.string()).returns(z.boolean()),\n ]),\n methods: z\n .array(z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD']))\n .optional(),\n allowedHeaders: z.array(headerSafeString).optional(),\n exposedHeaders: z.array(headerSafeString).optional(),\n credentials: z.boolean().default(false),\n maxAge: z.number().int().min(0).max(86400).default(600),\n })\n .refine((c) => !(c.origins === '*' && c.credentials), {\n message: 'CORS spec forbids origins:\"*\" with credentials:true — browsers ignore the wildcard',\n })\n\nexport const securitySchema = z.object({\n // T6.1 — default flipped from 'warn' to 'strict' for 0.3.0. Apps that\n // grep their warn-mode logs from 0.2.x already know which endpoints\n // break; opt back into 'warn' globally OR use disallowedRoutes for\n // surgical migration. See docs/migrating/0.2-to-0.3.md.\n csrf: z.enum(['off', 'warn', 'strict']).default('strict'),\n headers: securityHeadersSchema.optional(),\n /** T5.1 — per-route escalation (Rails disallowed_warnings pattern). */\n disallowed: disallowedConfigSchema.optional(),\n /** T1.2 — Cross-Origin Resource Sharing. Single global config; runs first in pipeline. */\n cors: corsSchema.optional(),\n})\n\n/**\n * StorageManager schemas (T1.1 / ADR-0007 D4).\n *\n * `theo.config.ts > storage` declares Postgres servers (credentials), the\n * databases on each server (TheoCloud / managed PG / self-host), and Redis\n * servers. The runtime `StorageManager` consumes this block; adapters\n * (PostgresJobBackend, PostgresConversationStorage, etc.) request pools by\n * database name and never see raw credentials at the call site.\n *\n * EC-1 (DOCUMENT in concept doc T4.1): Zod default strip-unknown mode\n * silently drops typo keys (`databasees` instead of `databases`). The\n * concept doc warns users to use exact names; runtime errors are still\n * actionable (`Database \"X\" not configured`).\n *\n * EC-2 (DEFERRED to use-time): `databases.X.server` references a key in\n * `servers`. Cross-field validation is intentionally NOT enforced at parse\n * time — `StorageManager.usePostgres()` throws an actionable error on the\n * first call with the dangling reference, matching Rails / Nitro behavior.\n */\nconst tlsConfigSchema = z.object({\n rejectUnauthorized: z.boolean().optional(),\n caCert: z.string().optional(),\n clientCert: z.string().optional(),\n clientKey: z.string().optional(),\n})\n\nconst serverConfigSchema = z.object({\n host: z.string().min(1),\n port: z.number().int().positive().max(65535).optional(),\n user: z.string().min(1),\n /** Password may be the empty string (some providers permit it). */\n password: z.string(),\n tls: tlsConfigSchema.optional(),\n})\n\nconst postgresPoolConfigSchema = z.object({\n min: z.number().int().nonnegative().optional(),\n max: z.number().int().positive().optional(),\n connectionTimeoutMillis: z.number().int().positive().optional(),\n idleTimeoutMillis: z.number().int().nonnegative().optional(),\n})\n\nconst postgresDatabaseConfigSchema = z.object({\n /** References a key in `storage.servers`. Resolved at `usePostgres()` call time. */\n server: z.string().min(1),\n database: z.string().min(1),\n pool: postgresPoolConfigSchema.optional(),\n})\n\nconst redisServerConfigSchema = serverConfigSchema.extend({\n db: z.number().int().nonnegative().optional(),\n maxRetriesPerRequest: z.number().int().nonnegative().optional(),\n})\n\nexport const storageSchema = z.object({\n servers: z.record(z.string(), serverConfigSchema).optional(),\n databases: z.record(z.string(), postgresDatabaseConfigSchema).optional(),\n redis: z.record(z.string(), redisServerConfigSchema).optional(),\n})\n\nexport type StorageConfig = z.infer<typeof storageSchema>\n\nexport const theoConfigSchema = z\n .object({\n appDir: z.string().default('app'),\n serverDir: z.string().default('server'),\n /**\n * T2.2 / EC-4 — Build output directory. Must be a relative path inside\n * the project root. Refused absolute or parent-relative paths to prevent\n * `cleanOutDir` from wiping arbitrary locations (defense-in-depth on\n * top of cleanOutDir's runtime EC-3 guard).\n */\n distDir: z\n .string()\n .default('.theo')\n .refine(\n (d) => !/^([A-Za-z]:)?[/\\\\]/.test(d) && !d.startsWith('..'),\n 'distDir must be a relative path inside the project root (e.g., \".theo\")',\n ),\n /**\n * Agent runtime configuration.\n *\n * - `maxRegistries` (T2.3, legacy): dev-mode cleanup of stale\n * `.theokit/agents/<id>/` dirs by mtime. Now superseded by SDK's\n * native registry GC but kept for backward-compat.\n * - `registry` (Phase 6, Production-Readiness #2): forwarded to\n * `Agent.registry.configure()` lazily on first request.\n * * `maxAgents` — LRU cap. MUST be ≥ max-concurrent-active-conversations\n * (EC-17 DOCUMENT): with maxAgents:1 and 2 concurrent chats, LRU evicts\n * mid-stream → SDK aborts with code:'aborted'. Default 100 covers\n * indie/small-team; tune up for high-traffic.\n * * `idleTimeoutMs` — auto-evict idle agents (default 30 min). 0 disables\n * idle eviction (LRU only).\n */\n agents: z\n .object({\n maxRegistries: z.number().int().positive().default(100),\n registry: z\n .object({\n /** LRU cap — MUST be ≥ max-concurrent-active-conversations. */\n maxAgents: z.number().int().positive().max(10_000).default(100),\n /** Idle eviction window in ms. 0 disables idle eviction (LRU only). */\n idleTimeoutMs: z\n .number()\n .int()\n .nonnegative()\n .default(30 * 60_000),\n })\n .optional(),\n })\n .optional(),\n port: z.number().int().min(1).max(65535).default(3000),\n ssr: z.boolean().default(false),\n /** When true (and ssr === true), use renderToPipeableStream with progressive\n * shell flush instead of single-shot renderToString. Opt-in for streaming\n * SSR; default false preserves the current behavior. */\n ssrStreaming: z.boolean().default(false),\n rateLimit: rateLimitSchema.optional(),\n upload: uploadSchema.optional(),\n logging: loggingSchema.optional(),\n security: securitySchema.optional(),\n serialization: z.enum(['json', 'superjson']).default('json'),\n // Plugins are validated structurally at runtime by createPluginRunnerFromConfig.\n // Zod only checks the shape minimally (must be array). Type-level safety is\n // provided through defineConfig at the user surface.\n plugins: z.array(z.unknown()).optional(),\n /** Enable client-side batching of theoFetch calls and the\n * /api/__theo_batch__ server endpoint. */\n batching: z\n .union([z.boolean(), z.object({ max: z.number().int().positive().optional() })])\n .optional(),\n /** T4.1 — Audit log. When `logger` is provided, framework events\n * (csrf.warn, rate-limit.exceeded, session.rotated, csp.violation) are\n * emitted to it. Default: noop. */\n audit: z\n .object({\n logger: z.unknown().optional(),\n })\n .optional(),\n /** TheoUI auto-wire (T2.1). `false` = opt-out; object = explicit theme/fonts;\n * undefined = enabled when @usetheo/ui is detected in node_modules. */\n ui: z\n .union([\n z.literal(false),\n z.object({\n theme: z.enum(['violet-forge', 'noir', 'paper']).optional(),\n fonts: z.enum(['bundled', 'cdn']).optional(),\n }),\n ])\n .optional(),\n /**\n * Cache subsystem (caching-and-revalidation-plan).\n * Default `undefined` keeps caching disabled (backward compatible).\n * Pass `cache: {}` to opt in with defaults.\n */\n cache: cacheSchema.optional(),\n /**\n * Devtools overlay (Phase 0.4.0+ — see docs/plans/devtools-plan.md).\n *\n * - `undefined` (default): devtools auto-injects in `pnpm dev`, NEVER in `vite build`.\n * - `false`: devtools disabled entirely (Vite plugin skips injection even in dev).\n * - `{ ... }`: devtools enabled with explicit defaults (position, theme).\n *\n * Tree-shaken to noop in prod via the dual-export pattern in\n * `packages/theo/src/devtools/index.ts` (EC-17 positive prod check).\n */\n devtools: z\n .union([\n z.literal(false),\n z.object({\n position: z.enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']).optional(),\n theme: z.enum(['light', 'dark', 'system']).optional(),\n }),\n ])\n .optional(),\n /**\n * Informative list of deploy adapters the app supports. Does NOT\n * trigger per-build translations — only the `--target` CLI flag does\n * (EC-201 / ADR D2). If `config.adapters` includes a target NOT\n * matching `--target`, `theokit build` emits a cross-reference note.\n */\n adapters: z.array(z.string()).optional(),\n /**\n * Extra package names to pre-bundle via Vite's `optimizeDeps.include`.\n *\n * Framework auto-includes `@usetheo/ui` and `lucide-react` when present.\n * Apps adding plugin peer-deps that rely on a runtime `import('<pkg>')`\n * (dynamic specifier) — e.g. `@theokit/plugin-canvas` consumers\n * installing `mermaid` for Mermaid SVG rendering — must declare those\n * here so Vite can resolve the literal in dev mode without\n * \"Failed to resolve module specifier\" errors. Production builds use\n * tsup/esbuild bundling and are not affected.\n *\n * Example:\n * viteOptimizeDeps: ['mermaid']\n */\n viteOptimizeDeps: z.array(z.string()).optional(),\n /**\n * Jobs backend (ADR D3 + T2.1). When configured, every request gets\n * `ctx.queue.enqueue` auto-wired via the outbox lifecycle. Pass a\n * `JobBackend` instance (InMemoryJobBackend, PostgresJobBackend, etc.).\n */\n jobs: z\n .object({\n backend: z.custom<unknown>((v) => typeof v === 'object' && v !== null),\n })\n .optional(),\n /**\n * StorageManager configuration (T1.1 / ADR-0007).\n *\n * Declares Postgres servers + databases + Redis servers. Consumed by\n * `getStorageManager().configure()` at boot via `start.ts`.\n *\n * Default `undefined` means manager exists but is not configured — adapters\n * relying on the manager (PostgresJobBackend.fromStorageManager, etc.) will\n * throw with an actionable error on first use.\n */\n storage: storageSchema.optional(),\n /**\n * Wave 2 — Polyglot services orchestration (T1.1 / ADR-0012/0013/0014/0015).\n *\n * Declarative external sidecar processes (Python FastAPI / Node Hono)\n * that boot alongside the TheoKit TS app. Empty `services: {}` is the\n * default and preserves Wave 1 behavior.\n */\n services: servicesConfigSchema,\n /**\n * G2 — OpenAPI emit (build-time only).\n *\n * When present, `theokit build` writes a generated `openapi.json` from\n * every `defineRoute()` body/query/params Zod schema. `undefined` keeps\n * the framework backward-compatible (no emit). Pass `openapi: {}` to\n * opt in with defaults.\n *\n * Defaults: spec 3.1.0 · servers `http://localhost:3000` · title\n * \"TheoKit App\" · version \"0.0.0\" · outDir \".theo\" (next to dist).\n *\n * The env var `THEOKIT_OPENAPI_SERVERS` (CSV of URLs) overrides\n * `servers[].url` at emit time without rebuilding the config.\n */\n openapi: z\n .object({\n servers: z\n .array(\n z.object({\n url: z.string().url(),\n description: z.string().optional(),\n }),\n )\n .default([{ url: 'http://localhost:3000', description: 'Local development' }]),\n specVersion: z.enum(['3.1.0', '3.0.3']).default('3.1.0'),\n title: z.string().default('TheoKit App'),\n version: z.string().default('0.0.0'),\n outDir: z.string().default('.theo'),\n })\n .optional(),\n })\n // EC-2 fix: cross-config refine — no service may share TheoKit's web port.\n .refine((cfg) => !Object.values(cfg.services).some((s) => s.port === cfg.port), {\n message: 'service.port collides with TheoKit web port — change one of them',\n path: ['services'],\n })\n\nexport type TheoConfig = z.infer<typeof theoConfigSchema>\n\nexport type OpenApiConfig = NonNullable<TheoConfig['openapi']>\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "tsx/esm";
|
|
3
|
+
|
|
4
|
+
// src/vite-plugin/openapi-emit/emit.ts
|
|
5
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
|
|
8
|
+
// src/vite-plugin/openapi-emit/zod-to-openapi.ts
|
|
9
|
+
var ZodToOpenApiError = class extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "ZodToOpenApiError";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function zodToOpenApiSchema(schema, options = {}) {
|
|
16
|
+
const ctx = options.ctx ?? { seen: /* @__PURE__ */ new Map(), components: {} };
|
|
17
|
+
const name = options.name;
|
|
18
|
+
if (name !== void 0) {
|
|
19
|
+
if (Object.prototype.hasOwnProperty.call(ctx.components, name)) {
|
|
20
|
+
return { $ref: `#/components/schemas/${name}` };
|
|
21
|
+
}
|
|
22
|
+
ctx.seen.set(schema, name);
|
|
23
|
+
ctx.components[name] = {};
|
|
24
|
+
const body = convert(schema, ctx);
|
|
25
|
+
ctx.components[name] = body;
|
|
26
|
+
return { $ref: `#/components/schemas/${name}` };
|
|
27
|
+
}
|
|
28
|
+
return convert(schema, ctx);
|
|
29
|
+
}
|
|
30
|
+
function convert(schema, ctx) {
|
|
31
|
+
const existing = ctx.seen.get(schema);
|
|
32
|
+
if (existing !== void 0) {
|
|
33
|
+
return { $ref: `#/components/schemas/${existing}` };
|
|
34
|
+
}
|
|
35
|
+
const def = schema._def;
|
|
36
|
+
const typeName = def.typeName ?? "";
|
|
37
|
+
switch (typeName) {
|
|
38
|
+
case "ZodString":
|
|
39
|
+
return convertString(schema);
|
|
40
|
+
case "ZodNumber":
|
|
41
|
+
return convertNumber(schema);
|
|
42
|
+
case "ZodBoolean":
|
|
43
|
+
return { type: "boolean" };
|
|
44
|
+
case "ZodLiteral":
|
|
45
|
+
return convertLiteral(schema);
|
|
46
|
+
case "ZodEnum":
|
|
47
|
+
return convertEnum(schema);
|
|
48
|
+
case "ZodArray":
|
|
49
|
+
return convertArray(schema, ctx);
|
|
50
|
+
case "ZodObject":
|
|
51
|
+
return convertObject(schema, ctx);
|
|
52
|
+
case "ZodUnion":
|
|
53
|
+
return convertUnion(schema, ctx);
|
|
54
|
+
case "ZodDiscriminatedUnion":
|
|
55
|
+
return convertDiscriminatedUnion(schema, ctx);
|
|
56
|
+
case "ZodOptional":
|
|
57
|
+
return convert(schema._def.innerType, ctx);
|
|
58
|
+
case "ZodNullable": {
|
|
59
|
+
const inner = convert(
|
|
60
|
+
schema._def.innerType,
|
|
61
|
+
ctx
|
|
62
|
+
);
|
|
63
|
+
return { ...inner, nullable: true };
|
|
64
|
+
}
|
|
65
|
+
case "ZodEffects":
|
|
66
|
+
case "ZodTransform":
|
|
67
|
+
return convert(schema._def.schema, ctx);
|
|
68
|
+
case "ZodDefault":
|
|
69
|
+
return convert(schema._def.innerType, ctx);
|
|
70
|
+
case "ZodLazy": {
|
|
71
|
+
const getter = schema._def.getter;
|
|
72
|
+
return convert(getter(), ctx);
|
|
73
|
+
}
|
|
74
|
+
case "ZodRecord": {
|
|
75
|
+
const valueType = schema._def.valueType;
|
|
76
|
+
return { type: "object", additionalProperties: convert(valueType, ctx) };
|
|
77
|
+
}
|
|
78
|
+
case "ZodAny":
|
|
79
|
+
case "ZodUnknown":
|
|
80
|
+
return {};
|
|
81
|
+
// no constraint
|
|
82
|
+
case "ZodNull":
|
|
83
|
+
return { type: "null" };
|
|
84
|
+
case "ZodFunction":
|
|
85
|
+
throw new ZodToOpenApiError(
|
|
86
|
+
"Unsupported Zod type: z.function() cannot be represented in OpenAPI Schema. Remove from the route schema."
|
|
87
|
+
);
|
|
88
|
+
case "ZodPromise":
|
|
89
|
+
throw new ZodToOpenApiError(
|
|
90
|
+
"Unsupported Zod type: z.promise() cannot be represented in OpenAPI Schema. Unwrap the value before passing to defineRoute."
|
|
91
|
+
);
|
|
92
|
+
default:
|
|
93
|
+
throw new ZodToOpenApiError(
|
|
94
|
+
`Unsupported Zod type: ${typeName || "(unknown)"}. Open an issue if this construct should be supported.`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function convertString(schema) {
|
|
99
|
+
const def = schema._def;
|
|
100
|
+
const checks = def.checks ?? [];
|
|
101
|
+
const out = { type: "string" };
|
|
102
|
+
for (const c of checks) {
|
|
103
|
+
if (c.kind === "email") out.format = "email";
|
|
104
|
+
else if (c.kind === "uuid") out.format = "uuid";
|
|
105
|
+
else if (c.kind === "url") out.format = "uri";
|
|
106
|
+
else if (c.kind === "datetime") out.format = "date-time";
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
function convertNumber(schema) {
|
|
111
|
+
const def = schema._def;
|
|
112
|
+
const checks = def.checks ?? [];
|
|
113
|
+
const isInt = checks.some((c) => c.kind === "int");
|
|
114
|
+
return { type: isInt ? "integer" : "number" };
|
|
115
|
+
}
|
|
116
|
+
function convertLiteral(schema) {
|
|
117
|
+
const value = schema._def.value;
|
|
118
|
+
const typed = literalTypeOf(value);
|
|
119
|
+
if (typed === null) {
|
|
120
|
+
return { type: "null", enum: [null] };
|
|
121
|
+
}
|
|
122
|
+
return { type: typed, enum: [value] };
|
|
123
|
+
}
|
|
124
|
+
function literalTypeOf(value) {
|
|
125
|
+
if (value === null) return null;
|
|
126
|
+
if (typeof value === "string") return "string";
|
|
127
|
+
if (typeof value === "number") return Number.isInteger(value) ? "integer" : "number";
|
|
128
|
+
if (typeof value === "boolean") return "boolean";
|
|
129
|
+
return "string";
|
|
130
|
+
}
|
|
131
|
+
function convertEnum(schema) {
|
|
132
|
+
const values = schema._def.values;
|
|
133
|
+
return { type: "string", enum: [...values] };
|
|
134
|
+
}
|
|
135
|
+
function convertArray(schema, ctx) {
|
|
136
|
+
const inner = schema._def.type;
|
|
137
|
+
return { type: "array", items: convert(inner, ctx) };
|
|
138
|
+
}
|
|
139
|
+
function convertObject(schema, ctx) {
|
|
140
|
+
const shape = schema.shape;
|
|
141
|
+
const properties = {};
|
|
142
|
+
const required = [];
|
|
143
|
+
for (const [key, child] of Object.entries(shape)) {
|
|
144
|
+
properties[key] = convert(child, ctx);
|
|
145
|
+
const childDef = child._def;
|
|
146
|
+
const isOptional = childDef.typeName === "ZodOptional" || childDef.typeName === "ZodDefault";
|
|
147
|
+
if (!isOptional) required.push(key);
|
|
148
|
+
}
|
|
149
|
+
const out = {
|
|
150
|
+
type: "object",
|
|
151
|
+
properties,
|
|
152
|
+
additionalProperties: false
|
|
153
|
+
};
|
|
154
|
+
if (required.length > 0) out.required = required;
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
function convertUnion(schema, ctx) {
|
|
158
|
+
const options = schema._def.options;
|
|
159
|
+
return { oneOf: options.map((o) => convert(o, ctx)) };
|
|
160
|
+
}
|
|
161
|
+
function convertDiscriminatedUnion(schema, ctx) {
|
|
162
|
+
const def = schema._def;
|
|
163
|
+
return {
|
|
164
|
+
oneOf: def.options.map((o) => convert(o, ctx)),
|
|
165
|
+
discriminator: { propertyName: def.discriminator }
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/vite-plugin/openapi-emit/emit.ts
|
|
170
|
+
var METHOD_TO_KEY = {
|
|
171
|
+
GET: "get",
|
|
172
|
+
POST: "post",
|
|
173
|
+
PUT: "put",
|
|
174
|
+
PATCH: "patch",
|
|
175
|
+
DELETE: "delete",
|
|
176
|
+
HEAD: "head",
|
|
177
|
+
OPTIONS: "options"
|
|
178
|
+
};
|
|
179
|
+
function templatePath(routePath) {
|
|
180
|
+
return routePath.replace(/:([A-Za-z_]\w{0,64})\??/g, "{$1}");
|
|
181
|
+
}
|
|
182
|
+
function buildParameters(paramsSchema, querySchema, ctx) {
|
|
183
|
+
const out = [];
|
|
184
|
+
if (paramsSchema !== void 0) {
|
|
185
|
+
appendObjectAsParameters(paramsSchema, "path", out, ctx);
|
|
186
|
+
}
|
|
187
|
+
if (querySchema !== void 0) {
|
|
188
|
+
appendObjectAsParameters(querySchema, "query", out, ctx);
|
|
189
|
+
}
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
function appendObjectAsParameters(schema, location, out, ctx) {
|
|
193
|
+
const shape = schema.shape;
|
|
194
|
+
if (shape === void 0) return;
|
|
195
|
+
for (const [name, child] of Object.entries(shape)) {
|
|
196
|
+
const childDef = child._def;
|
|
197
|
+
const optional = childDef.typeName === "ZodOptional" || childDef.typeName === "ZodDefault";
|
|
198
|
+
out.push({
|
|
199
|
+
name,
|
|
200
|
+
in: location,
|
|
201
|
+
required: location === "path" ? true : !optional,
|
|
202
|
+
schema: zodToOpenApiSchema(child, { ctx })
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function buildOperation(route, ctx, method) {
|
|
207
|
+
const sanitized = route.routePath.replace(/[/:\-{}]/g, "_").replace(/_+/g, "_");
|
|
208
|
+
const operationId = `${method.toLowerCase()}_${sanitized.replace(/^_|_$/g, "")}`;
|
|
209
|
+
const op = {
|
|
210
|
+
operationId,
|
|
211
|
+
responses: {
|
|
212
|
+
"200": { description: "OK" }
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const parameters = buildParameters(route.params, route.query, ctx);
|
|
216
|
+
if (parameters.length > 0) op.parameters = parameters;
|
|
217
|
+
if (route.body !== void 0) {
|
|
218
|
+
op.requestBody = {
|
|
219
|
+
required: true,
|
|
220
|
+
content: {
|
|
221
|
+
"application/json": { schema: zodToOpenApiSchema(route.body, { ctx }) }
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (route.response !== void 0) {
|
|
226
|
+
op.responses["200"] = {
|
|
227
|
+
description: "OK",
|
|
228
|
+
content: {
|
|
229
|
+
"application/json": { schema: zodToOpenApiSchema(route.response, { ctx }) }
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return op;
|
|
234
|
+
}
|
|
235
|
+
function emitOpenApi(input) {
|
|
236
|
+
const { manifest, config } = input;
|
|
237
|
+
const ctx = { seen: /* @__PURE__ */ new Map(), components: {} };
|
|
238
|
+
const paths = {};
|
|
239
|
+
for (const route of manifest) {
|
|
240
|
+
const templatedPath = templatePath(route.routePath);
|
|
241
|
+
const item = paths[templatedPath] ?? {};
|
|
242
|
+
for (const method of route.methods) {
|
|
243
|
+
const key = METHOD_TO_KEY[method.toUpperCase()];
|
|
244
|
+
if (key === void 0) continue;
|
|
245
|
+
item[key] = buildOperation(route, ctx, method);
|
|
246
|
+
}
|
|
247
|
+
paths[templatedPath] = item;
|
|
248
|
+
}
|
|
249
|
+
const servers = applyServerOverride(config.servers);
|
|
250
|
+
const document = {
|
|
251
|
+
openapi: config.specVersion,
|
|
252
|
+
info: { title: config.title, version: config.version },
|
|
253
|
+
servers,
|
|
254
|
+
paths
|
|
255
|
+
};
|
|
256
|
+
if (Object.keys(ctx.components).length > 0) {
|
|
257
|
+
document.components = { schemas: ctx.components };
|
|
258
|
+
}
|
|
259
|
+
mkdirSync(config.outDir, { recursive: true });
|
|
260
|
+
const outPath = join(config.outDir, "openapi.json");
|
|
261
|
+
writeFileSync(outPath, `${JSON.stringify(document, null, 2)}
|
|
262
|
+
`, "utf8");
|
|
263
|
+
return { document, path: outPath };
|
|
264
|
+
}
|
|
265
|
+
function applyServerOverride(servers) {
|
|
266
|
+
const override = process.env.THEOKIT_OPENAPI_SERVER_URL;
|
|
267
|
+
if (override === void 0 || override === "") return servers;
|
|
268
|
+
if (servers.length === 0) return [{ url: override }];
|
|
269
|
+
const [first, ...rest] = servers;
|
|
270
|
+
return [
|
|
271
|
+
{
|
|
272
|
+
url: override,
|
|
273
|
+
...first.description !== void 0 ? { description: first.description } : {}
|
|
274
|
+
},
|
|
275
|
+
...rest
|
|
276
|
+
];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/vite-plugin/openapi-emit/load-routes.ts
|
|
280
|
+
import { resolve } from "path";
|
|
281
|
+
var HTTP_METHOD_KEYS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
282
|
+
async function loadRoutesForOpenApi(options) {
|
|
283
|
+
const { serverDir, routes } = options;
|
|
284
|
+
let loadModule = options.loadModule;
|
|
285
|
+
let dispose;
|
|
286
|
+
if (loadModule === void 0) {
|
|
287
|
+
const created = await createDefaultLoader(serverDir);
|
|
288
|
+
loadModule = created.load;
|
|
289
|
+
dispose = created.dispose;
|
|
290
|
+
}
|
|
291
|
+
const out = [];
|
|
292
|
+
try {
|
|
293
|
+
for (const r of routes) {
|
|
294
|
+
const abs = resolve(serverDir, r.filePath);
|
|
295
|
+
let mod;
|
|
296
|
+
try {
|
|
297
|
+
mod = await loadModule(abs);
|
|
298
|
+
} catch (err) {
|
|
299
|
+
console.warn(
|
|
300
|
+
`[openapi-emit] Skipping ${r.filePath}: load failed (${err.message})`
|
|
301
|
+
);
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
const methods = r.methods ?? HTTP_METHOD_KEYS.filter((m) => mod[m] !== void 0);
|
|
305
|
+
if (methods.length === 0) {
|
|
306
|
+
const def = mod.default;
|
|
307
|
+
if (def !== void 0 && def !== null) {
|
|
308
|
+
out.push({ routePath: r.routePath, methods: ["GET"], ...extractSchemas(def) });
|
|
309
|
+
}
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
for (const method of methods) {
|
|
313
|
+
const handler = mod[method] ?? mod.default;
|
|
314
|
+
if (handler === void 0 || handler === null) continue;
|
|
315
|
+
out.push({ routePath: r.routePath, methods: [method], ...extractSchemas(handler) });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
} finally {
|
|
319
|
+
if (dispose !== void 0) {
|
|
320
|
+
await dispose();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return out;
|
|
324
|
+
}
|
|
325
|
+
function extractSchemas(handlerExport) {
|
|
326
|
+
if (typeof handlerExport !== "object" || handlerExport === null) return {};
|
|
327
|
+
const cfg = handlerExport;
|
|
328
|
+
const out = {};
|
|
329
|
+
if (cfg.body !== void 0) out.body = cfg.body;
|
|
330
|
+
if (cfg.query !== void 0) out.query = cfg.query;
|
|
331
|
+
if (cfg.params !== void 0) out.params = cfg.params;
|
|
332
|
+
if (cfg.response !== void 0) out.response = cfg.response;
|
|
333
|
+
return out;
|
|
334
|
+
}
|
|
335
|
+
async function createDefaultLoader(serverDir) {
|
|
336
|
+
const { createServer } = await import("vite");
|
|
337
|
+
const server = await createServer({
|
|
338
|
+
root: serverDir,
|
|
339
|
+
configFile: false,
|
|
340
|
+
server: { middlewareMode: true },
|
|
341
|
+
appType: "custom",
|
|
342
|
+
logLevel: "silent"
|
|
343
|
+
});
|
|
344
|
+
const swallow = () => {
|
|
345
|
+
};
|
|
346
|
+
return {
|
|
347
|
+
load: async (absPath) => server.ssrLoadModule(absPath),
|
|
348
|
+
dispose: async () => {
|
|
349
|
+
await server.close().catch(swallow);
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export {
|
|
355
|
+
emitOpenApi,
|
|
356
|
+
loadRoutesForOpenApi
|
|
357
|
+
};
|
|
358
|
+
//# sourceMappingURL=chunk-ZOXNJV2O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vite-plugin/openapi-emit/emit.ts","../src/vite-plugin/openapi-emit/zod-to-openapi.ts","../src/vite-plugin/openapi-emit/load-routes.ts"],"sourcesContent":["/**\n * In-house `emitOpenApi()` orchestrator (build-time only).\n *\n * Pure transformation: takes a route manifest (already hydrated with Zod\n * schemas extracted from `defineRoute()` config) + the openapi config\n * block, builds an OpenAPI 3.x document, writes `<outDir>/openapi.json`,\n * returns the document for downstream callers (CLI logs, tests).\n *\n * Per G2 plan v1.1 T2.1. Modelled on trpc-openapi's\n * `generateOpenApiDocument` + encore's `Generator.Generate()`.\n *\n * NEVER ship to runtime — devDep-shaped artifact.\n *\n * Path templating: TheoKit's `:param` syntax is converted to OpenAPI's\n * `{param}` per the spec. Env-var override: `THEOKIT_OPENAPI_SERVER_URL`\n * overrides `servers[0].url` without rebuilding the config.\n */\n/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time emit. outDir is a config-controlled relative path. The\n * caller already refused absolute paths via theoConfigSchema.distDir\n * pattern; the openapi.outDir field follows the same convention.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { z } from 'zod'\n\nimport { zodToOpenApiSchema, type ConvertCtx, type OpenApiSchema } from './zod-to-openapi.js'\n\nexport interface OpenApiManifestRoute {\n /** TheoKit-style path with `:param` placeholders (`/users/:id`). */\n routePath: string\n /** Uppercase HTTP methods the route exports (`['GET','POST']`). */\n methods: string[]\n /** Optional `defineRoute({body})` schema. */\n body?: z.ZodType\n /** Optional `defineRoute({query})` schema. */\n query?: z.ZodType\n /** Optional `defineRoute({params})` schema. */\n params?: z.ZodType\n /** Optional `defineRoute({response})` schema. */\n response?: z.ZodType\n}\n\nexport interface OpenApiEmitConfig {\n servers: { url: string; description?: string }[]\n specVersion: '3.1.0' | '3.0.3'\n title: string\n version: string\n outDir: string\n}\n\nexport interface OpenApiOperation {\n operationId?: string\n parameters?: OpenApiParameter[]\n requestBody?: {\n required?: boolean\n content: Record<string, { schema: OpenApiSchema }>\n }\n responses: Record<\n string,\n { description: string; content?: Record<string, { schema: OpenApiSchema }> }\n >\n}\n\nexport interface OpenApiParameter {\n name: string\n in: 'path' | 'query' | 'header' | 'cookie'\n required: boolean\n schema: OpenApiSchema\n description?: string\n}\n\nexport type OpenApiPathItem = Partial<\n Record<'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options', OpenApiOperation>\n>\n\nexport interface OpenApiDocument {\n openapi: '3.1.0' | '3.0.3'\n info: { title: string; version: string }\n servers: { url: string; description?: string }[]\n paths: Record<string, OpenApiPathItem>\n components?: { schemas?: Record<string, OpenApiSchema> }\n}\n\nexport interface EmitOpenApiInput {\n manifest: OpenApiManifestRoute[]\n config: OpenApiEmitConfig\n}\n\nexport interface EmitOpenApiResult {\n document: OpenApiDocument\n path: string\n}\n\nconst METHOD_TO_KEY: Record<string, keyof OpenApiPathItem> = {\n GET: 'get',\n POST: 'post',\n PUT: 'put',\n PATCH: 'patch',\n DELETE: 'delete',\n HEAD: 'head',\n OPTIONS: 'options',\n}\n\n/** Convert `/users/:id/posts/:postId?` → `/users/{id}/posts/{postId}`. */\nexport function templatePath(routePath: string): string {\n // Bounded quantifier (\\w{0,64}) is OSS-safe — TheoKit route param names\n // never exceed 64 chars in practice; cap prevents super-linear backtracking.\n return routePath.replace(/:([A-Za-z_]\\w{0,64})\\??/g, '{$1}')\n}\n\nfunction buildParameters(\n paramsSchema: z.ZodType | undefined,\n querySchema: z.ZodType | undefined,\n ctx: ConvertCtx,\n): OpenApiParameter[] {\n const out: OpenApiParameter[] = []\n if (paramsSchema !== undefined) {\n appendObjectAsParameters(paramsSchema, 'path', out, ctx)\n }\n if (querySchema !== undefined) {\n appendObjectAsParameters(querySchema, 'query', out, ctx)\n }\n return out\n}\n\nfunction appendObjectAsParameters(\n schema: z.ZodType,\n location: 'path' | 'query',\n out: OpenApiParameter[],\n ctx: ConvertCtx,\n): void {\n // We expect an object schema; if it's not, skip silently (caller already\n // validated upstream when scanning defineRoute()).\n const shape = (schema as unknown as { shape?: Record<string, z.ZodType> }).shape\n if (shape === undefined) return\n for (const [name, child] of Object.entries(shape)) {\n const childDef = (child as unknown as { _def: { typeName?: string } })._def\n const optional = childDef.typeName === 'ZodOptional' || childDef.typeName === 'ZodDefault'\n out.push({\n name,\n in: location,\n required: location === 'path' ? true : !optional,\n schema: zodToOpenApiSchema(child, { ctx }),\n })\n }\n}\n\nfunction buildOperation(\n route: OpenApiManifestRoute,\n ctx: ConvertCtx,\n method: string,\n): OpenApiOperation {\n // Bounded sanitizer: two single-pass replacements (no nested quantifiers).\n const sanitized = route.routePath.replace(/[/:\\-{}]/g, '_').replace(/_+/g, '_')\n const operationId = `${method.toLowerCase()}_${sanitized.replace(/^_|_$/g, '')}`\n const op: OpenApiOperation = {\n operationId,\n responses: {\n '200': { description: 'OK' },\n },\n }\n\n const parameters = buildParameters(route.params, route.query, ctx)\n if (parameters.length > 0) op.parameters = parameters\n\n // Body only meaningful for write methods; we still attach if defined so\n // the document is honest about the contract.\n if (route.body !== undefined) {\n op.requestBody = {\n required: true,\n content: {\n 'application/json': { schema: zodToOpenApiSchema(route.body, { ctx }) },\n },\n }\n }\n\n if (route.response !== undefined) {\n op.responses['200'] = {\n description: 'OK',\n content: {\n 'application/json': { schema: zodToOpenApiSchema(route.response, { ctx }) },\n },\n }\n }\n\n return op\n}\n\nexport function emitOpenApi(input: EmitOpenApiInput): EmitOpenApiResult {\n const { manifest, config } = input\n\n const ctx: ConvertCtx = { seen: new Map(), components: {} }\n\n const paths: Record<string, OpenApiPathItem> = {}\n for (const route of manifest) {\n const templatedPath = templatePath(route.routePath)\n const item: OpenApiPathItem = paths[templatedPath] ?? {}\n for (const method of route.methods) {\n // Defensive: manifest emitter normalizes to uppercase, but if a\n // future scanner produces a non-HTTP verb the key lookup yields\n // undefined and we skip silently. TS narrows the indexed type to\n // keyof OpenApiPathItem; the runtime undefined check is honest.\n const key = METHOD_TO_KEY[method.toUpperCase()] as keyof OpenApiPathItem | undefined\n if (key === undefined) continue\n item[key] = buildOperation(route, ctx, method)\n }\n paths[templatedPath] = item\n }\n\n const servers = applyServerOverride(config.servers)\n\n const document: OpenApiDocument = {\n openapi: config.specVersion,\n info: { title: config.title, version: config.version },\n servers,\n paths,\n }\n\n if (Object.keys(ctx.components).length > 0) {\n document.components = { schemas: ctx.components }\n }\n\n mkdirSync(config.outDir, { recursive: true })\n const outPath = join(config.outDir, 'openapi.json')\n writeFileSync(outPath, `${JSON.stringify(document, null, 2)}\\n`, 'utf8')\n\n return { document, path: outPath }\n}\n\nfunction applyServerOverride(\n servers: { url: string; description?: string }[],\n): { url: string; description?: string }[] {\n const override = process.env.THEOKIT_OPENAPI_SERVER_URL\n if (override === undefined || override === '') return servers\n if (servers.length === 0) return [{ url: override }]\n const [first, ...rest] = servers\n return [\n {\n url: override,\n ...(first.description !== undefined ? { description: first.description } : {}),\n },\n ...rest,\n ]\n}\n","/**\n * In-house Zod → OpenAPI 3.x Schema converter (build-time only).\n *\n * Per G2 plan v1.1 ADR D1 + EC-1: installed zod is 3.x (no native\n * `.toJSONSchema()`). This module is the PRIMARY conversion path.\n * Algorithm modelled on encore's `pkg/clientgen/openapi/schema.go`:\n * recursive descent + seen-map for cycle detection (named refs).\n *\n * Pure function: no I/O, no module loading. Caller extracts the Zod\n * schemas from `defineRoute({body, query, params})` and passes them\n * here. Returned `OpenApiSchema` is a structural subset of the OpenAPI\n * 3.0/3.1 Schema Object — fields populated as needed.\n *\n * NEVER ship to runtime — devDep-shaped artifact.\n *\n * Unsupported Zod constructs (z.function(), z.promise()) throw a\n * `ZodToOpenApiError` with a descriptive message so the caller can\n * surface the offending route + advise the user.\n */\nimport type { z } from 'zod'\n\nexport interface OpenApiSchema {\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object' | 'null'\n format?: string\n items?: OpenApiSchema\n properties?: Record<string, OpenApiSchema>\n required?: string[]\n additionalProperties?: boolean | OpenApiSchema\n oneOf?: OpenApiSchema[]\n anyOf?: OpenApiSchema[]\n allOf?: OpenApiSchema[]\n discriminator?: { propertyName: string; mapping?: Record<string, string> }\n enum?: unknown[]\n nullable?: boolean\n description?: string\n $ref?: string\n // OpenAPI 3.1 (JSON Schema 2020-12) allows `type: [..., 'null']`; for now\n // we stick with 3.0-compatible `nullable: true`. Caller can transform at\n // emit time if specVersion === '3.1.0'.\n}\n\nexport interface ConvertCtx {\n /** Seen-map: zod schema reference → component name (for $ref cycle detection). */\n seen: Map<z.ZodType, string>\n /** Output bucket for named component schemas. */\n components: Record<string, OpenApiSchema>\n}\n\nexport interface ConvertOptions {\n /**\n * Optional context carried across recursive calls. Pass the SAME ctx to\n * every `zodToOpenApiSchema` invocation in one emit pass so cycle\n * detection works across multiple routes.\n */\n ctx?: ConvertCtx\n /**\n * If provided, the schema is registered under `components.schemas[name]`\n * and the returned value is `{ $ref: '#/components/schemas/<name>' }`.\n * Use this for top-level recursive types where the consumer (e.g.,\n * OpenAPI document builder) wants named schemas instead of inlined ones.\n */\n name?: string\n}\n\nexport class ZodToOpenApiError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ZodToOpenApiError'\n }\n}\n\nexport function zodToOpenApiSchema(schema: z.ZodType, options: ConvertOptions = {}): OpenApiSchema {\n const ctx: ConvertCtx = options.ctx ?? { seen: new Map(), components: {} }\n\n const name = options.name\n if (name !== undefined) {\n // Top-level named schema — register placeholder BEFORE recursing, then\n // patch the slot with the computed body. This avoids infinite recursion\n // for self-referential types (encore schema.go:289 pattern).\n if (Object.prototype.hasOwnProperty.call(ctx.components, name)) {\n return { $ref: `#/components/schemas/${name}` }\n }\n ctx.seen.set(schema, name)\n ctx.components[name] = {} // placeholder\n const body = convert(schema, ctx)\n ctx.components[name] = body\n return { $ref: `#/components/schemas/${name}` }\n }\n\n return convert(schema, ctx)\n}\n\n// eslint-disable-next-line complexity -- switch-based dispatch on Zod typeName; splitting hides intent\nfunction convert(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n // Cycle: if we've seen this exact schema reference before, emit $ref.\n const existing = ctx.seen.get(schema)\n if (existing !== undefined) {\n return { $ref: `#/components/schemas/${existing}` }\n }\n\n const def = (schema as unknown as { _def: { typeName?: string } })._def\n const typeName = def.typeName ?? ''\n\n switch (typeName) {\n case 'ZodString':\n return convertString(schema)\n case 'ZodNumber':\n return convertNumber(schema)\n case 'ZodBoolean':\n return { type: 'boolean' }\n case 'ZodLiteral':\n return convertLiteral(schema)\n case 'ZodEnum':\n return convertEnum(schema)\n case 'ZodArray':\n return convertArray(schema, ctx)\n case 'ZodObject':\n return convertObject(schema, ctx)\n case 'ZodUnion':\n return convertUnion(schema, ctx)\n case 'ZodDiscriminatedUnion':\n return convertDiscriminatedUnion(schema, ctx)\n case 'ZodOptional':\n // Optional-as-property is handled at object level; here we unwrap.\n return convert((schema as unknown as { _def: { innerType: z.ZodType } })._def.innerType, ctx)\n case 'ZodNullable': {\n const inner = convert(\n (schema as unknown as { _def: { innerType: z.ZodType } })._def.innerType,\n ctx,\n )\n return { ...inner, nullable: true }\n }\n case 'ZodEffects':\n case 'ZodTransform':\n // Transforms change runtime output, but the WIRE shape is the input.\n return convert((schema as unknown as { _def: { schema: z.ZodType } })._def.schema, ctx)\n case 'ZodDefault':\n return convert((schema as unknown as { _def: { innerType: z.ZodType } })._def.innerType, ctx)\n case 'ZodLazy': {\n const getter = (schema as unknown as { _def: { getter: () => z.ZodType } })._def.getter\n return convert(getter(), ctx)\n }\n case 'ZodRecord': {\n const valueType = (schema as unknown as { _def: { valueType: z.ZodType } })._def.valueType\n return { type: 'object', additionalProperties: convert(valueType, ctx) }\n }\n case 'ZodAny':\n case 'ZodUnknown':\n return {} // no constraint\n case 'ZodNull':\n return { type: 'null' }\n case 'ZodFunction':\n throw new ZodToOpenApiError(\n 'Unsupported Zod type: z.function() cannot be represented in OpenAPI Schema. Remove from the route schema.',\n )\n case 'ZodPromise':\n throw new ZodToOpenApiError(\n 'Unsupported Zod type: z.promise() cannot be represented in OpenAPI Schema. Unwrap the value before passing to defineRoute.',\n )\n default:\n throw new ZodToOpenApiError(\n `Unsupported Zod type: ${typeName || '(unknown)'}. Open an issue if this construct should be supported.`,\n )\n }\n}\n\ninterface StringCheck {\n kind: string\n}\n\nfunction convertString(schema: z.ZodType): OpenApiSchema {\n const def = (schema as unknown as { _def: { checks?: StringCheck[] } })._def\n const checks = def.checks ?? []\n const out: OpenApiSchema = { type: 'string' }\n for (const c of checks) {\n if (c.kind === 'email') out.format = 'email'\n else if (c.kind === 'uuid') out.format = 'uuid'\n else if (c.kind === 'url') out.format = 'uri'\n else if (c.kind === 'datetime') out.format = 'date-time'\n }\n return out\n}\n\ninterface NumberCheck {\n kind: string\n}\n\nfunction convertNumber(schema: z.ZodType): OpenApiSchema {\n const def = (schema as unknown as { _def: { checks?: NumberCheck[] } })._def\n const checks = def.checks ?? []\n const isInt = checks.some((c) => c.kind === 'int')\n return { type: isInt ? 'integer' : 'number' }\n}\n\nfunction convertLiteral(schema: z.ZodType): OpenApiSchema {\n const value = (schema as unknown as { _def: { value: unknown } })._def.value\n const typed = literalTypeOf(value)\n if (typed === null) {\n // Null literal\n return { type: 'null', enum: [null] }\n }\n return { type: typed, enum: [value] }\n}\n\nfunction literalTypeOf(value: unknown): OpenApiSchema['type'] | null {\n if (value === null) return null\n if (typeof value === 'string') return 'string'\n if (typeof value === 'number') return Number.isInteger(value) ? 'integer' : 'number'\n if (typeof value === 'boolean') return 'boolean'\n return 'string' // fallback for symbol/etc.\n}\n\nfunction convertEnum(schema: z.ZodType): OpenApiSchema {\n const values = (schema as unknown as { _def: { values: readonly string[] } })._def.values\n return { type: 'string', enum: [...values] }\n}\n\nfunction convertArray(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const inner = (schema as unknown as { _def: { type: z.ZodType } })._def.type\n return { type: 'array', items: convert(inner, ctx) }\n}\n\nfunction convertObject(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const shape = (schema as unknown as { shape: Record<string, z.ZodType> }).shape\n const properties: Record<string, OpenApiSchema> = {}\n const required: string[] = []\n for (const [key, child] of Object.entries(shape)) {\n properties[key] = convert(child, ctx)\n const childDef = (child as unknown as { _def: { typeName?: string } })._def\n const isOptional = childDef.typeName === 'ZodOptional' || childDef.typeName === 'ZodDefault'\n if (!isOptional) required.push(key)\n }\n const out: OpenApiSchema = {\n type: 'object',\n properties,\n additionalProperties: false,\n }\n if (required.length > 0) out.required = required\n return out\n}\n\nfunction convertUnion(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const options = (schema as unknown as { _def: { options: z.ZodType[] } })._def.options\n return { oneOf: options.map((o) => convert(o, ctx)) }\n}\n\nfunction convertDiscriminatedUnion(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const def = (\n schema as unknown as {\n _def: { discriminator: string; options: z.ZodType[] }\n }\n )._def\n return {\n oneOf: def.options.map((o) => convert(o, ctx)),\n discriminator: { propertyName: def.discriminator },\n }\n}\n","/**\n * Build-time route loader for OpenAPI emit.\n *\n * Takes the G1 manifest (filePath + routePath + methods) and hydrates each\n * route's Zod schemas by dynamically importing the module. `defineRoute`\n * is an identity function, so the imported config exposes `body/query/\n * params/response` directly without any AST gymnastics.\n *\n * Supports both export shapes:\n * 1. `export const POST = defineRoute({...})` (per-method named exports)\n * 2. `export default defineRoute({...})` (single-export legacy shape)\n *\n * Per G2 plan v1.1 T2.2. Uses Vite's `ssrLoadModule` because route files\n * are TS at build time — Node's native loader doesn't transpile.\n */\nimport { resolve } from 'node:path'\n\nimport type { z } from 'zod'\n\nimport type { ManifestRoute } from '../../server/scan/manifest.js'\n\nimport type { OpenApiManifestRoute } from './emit.js'\n\ninterface RouteConfigShape {\n body?: z.ZodType\n query?: z.ZodType\n params?: z.ZodType\n response?: z.ZodType\n}\n\ninterface ViteLikeServer {\n ssrLoadModule: (id: string) => Promise<Record<string, unknown>>\n close: () => Promise<void>\n}\n\ninterface DefaultLoader {\n load: (absPath: string) => Promise<Record<string, unknown>>\n dispose: () => Promise<void>\n}\n\n/** Method names recognized as per-route named exports (UPPERCASE). */\nconst HTTP_METHOD_KEYS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const\n\nexport interface LoadRoutesOptions {\n serverDir: string\n routes: ManifestRoute[]\n /** Injectable for tests; defaults to a fresh Vite SSR dev server. */\n loadModule?: (absPath: string) => Promise<Record<string, unknown>>\n}\n\n/**\n * Hydrate manifest routes with Zod schemas extracted from their modules.\n *\n * Returns one `OpenApiManifestRoute` per (file × method) tuple. If a route\n * file declares multiple methods (`GET` + `POST`), each method gets its\n * own entry with the schemas from that method's `defineRoute()` call.\n *\n * Routes that fail to load are skipped with a console warning — the emit\n * should be best-effort, not a hard build failure.\n *\n * The default Vite loader is created once per call and disposed in the\n * `finally` block so the underlying server is released even when route\n * loading throws.\n */\nexport async function loadRoutesForOpenApi(\n options: LoadRoutesOptions,\n): Promise<OpenApiManifestRoute[]> {\n const { serverDir, routes } = options\n let loadModule = options.loadModule\n let dispose: (() => Promise<void>) | undefined\n if (loadModule === undefined) {\n const created = await createDefaultLoader(serverDir)\n loadModule = created.load\n dispose = created.dispose\n }\n\n const out: OpenApiManifestRoute[] = []\n try {\n for (const r of routes) {\n const abs = resolve(serverDir, r.filePath)\n let mod: Record<string, unknown>\n try {\n mod = await loadModule(abs)\n } catch (err) {\n console.warn(\n `[openapi-emit] Skipping ${r.filePath}: load failed (${(err as Error).message})`,\n )\n continue\n }\n\n const methods = r.methods ?? HTTP_METHOD_KEYS.filter((m) => mod[m] !== undefined)\n if (methods.length === 0) {\n // Fall back to default export when no method-named exports detected.\n const def = mod.default\n if (def !== undefined && def !== null) {\n out.push({ routePath: r.routePath, methods: ['GET'], ...extractSchemas(def) })\n }\n continue\n }\n\n for (const method of methods) {\n const handler = mod[method] ?? mod.default\n if (handler === undefined || handler === null) continue\n out.push({ routePath: r.routePath, methods: [method], ...extractSchemas(handler) })\n }\n }\n } finally {\n if (dispose !== undefined) {\n await dispose()\n }\n }\n return out\n}\n\nfunction extractSchemas(handlerExport: unknown): RouteConfigShape {\n if (typeof handlerExport !== 'object' || handlerExport === null) return {}\n const cfg = handlerExport as RouteConfigShape\n const out: RouteConfigShape = {}\n if (cfg.body !== undefined) out.body = cfg.body\n if (cfg.query !== undefined) out.query = cfg.query\n if (cfg.params !== undefined) out.params = cfg.params\n if (cfg.response !== undefined) out.response = cfg.response\n return out\n}\n\n/**\n * Default loader: spin up a minimal Vite SSR dev server (no HMR, no\n * middlewares) just to use its `ssrLoadModule`. Vite handles TS, ESM, and\n * import resolution for free.\n *\n * Returns `{load, dispose}` — the caller owns the lifecycle and MUST\n * call `dispose()` (typically in a `finally`) so the server is closed.\n */\nasync function createDefaultLoader(serverDir: string): Promise<DefaultLoader> {\n // Vite is a peerDep in build flows; import dynamically.\n const { createServer } = await import('vite')\n const server = (await createServer({\n root: serverDir,\n configFile: false,\n server: { middlewareMode: true },\n appType: 'custom',\n logLevel: 'silent',\n })) as unknown as ViteLikeServer\n\n const swallow = (): void => {\n /* eat close errors — best-effort cleanup */\n }\n return {\n load: async (absPath) => server.ssrLoadModule(absPath),\n dispose: async () => {\n await server.close().catch(swallow)\n },\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli/index.js
CHANGED
|
@@ -6,12 +6,12 @@ import "../chunk-KT3MWNZG.js";
|
|
|
6
6
|
import cac from "cac";
|
|
7
7
|
var cli = cac("theokit");
|
|
8
8
|
cli.command("dev", "Start development server").option("--port <port>", "Port number").action(async (options) => {
|
|
9
|
-
const { devCommand } = await import("../dev-
|
|
9
|
+
const { devCommand } = await import("../dev-74KPI5C5.js");
|
|
10
10
|
await devCommand({ port: options.port ? Number(options.port) : void 0 });
|
|
11
11
|
});
|
|
12
12
|
cli.command("build", "Build for production").option("--target <target>", "Deploy target (node, vercel, cloudflare)").action(async (options) => {
|
|
13
13
|
try {
|
|
14
|
-
const { buildCommand } = await import("../build-
|
|
14
|
+
const { buildCommand } = await import("../build-EWZDEDT3.js");
|
|
15
15
|
await buildCommand({ target: options.target });
|
|
16
16
|
} catch (err) {
|
|
17
17
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -23,7 +23,7 @@ cli.command("build", "Build for production").option("--target <target>", "Deploy
|
|
|
23
23
|
});
|
|
24
24
|
cli.command("start", "Start production server").option("--port <port>", "Port number").action(async (options) => {
|
|
25
25
|
try {
|
|
26
|
-
const { startCommand } = await import("../start-
|
|
26
|
+
const { startCommand } = await import("../start-5JTFWF4T.js");
|
|
27
27
|
await startCommand({ port: options.port ? Number(options.port) : void 0 });
|
|
28
28
|
} catch (err) {
|
|
29
29
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -35,7 +35,7 @@ cli.command("start", "Start production server").option("--port <port>", "Port nu
|
|
|
35
35
|
});
|
|
36
36
|
cli.command("generate <type> <name>", "Generate a route, action, page, or ws endpoint").action(async (type, name) => {
|
|
37
37
|
try {
|
|
38
|
-
const { generateCommand } = await import("../generate-
|
|
38
|
+
const { generateCommand } = await import("../generate-DT4IIAHF.js");
|
|
39
39
|
await generateCommand(type, name);
|
|
40
40
|
} catch (err) {
|
|
41
41
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -47,7 +47,7 @@ cli.command("generate <type> <name>", "Generate a route, action, page, or ws end
|
|
|
47
47
|
});
|
|
48
48
|
cli.command("routes", "List all routes, actions, and WebSocket endpoints").action(async () => {
|
|
49
49
|
try {
|
|
50
|
-
const { routesCommand } = await import("../routes-
|
|
50
|
+
const { routesCommand } = await import("../routes-7O4NUDYS.js");
|
|
51
51
|
await routesCommand();
|
|
52
52
|
} catch (err) {
|
|
53
53
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -73,7 +73,7 @@ cli.command("check", "Run typecheck + scan + (optional) eslint").option(
|
|
|
73
73
|
`);
|
|
74
74
|
process.exit(1);
|
|
75
75
|
}
|
|
76
|
-
const { upgradeReadinessCommand } = await import("../upgrade-readiness-
|
|
76
|
+
const { upgradeReadinessCommand } = await import("../upgrade-readiness-Q46KTG2J.js");
|
|
77
77
|
await upgradeReadinessCommand({
|
|
78
78
|
json: Boolean(options.json),
|
|
79
79
|
allowWarnings: Boolean(options.allowWarnings)
|
|
@@ -88,9 +88,24 @@ cli.command("add <package>", "Install a known TheoKit adapter or plugin (whiteli
|
|
|
88
88
|
await addCommand(pkg);
|
|
89
89
|
});
|
|
90
90
|
cli.command("info", "Print environment info (runtime, config, routes)").action(async () => {
|
|
91
|
-
const { infoCommand } = await import("../info-
|
|
91
|
+
const { infoCommand } = await import("../info-VM7EK4JC.js");
|
|
92
92
|
await infoCommand();
|
|
93
93
|
});
|
|
94
|
+
cli.command(
|
|
95
|
+
"openapi",
|
|
96
|
+
"Generate <distDir>/openapi.json from route schemas (opt-in via config.openapi)"
|
|
97
|
+
).option("--dry-run", "Print the document to stdout without writing to disk (EC-3)").action(async (options) => {
|
|
98
|
+
try {
|
|
99
|
+
const { openapiCommand } = await import("../openapi-CBASKC7W.js");
|
|
100
|
+
await openapiCommand({ dryRun: Boolean(options.dryRun) });
|
|
101
|
+
} catch (err) {
|
|
102
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
103
|
+
console.error(`
|
|
104
|
+
\u2717 ${msg}
|
|
105
|
+
`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
94
109
|
cli.command("docker", "Generate Dockerfile for production").option("--force", "Overwrite existing Dockerfile").action(async (options) => {
|
|
95
110
|
try {
|
|
96
111
|
const { dockerCommand } = await import("../docker-EZDA5FT7.js");
|