theokit 0.5.1 → 0.5.2

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.
Files changed (135) hide show
  1. package/dist/{actions-virtual-module-IY46EEEX.js → actions-virtual-module-DL74V6SR.js} +2 -2
  2. package/dist/actions-virtual-module-DL74V6SR.js.map +1 -0
  3. package/dist/{actions-virtual-module-XNHDNCZ6.js → actions-virtual-module-ZDD54ZZE.js} +2 -2
  4. package/dist/actions-virtual-module-ZDD54ZZE.js.map +1 -0
  5. package/dist/{app-typed-client-OUJO3V5J.js → app-typed-client-4GIKUKRT.js} +4 -4
  6. package/dist/app-typed-client-4GIKUKRT.js.map +1 -0
  7. package/dist/{app-typed-client-YOMWSA3F.js → app-typed-client-4M4NVSK3.js} +3 -3
  8. package/dist/app-typed-client-4M4NVSK3.js.map +1 -0
  9. package/dist/{aws-lambda-GKSTX6HD.js → aws-lambda-SCRGTGF5.js} +5 -5
  10. package/dist/aws-lambda-SCRGTGF5.js.map +1 -0
  11. package/dist/{build-2WZ6XXVY.js → build-R74EU6BP.js} +11 -11
  12. package/dist/build-R74EU6BP.js.map +1 -0
  13. package/dist/{bun-ISHSNFIO.js → bun-FURRCQMS.js} +7 -7
  14. package/dist/bun-FURRCQMS.js.map +1 -0
  15. package/dist/{chunk-FI7MPTJW.js → chunk-3IOFTG3L.js} +1 -1
  16. package/dist/chunk-3IOFTG3L.js.map +1 -0
  17. package/dist/{chunk-U6TPSW4L.js → chunk-DUKXQNM7.js} +2 -2
  18. package/dist/{chunk-4S2UCILN.js → chunk-FGOX37NB.js} +8 -8
  19. package/dist/chunk-FGOX37NB.js.map +1 -0
  20. package/dist/{chunk-MR7OLIC6.js → chunk-GPF64ENM.js} +2 -2
  21. package/dist/{chunk-4S6YHNG2.js → chunk-GUUWDMR2.js} +2 -2
  22. package/dist/chunk-GUUWDMR2.js.map +1 -0
  23. package/dist/{chunk-WEGALZEU.js → chunk-HDA6M7P4.js} +3 -3
  24. package/dist/{chunk-K4M64WD6.js → chunk-IZQN5CDS.js} +4 -4
  25. package/dist/chunk-IZQN5CDS.js.map +1 -0
  26. package/dist/{chunk-M2EY7KDR.js → chunk-JD7AQNJS.js} +15 -15
  27. package/dist/chunk-JD7AQNJS.js.map +1 -0
  28. package/dist/{chunk-5Z2727GV.js → chunk-KJLECZWQ.js} +1 -1
  29. package/dist/chunk-KJLECZWQ.js.map +1 -0
  30. package/dist/{chunk-LC5PYNJP.js → chunk-MWYSRZI4.js} +7 -7
  31. package/dist/chunk-MWYSRZI4.js.map +1 -0
  32. package/dist/{chunk-VBZCVFSA.js → chunk-P2RS3WWY.js} +2 -2
  33. package/dist/{chunk-R7OC6UDK.js → chunk-P3SGM4NR.js} +1 -1
  34. package/dist/chunk-P3SGM4NR.js.map +1 -0
  35. package/dist/{chunk-ABVITXFH.js → chunk-S74FECKW.js} +1 -1
  36. package/dist/{chunk-ABVITXFH.js.map → chunk-S74FECKW.js.map} +1 -1
  37. package/dist/{chunk-COXLEZCN.js → chunk-UVHRD33F.js} +1 -1
  38. package/dist/chunk-UVHRD33F.js.map +1 -0
  39. package/dist/{chunk-27LWMYNK.js → chunk-X32KQH5C.js} +2 -2
  40. package/dist/chunk-X32KQH5C.js.map +1 -0
  41. package/dist/{chunk-2F4FROEQ.js → chunk-X3VNROZ7.js} +17 -17
  42. package/dist/chunk-X3VNROZ7.js.map +1 -0
  43. package/dist/{chunk-Y4H3JNVK.js → chunk-YB5DJJ4U.js} +1 -1
  44. package/dist/chunk-YB5DJJ4U.js.map +1 -0
  45. package/dist/cli/index.js +8 -8
  46. package/dist/{cloudflare-OJGJ7R2D.js → cloudflare-IZ6VJ2OU.js} +7 -7
  47. package/dist/cloudflare-IZ6VJ2OU.js.map +1 -0
  48. package/dist/{deno-deploy-BHWKFTOW.js → deno-deploy-O73NBXIW.js} +6 -6
  49. package/dist/deno-deploy-O73NBXIW.js.map +1 -0
  50. package/dist/{dev-U4UDZFDB.js → dev-ZU46C5AZ.js} +8 -8
  51. package/dist/{dev-emit-HHP2XJXE.js → dev-emit-66FCOS7V.js} +4 -4
  52. package/dist/{dev-emit-5VPRCHOD.js → dev-emit-JBVINGHU.js} +3 -3
  53. package/dist/devtools/entry.js +3 -4
  54. package/dist/devtools/entry.js.map +1 -1
  55. package/dist/{docker-EZDA5FT7.js → docker-AZSJFLP2.js} +3 -3
  56. package/dist/docker-AZSJFLP2.js.map +1 -0
  57. package/dist/{index-DWWEdFh5.d.ts → index-CuHICqb9.d.ts} +2 -2
  58. package/dist/index.d.ts +1 -1
  59. package/dist/index.js +3 -3
  60. package/dist/{info-47VB62MV.js → info-CORLCPEJ.js} +4 -4
  61. package/dist/{netlify-GSNSJGMN.js → netlify-O7G3RLK4.js} +3 -3
  62. package/dist/netlify-O7G3RLK4.js.map +1 -0
  63. package/dist/{node-6I5B6RL3.js → node-LXPQLMVB.js} +3 -3
  64. package/dist/{openapi-NFLSNNVQ.js → openapi-TEOUOIJ2.js} +7 -7
  65. package/dist/registry-KW4F4D2L.js +25 -0
  66. package/dist/{routes-3A4XGIEJ.js → routes-GAXVWJUK.js} +6 -6
  67. package/dist/{schema-KZVOV333.js → schema-Z5VJ2I76.js} +3 -3
  68. package/dist/server/cron/index.js +2 -2
  69. package/dist/server/http/index.d.ts +1 -1
  70. package/dist/server/http/index.js +2 -2
  71. package/dist/server/index.d.ts +3 -3
  72. package/dist/server/index.js +18 -11
  73. package/dist/server/index.js.map +1 -1
  74. package/dist/server/jobs/index.d.ts +1 -1
  75. package/dist/server/jobs/index.js +2 -2
  76. package/dist/server/scan/index.d.ts +1 -1
  77. package/dist/server/scan/index.js +2 -2
  78. package/dist/{services-json-Z2QNGVPW.js → services-json-6SHWMYJH.js} +1 -1
  79. package/dist/services-json-6SHWMYJH.js.map +1 -0
  80. package/dist/{services-typed-client-T7M5VPBP.js → services-typed-client-ASZL7FQV.js} +2 -2
  81. package/dist/{start-QDRSRNXK.js → start-HGUNNF5X.js} +10 -10
  82. package/dist/start-HGUNNF5X.js.map +1 -0
  83. package/dist/{static-QI5NQT2X.js → static-EO73I4C7.js} +6 -6
  84. package/dist/static-EO73I4C7.js.map +1 -0
  85. package/dist/{theo-cloud-RSQCBNXL.js → theo-cloud-HBCYEODQ.js} +2 -2
  86. package/dist/theo-cloud-HBCYEODQ.js.map +1 -0
  87. package/dist/{vercel-TKPZK62A.js → vercel-GSFDMF7K.js} +4 -4
  88. package/dist/vercel-GSFDMF7K.js.map +1 -0
  89. package/dist/vite-plugin/index.js +3 -3
  90. package/dist/{vite-plugin-CR4JDFUQ.js → vite-plugin-TX5H4MB6.js} +8 -8
  91. package/package.json +1 -1
  92. package/dist/actions-virtual-module-IY46EEEX.js.map +0 -1
  93. package/dist/actions-virtual-module-XNHDNCZ6.js.map +0 -1
  94. package/dist/app-typed-client-OUJO3V5J.js.map +0 -1
  95. package/dist/app-typed-client-YOMWSA3F.js.map +0 -1
  96. package/dist/aws-lambda-GKSTX6HD.js.map +0 -1
  97. package/dist/build-2WZ6XXVY.js.map +0 -1
  98. package/dist/bun-ISHSNFIO.js.map +0 -1
  99. package/dist/chunk-27LWMYNK.js.map +0 -1
  100. package/dist/chunk-2F4FROEQ.js.map +0 -1
  101. package/dist/chunk-4S2UCILN.js.map +0 -1
  102. package/dist/chunk-4S6YHNG2.js.map +0 -1
  103. package/dist/chunk-5Z2727GV.js.map +0 -1
  104. package/dist/chunk-COXLEZCN.js.map +0 -1
  105. package/dist/chunk-FI7MPTJW.js.map +0 -1
  106. package/dist/chunk-K4M64WD6.js.map +0 -1
  107. package/dist/chunk-LC5PYNJP.js.map +0 -1
  108. package/dist/chunk-M2EY7KDR.js.map +0 -1
  109. package/dist/chunk-R7OC6UDK.js.map +0 -1
  110. package/dist/chunk-Y4H3JNVK.js.map +0 -1
  111. package/dist/cloudflare-OJGJ7R2D.js.map +0 -1
  112. package/dist/deno-deploy-BHWKFTOW.js.map +0 -1
  113. package/dist/docker-EZDA5FT7.js.map +0 -1
  114. package/dist/netlify-GSNSJGMN.js.map +0 -1
  115. package/dist/registry-QHEZ3BWB.js +0 -25
  116. package/dist/services-json-Z2QNGVPW.js.map +0 -1
  117. package/dist/start-QDRSRNXK.js.map +0 -1
  118. package/dist/static-QI5NQT2X.js.map +0 -1
  119. package/dist/theo-cloud-RSQCBNXL.js.map +0 -1
  120. package/dist/vercel-TKPZK62A.js.map +0 -1
  121. /package/dist/{chunk-U6TPSW4L.js.map → chunk-DUKXQNM7.js.map} +0 -0
  122. /package/dist/{chunk-MR7OLIC6.js.map → chunk-GPF64ENM.js.map} +0 -0
  123. /package/dist/{chunk-WEGALZEU.js.map → chunk-HDA6M7P4.js.map} +0 -0
  124. /package/dist/{chunk-VBZCVFSA.js.map → chunk-P2RS3WWY.js.map} +0 -0
  125. /package/dist/{dev-U4UDZFDB.js.map → dev-ZU46C5AZ.js.map} +0 -0
  126. /package/dist/{dev-emit-HHP2XJXE.js.map → dev-emit-66FCOS7V.js.map} +0 -0
  127. /package/dist/{dev-emit-5VPRCHOD.js.map → dev-emit-JBVINGHU.js.map} +0 -0
  128. /package/dist/{info-47VB62MV.js.map → info-CORLCPEJ.js.map} +0 -0
  129. /package/dist/{node-6I5B6RL3.js.map → node-LXPQLMVB.js.map} +0 -0
  130. /package/dist/{openapi-NFLSNNVQ.js.map → openapi-TEOUOIJ2.js.map} +0 -0
  131. /package/dist/{registry-QHEZ3BWB.js.map → registry-KW4F4D2L.js.map} +0 -0
  132. /package/dist/{routes-3A4XGIEJ.js.map → routes-GAXVWJUK.js.map} +0 -0
  133. /package/dist/{schema-KZVOV333.js.map → schema-Z5VJ2I76.js.map} +0 -0
  134. /package/dist/{services-typed-client-T7M5VPBP.js.map → services-typed-client-ASZL7FQV.js.map} +0 -0
  135. /package/dist/{vite-plugin-CR4JDFUQ.js.map → vite-plugin-TX5H4MB6.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/cloudflare.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Cloudflare deploy adapter. All write paths are under `cwd/.theo/cloudflare/`\n * and `cwd/wrangler.toml`. Build-time tool — no HTTP input.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport type { TheoConfig } from '../config/schema.js'\nimport { assertServicesUnsupported, readManifest } from '../services/index.js'\n\nimport { nodeAdapter } from './node.js'\nimport type { AdapterBuildContext, DeployAdapter } from './types.js'\n\n/**\n * T2.1 — Cloudflare adapter rewritten to consume `theokit/adapters/web-shim`\n * instead of emitting an inline plain-object Request/Response shim. Reduces\n * template from ~50 lines to ~25 and centralizes maintenance.\n */\n\nexport function renderCloudflareWorkerEntry(opts: { ssrStreaming?: boolean } = {}): string {\n const streamingImport = opts.ssrStreaming\n ? `import { renderStreamingWeb } from '/@theo/entry-server'`\n : `// (ssrStreaming off: renderStreamingWeb not imported)`\n const nonApiBranch = opts.ssrStreaming\n ? ` // T2.3 — streaming SSR for non-API routes\\n return renderStreamingWeb(request)`\n : ` return notFoundResponse()`\n // CR-006: Workers lack `process.cwd()` and the `node:*` import surface\n // is brittle even under `nodejs_compat`. We use the Web Crypto\n // `crypto.randomUUID()` instead of `node:crypto.randomUUID`, and embed\n // the server directory as a build-time literal instead of resolving via\n // `node:path` at runtime.\n return [\n `// Generated by Theo — Cloudflare Workers Adapter`,\n `//`,\n `// REQUIREMENTS (EC-3):`,\n `// - wrangler.toml MUST include compatibility_flags = [\"nodejs_compat\"]`,\n `// (still required for transitive theokit/server deps, e.g. busboy)`,\n `// - package.json MUST list \"theokit\" in dependencies (not devDependencies)`,\n `// so Wrangler bundles theokit and its transitive deps`,\n `// - Deploy: wrangler deploy`,\n ``,\n `import { scanServerRoutes, matchRoute, executeRoute, createProductionLoader, scanWebSocketRoutes } from 'theokit/server'`,\n `import { createWebShim } from 'theokit/adapters/web-shim'`,\n `// T3.4 — WS bridge for Cloudflare Workers`,\n `import { createCloudflareWsBridge } from 'theokit/adapters/ws-shim'`,\n streamingImport,\n ``,\n `// Cold-start cache (avoid scanning routes on every request)`,\n `let routesCache = null`,\n `let wsRoutesCache = null`,\n `let loaderCache = null`,\n `// CR-006: server directory is a build-time literal — Workers cannot`,\n `// call process.cwd() and resolving paths at runtime returned '/server'.`,\n `const serverDir = 'server'`,\n ``,\n `function notFoundResponse() {`,\n ` return new Response(`,\n ` JSON.stringify({ error: { code: 'NOT_FOUND', message: 'Route not found' } }),`,\n ` { status: 404, headers: { 'Content-Type': 'application/json' } },`,\n ` )`,\n `}`,\n ``,\n `export default {`,\n ` async fetch(request, env, ctx) {`,\n ` const url = new URL(request.url)`,\n ``,\n ` // T3.4 — Detect WebSocket upgrade and delegate to the CF bridge`,\n ` if (request.headers.get('upgrade')?.toLowerCase() === 'websocket') {`,\n ` if (!wsRoutesCache) wsRoutesCache = scanWebSocketRoutes(serverDir)`,\n ` if (wsRoutesCache.length === 0) return notFoundResponse()`,\n ` const cfWs = createCloudflareWsBridge({`,\n ` onOpen: () => {},`,\n ` onMessage: (ws, data) => { ws.send(data) },`,\n ` onClose: () => {},`,\n ` })`,\n ` return cfWs.handle(request)`,\n ` }`,\n ``,\n ` if (!url.pathname.startsWith('/api/')) {`,\n nonApiBranch,\n ` }`,\n ``,\n ` if (!routesCache) routesCache = scanServerRoutes(serverDir)`,\n ` if (!loaderCache) loaderCache = createProductionLoader()`,\n ``,\n ` const match = matchRoute(url.pathname, routesCache)`,\n ` if (!match) return notFoundResponse()`,\n ``,\n ` const { req, res, toResponse } = createWebShim(request, { trustedProxy: 'platform' })`,\n ` const requestId = crypto.randomUUID()`,\n ` const method = request.method.toUpperCase()`,\n ` await executeRoute({`,\n ` route: match.route, method, params: match.params,`,\n ` req, res, loadModule: loaderCache, serverDir, requestId,`,\n ` })`,\n ` return toResponse()`,\n ` },`,\n `}`,\n ].join('\\n')\n}\n\nexport function renderWranglerToml(): string {\n return [\n `# Generated by Theo — Cloudflare Workers`,\n `name = \"theo-app\"`,\n `main = \".theo/cloudflare/worker.mjs\"`,\n `compatibility_date = \"2025-09-01\"`,\n `compatibility_flags = [\"nodejs_compat\"]`,\n ``,\n `[site]`,\n `bucket = \".theo/client\"`,\n ``,\n `# Environment variables are set via wrangler secret or dashboard`,\n `# Example: wrangler secret put DATABASE_URL`,\n ].join('\\n')\n}\n\nexport const cloudflareAdapter: DeployAdapter = {\n name: 'cloudflare',\n\n async build(config: TheoConfig, cwd: string, ctx?: AdapterBuildContext): Promise<void> {\n // Wave 2 (T2.2) — reject polyglot services on this adapter.\n assertServicesUnsupported('cloudflare', readManifest(cwd))\n\n // 1. Run the standard Node build first (ctx forwarded so nodeAdapter has makeVitePlugins)\n await nodeAdapter.build(config, cwd, ctx)\n\n const outputDir = resolve(cwd, '.theo/cloudflare')\n mkdirSync(outputDir, { recursive: true })\n\n // 2. Emit Worker entry (now uses the shared web-shim)\n writeFileSync(\n resolve(outputDir, 'worker.mjs'),\n renderCloudflareWorkerEntry({ ssrStreaming: config.ssrStreaming }),\n )\n\n // 3. Emit wrangler.toml (with nodejs_compat enforced)\n writeFileSync(resolve(cwd, 'wrangler.toml'), renderWranglerToml())\n\n // eslint-disable-next-line no-console -- CLI build progress\n console.log('\\n ✓ Cloudflare output → .theo/cloudflare/ + wrangler.toml\\n')\n },\n}\n"],"mappings":";;;;;;;;;;;;AAIA,SAAS,WAAW,qBAAqB;AACzC,SAAS,eAAe;AAcjB,SAAS,4BAA4B,OAAmC,CAAC,GAAW;AACzF,QAAM,kBAAkB,KAAK,eACzB,6DACA;AACJ,QAAM,eAAe,KAAK,eACtB;AAAA,4CACA;AAMJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,qBAA6B;AAC3C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEO,IAAM,oBAAmC;AAAA,EAC9C,MAAM;AAAA,EAEN,MAAM,MAAM,QAAoB,KAAa,KAA0C;AAErF,8BAA0B,cAAc,aAAa,GAAG,CAAC;AAGzD,UAAM,YAAY,MAAM,QAAQ,KAAK,GAAG;AAExC,UAAM,YAAY,QAAQ,KAAK,kBAAkB;AACjD,cAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAGxC;AAAA,MACE,QAAQ,WAAW,YAAY;AAAA,MAC/B,4BAA4B,EAAE,cAAc,OAAO,aAAa,CAAC;AAAA,IACnE;AAGA,kBAAc,QAAQ,KAAK,eAAe,GAAG,mBAAmB,CAAC;AAGjE,YAAQ,IAAI,yEAA+D;AAAA,EAC7E;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/deno-deploy.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Deno Deploy adapter. Writes to `cwd/.theo/deno-deploy/`. Build-time.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport type { TheoConfig } from '../config/schema.js'\nimport { assertServicesUnsupported, readManifest } from '../services/index.js'\n\nimport { nodeAdapter } from './node.js'\nimport type { AdapterBuildContext, DeployAdapter } from './types.js'\n\nexport interface DenoBuildDeps {\n runNodeBuild?: (config: TheoConfig, cwd: string, ctx?: AdapterBuildContext) => Promise<void>\n writeEntry?: (path: string, content: string) => void\n ensureDir?: (path: string) => void\n}\n\nexport function renderDenoEntry(port: number): string {\n return [\n `// Generated by Theo — Deno Deploy Adapter`,\n `// Deploy: deployctl deploy --project=<name> .theo/deno/server.ts`,\n `// Requires Deno >= 1.40 (Deno.serve + npm: specifier support)`,\n ``,\n `// Runtime guard`,\n `if (typeof Deno === 'undefined') {`,\n ` throw new Error('TheoDenoDeployAdapter must run inside Deno.')`,\n `}`,\n ``,\n `// Use npm: specifier so Deno resolves theokit from the user's package.json`,\n `// equivalent (works in both local 'deno run' and Deno Deploy).`,\n `import { scanServerRoutes, matchRoute, executeRoute, createProductionLoader, scanWebSocketRoutes } from 'npm:theokit/server'`,\n `import { createWebShim } from 'npm:theokit/adapters/web-shim'`,\n `// T3.3 — WS bridge for Deno runtime`,\n `import { createDenoWsBridge } from 'npm:theokit/adapters/ws-shim'`,\n ``,\n `const port = Number(Deno.env.get('PORT') ?? '${port}')`,\n `const cwd = Deno.cwd()`,\n `const serverDir = cwd + '/server'`,\n `let routesCache = null`,\n `let wsRoutesCache = null`,\n `let loaderCache = null`,\n ``,\n `function notFound() {`,\n ` return new Response(JSON.stringify({ error: { code: 'NOT_FOUND' } }), {`,\n ` status: 404,`,\n ` headers: { 'Content-Type': 'application/json' },`,\n ` })`,\n `}`,\n ``,\n `Deno.serve({ port }, async (request) => {`,\n ` const url = new URL(request.url)`,\n ``,\n ` // T3.3 — Detect WebSocket upgrade and delegate to the Deno bridge`,\n ` if (request.headers.get('upgrade')?.toLowerCase() === 'websocket') {`,\n ` if (!wsRoutesCache) wsRoutesCache = scanWebSocketRoutes(serverDir)`,\n ` if (wsRoutesCache.length === 0) return notFound()`,\n ` const denoWs = createDenoWsBridge({`,\n ` onOpen: () => {},`,\n ` onMessage: (ws, data) => { ws.send(data) },`,\n ` onClose: () => {},`,\n ` }, Deno)`,\n ` return denoWs.handle(request)`,\n ` }`,\n ``,\n ` if (!url.pathname.startsWith('/api/')) {`,\n ` // Static + SPA fallback are served by Deno Deploy's static asset handler.`,\n ` return notFound()`,\n ` }`,\n ``,\n ` if (!routesCache) routesCache = scanServerRoutes(serverDir)`,\n ` if (!loaderCache) loaderCache = createProductionLoader()`,\n ``,\n ` const match = matchRoute(url.pathname, routesCache)`,\n ` if (!match) return notFound()`,\n ``,\n ` const { req, res, toResponse } = createWebShim(request)`,\n ` const requestId = crypto.randomUUID()`,\n ` const method = request.method.toUpperCase()`,\n ` await executeRoute({ route: match.route, method, params: match.params, req, res, loadModule: loaderCache, serverDir, requestId })`,\n ` return toResponse()`,\n `})`,\n ``,\n `console.log('Theo (Deno Deploy) listening on :' + port)`,\n ].join('\\n')\n}\n\nexport async function buildDeno(\n config: TheoConfig,\n cwd: string,\n deps: DenoBuildDeps = {},\n ctx?: AdapterBuildContext,\n): Promise<void> {\n // Wave 2 (T2.2) — reject polyglot services on this adapter.\n assertServicesUnsupported('deno-deploy', readManifest(cwd))\n\n const runNodeBuild = deps.runNodeBuild ?? nodeAdapter.build.bind(nodeAdapter)\n await runNodeBuild(config, cwd, ctx)\n\n const outputDir = resolve(cwd, '.theo/deno')\n const ensureDir = deps.ensureDir ?? ((p: string) => mkdirSync(p, { recursive: true }))\n ensureDir(outputDir)\n\n const entry = renderDenoEntry(config.port)\n const write =\n deps.writeEntry ??\n ((p, c) => {\n writeFileSync(p, c)\n })\n write(resolve(outputDir, 'server.ts'), entry)\n\n // eslint-disable-next-line no-console -- CLI build progress\n console.log('\\n ✓ Deno Deploy output → .theo/deno/server.ts\\n')\n}\n\nexport const denoDeployAdapter: DeployAdapter = {\n name: 'deno-deploy',\n build(config, cwd, ctx) {\n return buildDeno(config, cwd, {}, ctx)\n },\n}\n"],"mappings":";;;;;;;;;;;;AAGA,SAAS,WAAW,qBAAqB;AACzC,SAAS,eAAe;AAcjB,SAAS,gBAAgB,MAAsB;AACpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gDAAgD,IAAI;AAAA,IACpD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,eAAsB,UACpB,QACA,KACA,OAAsB,CAAC,GACvB,KACe;AAEf,4BAA0B,eAAe,aAAa,GAAG,CAAC;AAE1D,QAAM,eAAe,KAAK,gBAAgB,YAAY,MAAM,KAAK,WAAW;AAC5E,QAAM,aAAa,QAAQ,KAAK,GAAG;AAEnC,QAAM,YAAY,QAAQ,KAAK,YAAY;AAC3C,QAAM,YAAY,KAAK,cAAc,CAAC,MAAc,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AACpF,YAAU,SAAS;AAEnB,QAAM,QAAQ,gBAAgB,OAAO,IAAI;AACzC,QAAM,QACJ,KAAK,eACJ,CAAC,GAAG,MAAM;AACT,kBAAc,GAAG,CAAC;AAAA,EACpB;AACF,QAAM,QAAQ,WAAW,WAAW,GAAG,KAAK;AAG5C,UAAQ,IAAI,6DAAmD;AACjE;AAEO,IAAM,oBAAmC;AAAA,EAC9C,MAAM;AAAA,EACN,MAAM,QAAQ,KAAK,KAAK;AACtB,WAAO,UAAU,QAAQ,KAAK,CAAC,GAAG,GAAG;AAAA,EACvC;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/commands/docker.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * CLI `theo docker`. Writes Dockerfile + .dockerignore under user's `cwd`.\n * Build-time tool. No HTTP input.\n */\nimport { existsSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nfunction detectPkgManager(cwd: string): 'pnpm' | 'npm' | 'yarn' {\n if (existsSync(resolve(cwd, 'pnpm-lock.yaml'))) return 'pnpm'\n if (existsSync(resolve(cwd, 'yarn.lock'))) return 'yarn'\n return 'npm'\n}\n\nfunction generateDockerfile(pkgManager: 'pnpm' | 'npm' | 'yarn'): string {\n const installCmd = {\n pnpm: 'RUN corepack enable && pnpm install --frozen-lockfile',\n npm: 'RUN npm ci',\n yarn: 'RUN yarn install --frozen-lockfile',\n }[pkgManager]\n\n const lockfile = {\n pnpm: 'pnpm-lock.yaml',\n npm: 'package-lock.json',\n yarn: 'yarn.lock',\n }[pkgManager]\n\n const runBuild = {\n pnpm: 'RUN pnpm theo build',\n npm: 'RUN npx theo build',\n yarn: 'RUN yarn theo build',\n }[pkgManager]\n\n const startCmd = {\n pnpm: 'CMD [\"pnpm\", \"theo\", \"start\"]',\n npm: 'CMD [\"npx\", \"theo\", \"start\"]',\n yarn: 'CMD [\"yarn\", \"theo\", \"start\"]',\n }[pkgManager]\n\n return [\n '# Generated by Theo',\n '# Multi-stage build for production',\n '',\n '# Stage 1: Build',\n 'FROM node:22-alpine AS builder',\n 'WORKDIR /app',\n `COPY package.json ${lockfile} ./`,\n installCmd,\n 'COPY . .',\n runBuild,\n '',\n '# Stage 2: Production',\n 'FROM node:22-alpine AS runner',\n 'WORKDIR /app',\n 'ENV NODE_ENV=production',\n 'COPY --from=builder /app/.theo ./.theo',\n 'COPY --from=builder /app/server ./server',\n 'COPY --from=builder /app/theo.config.ts ./theo.config.ts',\n 'COPY --from=builder /app/package.json ./package.json',\n `COPY --from=builder /app/${lockfile} ./${lockfile}`,\n 'COPY --from=builder /app/node_modules ./node_modules',\n '',\n 'EXPOSE 3000',\n startCmd,\n '',\n ].join('\\n')\n}\n\nfunction generateDockerignore(): string {\n return [\n 'node_modules',\n '.git',\n '.theo',\n 'dist',\n '.env',\n '.env.*',\n '!.env.example',\n '*.log',\n '.DS_Store',\n '.vscode',\n '.idea',\n 'Dockerfile',\n '.dockerignore',\n '',\n ].join('\\n')\n}\n\n// eslint-disable-next-line @typescript-eslint/require-await -- CLI surface contract is async; sync today is implementation detail\nexport async function dockerCommand(options?: { force?: boolean }): Promise<void> {\n const cwd = process.cwd()\n const dockerfilePath = resolve(cwd, 'Dockerfile')\n const dockerignorePath = resolve(cwd, '.dockerignore')\n\n if (existsSync(dockerfilePath) && !options?.force) {\n console.log('\\n ⚠ Dockerfile already exists. Use --force to overwrite.\\n')\n return\n }\n\n const pkgManager = detectPkgManager(cwd)\n writeFileSync(dockerfilePath, generateDockerfile(pkgManager))\n writeFileSync(dockerignorePath, generateDockerignore())\n\n console.log(`\\n ✓ Generated Dockerfile (${pkgManager})`)\n console.log(` ✓ Generated .dockerignore`)\n console.log(`\\n Next steps:`)\n console.log(` docker build -t my-app .`)\n console.log(` docker run -p 3000:3000 my-app\\n`)\n}\n"],"mappings":";;;;;AAIA,SAAS,YAAY,qBAAqB;AAC1C,SAAS,eAAe;AAExB,SAAS,iBAAiB,KAAsC;AAC9D,MAAI,WAAW,QAAQ,KAAK,gBAAgB,CAAC,EAAG,QAAO;AACvD,MAAI,WAAW,QAAQ,KAAK,WAAW,CAAC,EAAG,QAAO;AAClD,SAAO;AACT;AAEA,SAAS,mBAAmB,YAA6C;AACvE,QAAM,aAAa;AAAA,IACjB,MAAM;AAAA,IACN,KAAK;AAAA,IACL,MAAM;AAAA,EACR,EAAE,UAAU;AAEZ,QAAM,WAAW;AAAA,IACf,MAAM;AAAA,IACN,KAAK;AAAA,IACL,MAAM;AAAA,EACR,EAAE,UAAU;AAEZ,QAAM,WAAW;AAAA,IACf,MAAM;AAAA,IACN,KAAK;AAAA,IACL,MAAM;AAAA,EACR,EAAE,UAAU;AAEZ,QAAM,WAAW;AAAA,IACf,MAAM;AAAA,IACN,KAAK;AAAA,IACL,MAAM;AAAA,EACR,EAAE,UAAU;AAEZ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,qBAAqB,QAAQ;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,4BAA4B,QAAQ,MAAM,QAAQ;AAAA,IAClD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,uBAA+B;AACtC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAGA,eAAsB,cAAc,SAA8C;AAChF,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,iBAAiB,QAAQ,KAAK,YAAY;AAChD,QAAM,mBAAmB,QAAQ,KAAK,eAAe;AAErD,MAAI,WAAW,cAAc,KAAK,CAAC,SAAS,OAAO;AACjD,YAAQ,IAAI,mEAA8D;AAC1E;AAAA,EACF;AAEA,QAAM,aAAa,iBAAiB,GAAG;AACvC,gBAAc,gBAAgB,mBAAmB,UAAU,CAAC;AAC5D,gBAAc,kBAAkB,qBAAqB,CAAC;AAEtD,UAAQ,IAAI;AAAA,iCAA+B,UAAU,GAAG;AACxD,UAAQ,IAAI,kCAA6B;AACzC,UAAQ,IAAI;AAAA,cAAiB;AAC7B,UAAQ,IAAI,8BAA8B;AAC1C,UAAQ,IAAI;AAAA,CAAsC;AACpD;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/netlify.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Netlify deploy adapter. All paths derived from `cwd` and a fixed\n * `.theo/netlify/` output layout. Build-time tool — no HTTP input.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport type { TheoConfig } from '../config/schema.js'\nimport { assertServicesUnsupported, readManifest } from '../services/index.js'\n\nimport { nodeAdapter } from './node.js'\nimport type { AdapterBuildContext, DeployAdapter } from './types.js'\n\nexport class NetlifyConflictError extends Error {\n constructor(path: string, currentTo: string) {\n super(\n `netlify.toml has a conflicting redirect: \"${path}\" → \"${currentTo}\". ` +\n `Remove it manually or edit it to point to \"/.netlify/functions/theo\" ` +\n `before running the Netlify adapter again.`,\n )\n this.name = 'NetlifyConflictError'\n }\n}\n\nexport interface NetlifyBuildDeps {\n runNodeBuild?: (config: TheoConfig, cwd: string, ctx?: AdapterBuildContext) => Promise<void>\n writeFile?: (path: string, content: string) => void\n ensureDir?: (path: string) => void\n readTomlIfExists?: () => string | null\n}\n\nexport function renderNetlifyFunction(): string {\n return [\n `// Generated by Theo — Netlify Functions adapter`,\n `import { resolve } from 'node:path'`,\n `import { randomUUID } from 'node:crypto'`,\n `import { scanServerRoutes, matchRoute, executeRoute, createProductionLoader } from 'theokit/server'`,\n `import { createWebShim } from 'theokit/adapters/web-shim'`,\n ``,\n `const cwd = process.cwd()`,\n `const serverDir = resolve(cwd, 'server')`,\n `let routesCache = null`,\n `let loaderCache = null`,\n ``,\n `export default async (request, context) => {`,\n ` const url = new URL(request.url)`,\n ` if (!url.pathname.startsWith('/api/')) {`,\n ` return new Response('Not Found', { status: 404 })`,\n ` }`,\n ``,\n ` if (!routesCache) routesCache = scanServerRoutes(serverDir)`,\n ` if (!loaderCache) loaderCache = createProductionLoader()`,\n ``,\n ` const match = matchRoute(url.pathname, routesCache)`,\n ` if (!match) {`,\n ` return new Response(JSON.stringify({ error: { code: 'NOT_FOUND' } }), {`,\n ` status: 404,`,\n ` headers: { 'content-type': 'application/json' },`,\n ` })`,\n ` }`,\n ``,\n ` const { req, res, toResponse } = createWebShim(request)`,\n ` const requestId = randomUUID()`,\n ` const method = request.method.toUpperCase()`,\n ` await executeRoute({ route: match.route, method, params: match.params, req, res, loadModule: loaderCache, serverDir, requestId })`,\n ` return toResponse()`,\n `}`,\n ].join('\\n')\n}\n\nconst THEO_REDIRECT_FROM = '/api/*'\nconst THEO_REDIRECT_TO = '/.netlify/functions/theo'\n\n/**\n * TOML merge (EC-2) — non-destructive.\n *\n * We avoid adding a TOML parser dependency by working at the line level. The\n * supported subset is sufficient for the Netlify use case:\n * - detect existing `[[redirects]]` blocks\n * - find a block whose `from = \"...\"` matches our target\n * - error if such a block points elsewhere\n * - otherwise append our block\n *\n * Unknown sections (e.g. `[build]`, `[[headers]]`, `[context.production.environment]`)\n * are preserved as-is.\n */\ninterface NetlifyRedirectBlock {\n startLine: number\n endLine: number\n from?: string\n to?: string\n}\n\nfunction parseRedirectBlocks(lines: readonly string[]): NetlifyRedirectBlock[] {\n const blocks: NetlifyRedirectBlock[] = []\n let current: NetlifyRedirectBlock | null = null\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i].trim()\n if (trimmed === '[[redirects]]') {\n if (current) {\n current.endLine = i - 1\n blocks.push(current)\n }\n current = { startLine: i, endLine: i }\n continue\n }\n if (current && /^\\[(\\[|[^[])/.test(trimmed)) {\n // Entering another section — close current.\n current.endLine = i - 1\n blocks.push(current)\n current = null\n }\n if (current) {\n const fromMatch = /^from\\s*=\\s*\"([^\"]+)\"/.exec(trimmed)\n if (fromMatch) current.from = fromMatch[1]\n const toMatch = /^to\\s*=\\s*\"([^\"]+)\"/.exec(trimmed)\n if (toMatch) current.to = toMatch[1]\n current.endLine = i\n }\n }\n if (current) blocks.push(current)\n return blocks\n}\n\nconst THEO_REDIRECT_TARGET = [\n '[[redirects]]',\n ' from = \"/api/*\"',\n ' to = \"/.netlify/functions/theo\"',\n ' status = 200',\n ' force = true',\n].join('\\n')\n\nexport function mergeNetlifyToml(existing: string | null): string {\n if (existing === null || existing.trim().length === 0) {\n return `${THEO_REDIRECT_TARGET}\\n`\n }\n\n const blocks = parseRedirectBlocks(existing.split(/\\r?\\n/))\n\n // Detect conflict: every `/api/*` block must point at our function.\n for (const b of blocks) {\n if (b.from !== THEO_REDIRECT_FROM) continue\n if (b.to === THEO_REDIRECT_TO) {\n // Already merged — return existing as-is (idempotent).\n return existing.endsWith('\\n') ? existing : `${existing}\\n`\n }\n throw new NetlifyConflictError(b.from, b.to ?? '(unknown)')\n }\n\n // No conflict — append target block.\n const sep = existing.endsWith('\\n') ? '' : '\\n'\n return `${existing}${sep}\\n${THEO_REDIRECT_TARGET}\\n`\n}\n\nexport async function buildNetlify(\n config: TheoConfig,\n cwd: string,\n deps: NetlifyBuildDeps = {},\n ctx?: AdapterBuildContext,\n): Promise<void> {\n // Wave 2 (T2.2) — reject polyglot services on this adapter.\n assertServicesUnsupported('netlify', readManifest(cwd))\n\n const runNodeBuild = deps.runNodeBuild ?? nodeAdapter.build.bind(nodeAdapter)\n await runNodeBuild(config, cwd, ctx)\n\n const ensureDir = deps.ensureDir ?? ((p: string) => mkdirSync(p, { recursive: true }))\n const writeFile =\n deps.writeFile ??\n ((p, c) => {\n writeFileSync(p, c)\n })\n const readTomlIfExists =\n deps.readTomlIfExists ??\n (() => {\n const p = resolve(cwd, 'netlify.toml')\n return existsSync(p) ? readFileSync(p, 'utf-8') : null\n })\n\n const fnDir = resolve(cwd, '.netlify/functions')\n ensureDir(fnDir)\n writeFile(resolve(fnDir, 'theo.mjs'), renderNetlifyFunction())\n\n const existingToml = readTomlIfExists()\n const merged = mergeNetlifyToml(existingToml)\n writeFile(resolve(cwd, 'netlify.toml'), merged)\n\n // eslint-disable-next-line no-console -- CLI build progress\n console.log('\\n ✓ Netlify output → .netlify/functions/theo.mjs + netlify.toml\\n')\n}\n\nexport const netlifyAdapter: DeployAdapter = {\n name: 'netlify',\n build(config, cwd, ctx) {\n return buildNetlify(config, cwd, {}, ctx)\n },\n}\n"],"mappings":"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","names":[]}
@@ -1,25 +0,0 @@
1
- #!/usr/bin/env node
2
- import "tsx/esm";
3
- import "./chunk-KT3MWNZG.js";
4
-
5
- // src/adapters/registry.ts
6
- var adapterRegistry = {
7
- node: async () => (await import("./node-6I5B6RL3.js")).nodeAdapter,
8
- vercel: async () => (await import("./vercel-TKPZK62A.js")).vercelAdapter,
9
- cloudflare: async () => (await import("./cloudflare-OJGJ7R2D.js")).cloudflareAdapter,
10
- static: async () => (await import("./static-QI5NQT2X.js")).staticAdapter,
11
- bun: async () => (await import("./bun-ISHSNFIO.js")).bunAdapter,
12
- "deno-deploy": async () => (await import("./deno-deploy-BHWKFTOW.js")).denoDeployAdapter,
13
- netlify: async () => (await import("./netlify-GSNSJGMN.js")).netlifyAdapter,
14
- "aws-lambda": async () => (await import("./aws-lambda-GKSTX6HD.js")).awsLambdaAdapter,
15
- "theo-cloud": async () => (await import("./theo-cloud-RSQCBNXL.js")).theoCloudAdapter
16
- };
17
- async function resolveAdapter(target) {
18
- const factory = adapterRegistry[target];
19
- return factory();
20
- }
21
- export {
22
- adapterRegistry,
23
- resolveAdapter
24
- };
25
- //# sourceMappingURL=registry-QHEZ3BWB.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/commands/migrate/services-json.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time codemod: paths are derived from `<cwd>/theo.config.ts` (or\n * the supplied `--config` arg). No HTTP input reaches these fs calls.\n */\n/**\n * Plan v1.2 T2.3 + EC-2 — `theokit migrate services-json-v1-to-v2`.\n *\n * Idempotent codemod that injects a top-level `name` field into\n * `theo.config.ts` (and refreshes `.theo/services.json` if a build artifact\n * exists). When the resolved `name` would be `services-bundle`, the codemod\n * emits an actionable warning so the operator can decide between:\n * a) keeping `services-bundle` (zero-downtime — preserves the Gitea repo\n * lineage shipped by Plan B v3.1); or\n * b) renaming to a new project — requires ArgoCD App rewire downtime.\n *\n * Inputs (in order of precedence):\n * 1) explicit `--name <slug>` CLI argument\n * 2) `package.json` `name` field (slugified to DNS-1123)\n * 3) directory basename\n * 4) `services-bundle` fallback with a warning\n */\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { basename, join, resolve } from 'node:path'\n\nexport interface ServicesJsonMigrateOptions {\n /** Override theo.config.ts path. Defaults to `<cwd>/theo.config.ts`. */\n configPath?: string\n /** Override package.json path. Defaults to `<cwd>/package.json`. */\n pkgPath?: string\n /** Explicit project name. When set, bypasses package.json / dir-basename. */\n name?: string\n /** When true, prints the plan but performs no writes. */\n dryRun?: boolean\n /** When true, suppresses stdout (used in tests). */\n silent?: boolean\n /** When set, treats this as the working directory (defaults to process.cwd). */\n cwd?: string\n}\n\nexport interface ServicesJsonMigratePlan {\n /** The DNS-1123 project name that will land in theo.config.ts. */\n projectName: string\n /** Reason describing where the name came from. */\n source: 'flag' | 'package-json' | 'directory' | 'fallback'\n /** Whether `theo.config.ts` already declared `name`. */\n alreadyMigrated: boolean\n /** Warning string when projectName=services-bundle. Empty otherwise. */\n warning: string\n}\n\n// Canonical DNS-1123 anchor. Equivalent to ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$\n// but split into explicit single-char anchors so neither security/detect-\n// unsafe-regex nor sonarjs/slow-regex flag it (linear scan, no backtracking\n// hot paths over arbitrary input).\nfunction isDns1123(s: string): boolean {\n if (s.length === 0 || s.length > 63) return false\n for (let i = 0; i < s.length; i += 1) {\n const c = s.charCodeAt(i)\n const isLower = c >= 0x61 && c <= 0x7a\n const isDigit = c >= 0x30 && c <= 0x39\n const isHyphen = c === 0x2d\n if (!(isLower || isDigit || isHyphen)) return false\n if (i === 0 && isHyphen) return false\n if (i === s.length - 1 && isHyphen) return false\n }\n return true\n}\n\n/**\n * Best-effort slugifier: lowercases, replaces underscores with hyphens,\n * drops invalid characters, collapses repeated hyphens, trims leading /\n * trailing hyphens. Returns empty string when nothing survives.\n */\nexport function slugify(input: string): string {\n const lowered = input.toLowerCase()\n let result = ''\n let lastWasHyphen = false\n for (let i = 0; i < lowered.length; i += 1) {\n const ch = lowered.charAt(i)\n const code = lowered.charCodeAt(i)\n const isLower = code >= 0x61 && code <= 0x7a\n const isDigit = code >= 0x30 && code <= 0x39\n if (isLower || isDigit) {\n result += ch\n lastWasHyphen = false\n continue\n }\n if ((ch === '-' || ch === '_') && !lastWasHyphen && result.length > 0) {\n result += '-'\n lastWasHyphen = true\n }\n }\n while (result.endsWith('-')) result = result.slice(0, -1)\n return result.slice(0, 63)\n}\n\n/** Returns `true` when `theo.config.ts` source already declares `name: …`. */\nexport function configDeclaresName(source: string): boolean {\n // Linear scan instead of `[\\s\\S]*?` lookahead so sonarjs/slow-regex\n // stays clean (no super-linear backtracking). We anchor on `defineConfig(`\n // then walk forward looking for `name:` inside the literal block.\n const start = source.indexOf('defineConfig(')\n if (start < 0) return false\n return /\\bname\\s*:\\s*['\"]/u.test(source.slice(start))\n}\n\n/**\n * Inject `name: <project>,` into the first `defineConfig({ ... })` call.\n * Idempotent: when the config already declares `name`, returns the source\n * untouched.\n */\nexport function injectName(source: string, projectName: string): string {\n if (configDeclaresName(source)) return source\n return source.replace(/(defineConfig\\(\\s*\\{)([\\s\\S])/u, (_match, head: string, next: string) => {\n // Preserve existing whitespace style by sniffing the next character.\n const nl = next === '\\n' || next === '\\r' ? next : '\\n'\n return `${head}\\n name: '${projectName}',${nl === '\\n' ? '' : nl}`\n })\n}\n\ninterface CandidateResolution {\n projectName: string\n source: ServicesJsonMigratePlan['source']\n}\n\nfunction fromPackageJson(pkgPath: string): CandidateResolution | null {\n if (!existsSync(pkgPath)) return null\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { name?: string }\n if (typeof pkg.name !== 'string' || pkg.name.length === 0) return null\n const candidate = slugify(pkg.name)\n return isDns1123(candidate) ? { projectName: candidate, source: 'package-json' } : null\n } catch {\n return null\n }\n}\n\nfunction fromDirectoryBasename(cwd: string): CandidateResolution | null {\n const candidate = slugify(basename(resolve(cwd)))\n return isDns1123(candidate) ? { projectName: candidate, source: 'directory' } : null\n}\n\nfunction resolveProjectName(\n opts: ServicesJsonMigrateOptions,\n cwd: string,\n pkgPath: string,\n): CandidateResolution {\n if (opts.name !== undefined && opts.name.length > 0) {\n return { projectName: opts.name, source: 'flag' }\n }\n return (\n fromPackageJson(pkgPath) ??\n fromDirectoryBasename(cwd) ?? {\n projectName: 'services-bundle',\n source: 'fallback',\n }\n )\n}\n\nexport function planServicesJsonMigration(\n opts: ServicesJsonMigrateOptions,\n): ServicesJsonMigratePlan {\n const cwd = opts.cwd ?? process.cwd()\n const configPath = opts.configPath ?? join(cwd, 'theo.config.ts')\n const pkgPath = opts.pkgPath ?? join(cwd, 'package.json')\n\n const configSource = existsSync(configPath) ? readFileSync(configPath, 'utf-8') : ''\n const alreadyMigrated = configSource.length > 0 ? configDeclaresName(configSource) : false\n\n const resolution = resolveProjectName(opts, cwd, pkgPath)\n const warning =\n resolution.source === 'fallback'\n ? 'Using fallback project name `services-bundle`. This preserves the Gitea ' +\n 'repo lineage shipped by Plan B v3.1 (zero downtime). To adopt a new project ' +\n 'name, re-run with `--name <slug>` and coordinate the ArgoCD App rewire.'\n : ''\n\n if (!isDns1123(resolution.projectName)) {\n throw new Error(\n `services-json migrate: resolved project name \"${resolution.projectName}\" is not DNS-1123 ` +\n '(1-63 chars, lowercase alphanumeric+hyphens, no leading/trailing hyphen). Re-run with --name <slug>.',\n )\n }\n\n return {\n projectName: resolution.projectName,\n source: resolution.source,\n alreadyMigrated,\n warning,\n }\n}\n\n// Returns void; not async — kept Promise-bearing via the CLI dispatcher's\n// `await` site by wrapping into Promise.resolve(...) on the call boundary.\nexport function servicesJsonMigrateCommand(opts: ServicesJsonMigrateOptions): Promise<void> {\n const cwd = opts.cwd ?? process.cwd()\n const configPath = opts.configPath ?? join(cwd, 'theo.config.ts')\n const log = (m: string): void => {\n if (opts.silent === true) return\n process.stdout.write(`${m}\\n`)\n }\n\n if (!existsSync(configPath)) {\n return Promise.reject(\n new Error(`services-json migrate: ${configPath} not found. Run from a TheoKit project root.`),\n )\n }\n\n const plan = planServicesJsonMigration(opts)\n log(` • Resolved project name: '${plan.projectName}' (source: ${plan.source})`)\n if (plan.warning.length > 0) log(` ⚠ ${plan.warning}`)\n\n if (plan.alreadyMigrated) {\n log(' ✓ theo.config.ts already declares `name` — nothing to do (idempotent).')\n return Promise.resolve()\n }\n\n if (opts.dryRun === true) {\n log(' • Dry-run: would inject `name` into theo.config.ts (no write).')\n return Promise.resolve()\n }\n\n const before = readFileSync(configPath, 'utf-8')\n const after = injectName(before, plan.projectName)\n if (after === before) {\n log(\" ⚠ Could not locate `defineConfig({ ... })` block. Add `name: '<slug>',` manually.\")\n return Promise.resolve()\n }\n writeFileSync(configPath, after, 'utf-8')\n log(` ✓ Injected name='${plan.projectName}' into theo.config.ts`)\n log(' • Next: re-run `theokit build --target theo-cloud` to emit services.json v2.')\n return Promise.resolve()\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/commands/start/index.ts","../src/cli/commands/start/bootstrap-stages.ts","../src/cli/commands/start/graceful-shutdown.ts","../src/cli/commands/start/manifest-loader.ts","../src/cli/commands/start/request-handler.ts","../src/cli/commands/start/handlers.ts","../src/server/http/static.ts","../src/cli/commands/start/ssr-setup.ts","../src/cli/commands/start/websocket-handler.ts"],"sourcesContent":["/**\n * theokit start — production server orchestration spine.\n *\n * T4.2 (architecture-cleanup, ADR-0017): stages extracted to sibling modules.\n * - start-bootstrap-stages.ts — config/registry/storage bootstrap + resolveSsrEntry\n * - start-manifest-loader.ts — manifest.json or scan fallback\n * - start-ssr-setup.ts — SSR entry-server + HTML template split\n * - start-handlers.ts — branch handlers (action/route/static/404)\n * - start-request-handler.ts — request lifecycle wiring\n * - start-websocket-handler.ts — WS upgrade (opt-in)\n * - start-graceful-shutdown.ts — SIGTERM/SIGINT drain\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { createServer } from 'node:http'\nimport { join, resolve } from 'node:path'\n\nimport { loadConfig } from '../../../config/load-config.js'\nimport { loadEnv } from '../../../config/load-env.js'\nimport { createPluginRunnerFromConfig } from '../../../server/plugins/load-plugins.js'\nimport { createRateLimiter } from '../../../server/rate-limit/rate-limit.js'\nimport { createProductionLoader } from '../../../server/scan/module-loader.js'\nimport { resolveTransformer } from '../../../server/transformer.js'\nimport { preflightNodeAndBindings } from '../../preflight-node-version.js'\n\nimport {\n configureAgentRegistryFromConfig,\n configureStorageManagerFromConfig,\n} from './bootstrap-stages.js'\nimport { installGracefulShutdown } from './graceful-shutdown.js'\nimport type { RequestHandlerCtx } from './handlers.js'\nimport { loadRoutesAndActions } from './manifest-loader.js'\nimport { createRequestHandler } from './request-handler.js'\nimport { setupSsr } from './ssr-setup.js'\nimport { attachWebSocketHandler } from './websocket-handler.js'\n\n// Backwards-compat: external test fixtures may import resolveSsrEntry from here.\nexport { resolveSsrEntry } from './bootstrap-stages.js'\n\ninterface StartOptions {\n port?: number\n}\n\nexport async function startCommand(options: StartOptions): Promise<void> {\n const cwd = process.cwd()\n // Preflight (FIRST — BEFORE anything that touches native bindings).\n preflightNodeAndBindings(cwd)\n loadEnv({ cwd, mode: 'production' })\n const config = await loadConfig(cwd)\n\n await configureAgentRegistryFromConfig(config.agents?.registry)\n await configureStorageManagerFromConfig(config.storage)\n\n const distDir = resolve(cwd, '.theo')\n const clientDir = resolve(distDir, 'client')\n const serverDir = resolve(cwd, 'server')\n\n if (!existsSync(clientDir)) {\n throw new Error('No build found. Run `theo build` first.')\n }\n\n const indexHtml = readFileSync(join(clientDir, 'index.html'), 'utf-8')\n const loadModule = createProductionLoader()\n const port = options.port ?? config.port\n const pluginRunner = await createPluginRunnerFromConfig(config.plugins)\n const transformer = resolveTransformer(config.serialization)\n\n const custom404Path = join(clientDir, '404.html')\n const custom500Path = join(clientDir, '500.html')\n const custom404Html = existsSync(custom404Path) ? readFileSync(custom404Path, 'utf-8') : null\n const custom500Html = existsSync(custom500Path) ? readFileSync(custom500Path, 'utf-8') : null\n\n const {\n routes: cachedRoutes,\n actions: cachedActions,\n wsRoutes: cachedWsRoutes,\n } = loadRoutesAndActions(distDir, serverDir)\n\n // Rate limiter (legacy flat form only — per-route variant is handled in\n // api-middleware integration path, not this fallback).\n const flatRateLimit =\n config.rateLimit && 'windowMs' in config.rateLimit && 'max' in config.rateLimit\n ? config.rateLimit\n : undefined\n const rateLimiter = flatRateLimit ? createRateLimiter(flatRateLimit) : null\n\n const ssr = await setupSsr({\n distDir,\n indexHtml,\n ssrConfigEnabled: config.ssr,\n ssrStreamingConfig: config.ssrStreaming,\n })\n\n const server = createServer(\n createRequestHandler({\n buildCtx: (req, res, requestId, startTime): RequestHandlerCtx => ({\n req,\n res,\n url: req.url ?? '/',\n requestId,\n startTime,\n clientDir,\n custom404Html,\n cachedRoutes,\n cachedActions,\n loadModule,\n serverDir,\n pluginRunner,\n transformer,\n csrfMode: config.security?.csrf ?? 'strict',\n disallowed: config.security?.disallowed,\n rateLimiter,\n }),\n securityHeadersConfig: config.security?.headers ?? {},\n ssrRender: ssr.render,\n ssrRenderStreaming: ssr.renderStreaming,\n ssrStreamingEnabled: ssr.streamingEnabled,\n htmlHead: ssr.htmlHead,\n htmlTail: ssr.htmlTail,\n indexHtml,\n custom500Html,\n }),\n )\n\n await attachWebSocketHandler(server, cachedWsRoutes, loadModule)\n\n server.listen(port, () => {\n console.log(`\\n Theo production server`)\n console.log(` → http://localhost:${String(port)}\\n`)\n })\n\n installGracefulShutdown(server)\n}\n","/**\n * Bootstrap stages extracted from `start.ts` per T4.2 (architecture-cleanup, ADR-0017).\n *\n * The full goal of T4.2 is a ≤30-LOC `startCommand` spine + 6-8 stage files. This\n * file ships the first batch: the configure-from-config bootstrap helpers + the\n * SSR entry resolver. They are stand-alone, side-effect-free at module load, and\n * already individually testable.\n *\n * Remaining stages (request-handler extraction, graceful-shutdown extraction,\n * signal-handlers extraction) are deferred to a follow-up sprint — see plan\n * `docs/plans/architecture-cleanup-plan.md` T4.2 Deferred sub-tasks.\n */\n\nimport { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport { warnOnce } from '../../../server/observability/logger.js'\n\ninterface SdkAgentRegistry {\n configure?: (opts: { maxAgents?: number; idleTimeoutMs?: number }) => void\n}\ninterface SdkModule {\n Agent?: { registry?: SdkAgentRegistry }\n}\n\n/**\n * Configure SDK's Agent.registry from `theo.config.ts > agents.registry`.\n * Lazy at boot; EC-3 sync flag flip prevents race under concurrent boot.\n * Silent no-op when registry config is absent or SDK is uninstalled.\n */\nexport async function configureAgentRegistryFromConfig(\n registryConfig: { maxAgents: number; idleTimeoutMs: number } | undefined,\n): Promise<void> {\n if (registryConfig === undefined) return\n try {\n const sdk = (await import('@theokit/sdk').catch(() => null)) as SdkModule | null\n const sdkConfigure = sdk?.Agent?.registry?.configure\n if (sdkConfigure === undefined) return\n const { configureAgentRegistryOnce } =\n await import('../../../server/agent/configure-agent-registry.js')\n configureAgentRegistryOnce(\n {\n configure: (opts) => {\n sdkConfigure(opts)\n },\n },\n registryConfig,\n )\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n warnOnce('bootstrap.agent_registry_skip', {\n event: 'bootstrap.agent_registry_skip',\n message: msg,\n })\n }\n}\n\n/**\n * Configure the StorageManager from `theo.config.ts > storage` (ADR-0007).\n * Manager enforces configure-once internally (D3); this helper bridges the\n * config to the singleton with actionable error handling.\n */\nexport async function configureStorageManagerFromConfig(storageConfig: unknown): Promise<void> {\n if (storageConfig === undefined || storageConfig === null) return\n try {\n const { getStorageManager } = await import('../../../server/storage/storage-manager.js')\n const { storageSchema } = await import('../../../config/schema.js')\n // Re-validate at boot so a malformed config from a non-Zod source\n // (test fixtures, dynamic configs) surfaces a clear error early.\n const parsed = storageSchema.parse(storageConfig)\n getStorageManager().configure(parsed)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n warnOnce('bootstrap.storage_skip', {\n event: 'bootstrap.storage_skip',\n message: msg,\n })\n }\n}\n\nconst SSR_EXTENSIONS = ['.mjs', '.js'] as const\n\n/**\n * Resolve the SSR entry-server module path. tsup may emit `.mjs` or `.js`\n * depending on output format. Try `.mjs` first (modern default) then fall\n * back to `.js`. Returns null when neither exists — SSR stays disabled.\n *\n * Exported so unit tests can pin the resolution order without booting the\n * full CLI.\n */\nexport function resolveSsrEntry(distDir: string): string | null {\n for (const ext of SSR_EXTENSIONS) {\n const path = resolve(distDir, `server/entry-server${ext}`)\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- distDir is from `theokit start`'s own caller-controlled config; the suffix is from a const literal array\n if (existsSync(path)) return path\n }\n return null\n}\n","/**\n * Graceful shutdown stage for `theokit start` (T4.2 architecture-cleanup,\n * ADR-0007 D6 — SIGTERM evicts agents + drains StorageManager).\n *\n * EC-13: SIGTERM evicts agents IMMEDIATELY (no per-request drain). In-flight\n * requests get aborted mid-stream — acceptable because the platform LB\n * removed this pod from rotation BEFORE sending SIGTERM (K8s preStop hook +\n * terminationGracePeriodSeconds; same on Vercel/CF/Render).\n *\n * Re-entry guard: multiple SIGTERMs in quick succession run shutdown ONCE.\n */\n\nimport type { Server as HttpServer } from 'node:http'\n\nimport { warnOnce } from '../../../server/observability/logger.js'\n\nexport function installGracefulShutdown(server: HttpServer): void {\n let shuttingDown = false\n const shutdown = (signal: NodeJS.Signals): void => {\n if (shuttingDown) return\n shuttingDown = true\n console.log(`\\n [theokit] ${signal} received — evicting agents`)\n void (async () => {\n // Lazy-import SDK only at shutdown time to avoid forcing the dep on\n // apps that don't use agents at all.\n try {\n const sdk = (await import('@theokit/sdk').catch(() => null)) as {\n Agent?: { registry?: { evictAll?: () => Promise<void> } }\n } | null\n if (sdk?.Agent?.registry?.evictAll !== undefined) {\n await sdk.Agent.registry.evictAll()\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n warnOnce('shutdown.evict_error', {\n event: 'shutdown.evict_error',\n message: msg,\n })\n }\n // T3.1 — drain the StorageManager AFTER agent eviction. Order matters:\n // agents may still hold open pool refs while evicting; closing pools\n // first would break in-flight queries.\n try {\n const { getStorageManager } = await import('../../../server/storage/storage-manager.js')\n const manager = getStorageManager()\n await manager.dispose()\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n warnOnce('shutdown.dispose_error', {\n event: 'shutdown.dispose_error',\n message: msg,\n })\n }\n console.log(` [theokit] shutdown complete`)\n server.close(() => {\n process.exit(0)\n })\n setTimeout(() => {\n warnOnce('shutdown.forced_exit', {\n event: 'shutdown.forced_exit',\n message: 'forced exit after 25s timeout',\n })\n process.exit(0)\n }, 25_000).unref()\n })()\n }\n process.on('SIGTERM', () => {\n shutdown('SIGTERM')\n })\n process.on('SIGINT', () => {\n shutdown('SIGINT')\n })\n}\n","/**\n * Manifest loading stage for `theokit start` (T4.2 architecture-cleanup).\n *\n * Loads pre-built manifest from `.theo/manifest.json` if present; otherwise\n * scans server/ for routes/actions/ws at startup with a structured warn.\n */\n\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { warnOnce } from '../../../server/observability/logger.js'\nimport type { ActionNode } from '../../../server/scan/action-scan.js'\nimport { scanServerActions } from '../../../server/scan/action-scan.js'\nimport { loadManifest } from '../../../server/scan/manifest.js'\nimport type { ServerRouteNode } from '../../../server/scan/match.js'\nimport { scanServerRoutes } from '../../../server/scan/scan.js'\nimport type { WebSocketRouteNode } from '../../../server/scan/ws-scan.js'\nimport { scanWebSocketRoutes } from '../../../server/scan/ws-scan.js'\n\nexport interface LoadedRoutes {\n routes: ServerRouteNode[]\n actions: ActionNode[]\n wsRoutes: WebSocketRouteNode[]\n}\n\nexport function loadRoutesAndActions(distDir: string, serverDir: string): LoadedRoutes {\n const manifestPath = join(distDir, 'manifest.json')\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- distDir is from `theokit start`'s own caller-controlled cwd\n if (existsSync(manifestPath)) {\n const manifest = loadManifest(distDir, serverDir)\n return {\n routes: manifest.routes,\n actions: manifest.actions,\n wsRoutes: manifest.websockets,\n }\n }\n warnOnce('bootstrap.manifest_not_found', {\n event: 'bootstrap.manifest_not_found',\n message:\n 'No manifest found, scanning routes at startup. Run \"theo build\" to generate manifest.',\n serverDir,\n })\n return {\n routes: scanServerRoutes(serverDir),\n actions: scanServerActions(serverDir),\n wsRoutes: scanWebSocketRoutes(serverDir),\n }\n}\n","/**\n * Inline request handler for `theokit start` (T4.2 architecture-cleanup).\n *\n * Wires the per-request flow: security headers → action/route/static branches\n * → SSR fallback → CSR fallback → 500 page.\n */\n\nimport { randomUUID } from 'node:crypto'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport { generateNonce } from '../../../server/auth/nonce.js'\nimport { sendError } from '../../../server/http/send-response.js'\nimport { buildSecurityHeaders } from '../../../server/security/security-headers.js'\n\nimport {\n tryServeAction,\n tryServeApiRoute,\n tryServeCustom404,\n tryServeStatic,\n type RequestHandlerCtx,\n} from './handlers.js'\nimport {\n isSsrRenderResult,\n type SsrRender,\n type SsrRenderResult,\n type SsrRenderStreaming,\n} from './ssr-setup.js'\n\nexport interface RequestHandlerContext {\n buildCtx: (\n req: IncomingMessage,\n res: ServerResponse,\n requestId: string,\n startTime: number,\n ) => RequestHandlerCtx\n securityHeadersConfig: Parameters<typeof buildSecurityHeaders>[0]\n ssrRender: SsrRender | null\n ssrRenderStreaming: SsrRenderStreaming | null\n ssrStreamingEnabled: boolean\n htmlHead: string\n htmlTail: string\n indexHtml: string\n custom500Html: string | null\n}\n\nfunction asSsrRenderResult(value: SsrRenderResult): SsrRenderResult {\n return value\n}\n\n/* eslint-disable complexity, sonarjs/cognitive-complexity --\n * inline request orchestrator co-located so the lifecycle is readable end-to-end.\n */\nexport function createRequestHandler(\n ctx: RequestHandlerContext,\n): (req: IncomingMessage, res: ServerResponse) => void {\n return (req: IncomingMessage, res: ServerResponse) => {\n void (async () => {\n const url = req.url ?? '/'\n const requestId = randomUUID()\n const start = Date.now()\n\n // Per-request nonce (EC-6 dev/prod parity).\n const nonce = generateNonce()\n const securityHeaders = buildSecurityHeaders(\n ctx.securityHeadersConfig,\n { production: true },\n { nonce },\n )\n for (const [k, v] of Object.entries(securityHeaders)) {\n res.setHeader(k, v)\n }\n\n const handlerCtx = ctx.buildCtx(req, res, requestId, start)\n\n try {\n if (await tryServeAction(handlerCtx)) return\n if (await tryServeApiRoute(handlerCtx)) return\n if (tryServeStatic(handlerCtx)) return\n if (tryServeCustom404(handlerCtx)) return\n\n // SSR streaming branch\n if (ctx.ssrStreamingEnabled && ctx.ssrRenderStreaming) {\n const controller = new AbortController()\n const onClose = (): void => {\n controller.abort()\n }\n req.on('close', onClose)\n try {\n const result = await ctx.ssrRenderStreaming(url, res, {\n signal: controller.signal,\n nonce,\n })\n if (result && typeof result === 'object' && 'redirect' in result) {\n res.writeHead(302, { Location: result.redirect.headers.get('location') ?? '/' })\n res.end()\n return\n }\n return\n } catch (streamErr) {\n console.error('[SSR Stream Error]', (streamErr as Error).message)\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'text/html' })\n }\n if (!res.writableEnded) {\n res.end(ctx.custom500Html ?? '<h1>500 — Server Error</h1>')\n }\n return\n } finally {\n req.removeListener('close', onClose)\n }\n }\n\n // SSR (non-streaming) branch\n if (ctx.ssrRender) {\n try {\n const result = await ctx.ssrRender(url, { nonce })\n if (result && typeof result === 'object' && 'redirect' in result) {\n res.writeHead(302, { Location: result.redirect.headers.get('location') ?? '/' })\n res.end()\n return\n }\n let ssrHtml = ''\n let hydrationScript = ''\n if (typeof result === 'string') {\n ssrHtml = result\n } else if (isSsrRenderResult(result)) {\n const rendered = asSsrRenderResult(result)\n ssrHtml = rendered.html\n const dataJson = JSON.stringify(rendered.hydrationData).replace(/</g, '\\\\u003c')\n hydrationScript = `<script${\n nonce ? ` nonce=\"${nonce}\"` : ''\n }>window.__staticRouterHydrationData=${dataJson}</script>`\n }\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(ctx.htmlHead + ssrHtml + hydrationScript + ctx.htmlTail)\n return\n } catch (ssrErr) {\n console.error('[SSR Error] Falling back to CSR:', (ssrErr as Error).message)\n // Fall through to CSR fallback\n }\n }\n\n // CSR fallback\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(ctx.indexHtml)\n } catch (err) {\n if (ctx.custom500Html && !res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'text/html' })\n res.end(ctx.custom500Html)\n } else if (!res.headersSent) {\n sendError(res, 'INTERNAL_ERROR', (err as Error).message, 500)\n } else {\n res.end()\n }\n }\n })()\n }\n}\n/* eslint-enable complexity, sonarjs/cognitive-complexity */\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { extname } from 'node:path'\n\nimport { executeAction } from '../../../server/http/action-execute.js'\nimport { executeRoute } from '../../../server/http/execute.js'\nimport { sendError } from '../../../server/http/send-response.js'\nimport { serveStaticFile } from '../../../server/http/static.js'\nimport { logRequest } from '../../../server/observability/logger.js'\nimport { findSuggestion } from '../../../server/observability/suggest.js'\nimport type { PluginRunner } from '../../../server/plugins/plugin-runner.js'\nimport type { ActionNode } from '../../../server/scan/action-scan.js'\nimport { matchRoute } from '../../../server/scan/match.js'\nimport type { ServerRouteNode } from '../../../server/scan/match.js'\nimport type { LoadModule } from '../../../server/scan/module-loader.js'\nimport type { CsrfMode, DisallowedConfig } from '../../../server/security/csrf.js'\nimport type { TheoTransformer } from '../../../server/transformer.js'\n\n/**\n * T6.1 (PV-7 SRP): start.ts request orchestrator decomposed into 5 focused\n * per-branch handlers. Each handler returns `true` if it handled the\n * request (response sent) so the orchestrator can stop iterating.\n *\n * The original 455-LOC monolith closed over 14+ locals; the shared shape\n * `RequestHandlerCtx` makes the dependencies explicit + reviewable.\n */\nexport interface RequestHandlerCtx {\n req: IncomingMessage\n res: ServerResponse\n url: string\n requestId: string\n startTime: number\n // Pre-loaded build artifacts\n clientDir: string\n custom404Html: string | null\n // Manifest-resolved tables\n cachedRoutes: ServerRouteNode[]\n cachedActions: ActionNode[]\n // Runtime infra\n loadModule: LoadModule\n serverDir: string\n pluginRunner: PluginRunner | undefined\n transformer: TheoTransformer | undefined\n csrfMode: CsrfMode\n disallowed: DisallowedConfig | undefined\n rateLimiter:\n | ((req: IncomingMessage) => { limited: boolean; headers: Record<string, string> })\n | null\n}\n\n/** Apply rate limit; return true if request was limited (response sent). */\nfunction applyRateLimit(c: RequestHandlerCtx, method: string): boolean {\n if (!c.rateLimiter) return false\n const check = c.rateLimiter(c.req)\n for (const [k, v] of Object.entries(check.headers)) c.res.setHeader(k, v)\n if (check.limited) {\n sendError(c.res, 'RATE_LIMITED', 'Too many requests', 429, undefined, c.requestId)\n logRequest({\n method,\n url: c.url,\n status: 429,\n duration: Date.now() - c.startTime,\n requestId: c.requestId,\n })\n return true\n }\n return false\n}\n\n/** Branch 1: action routes (`/api/__actions/{file}/{exportName}`). */\nexport async function tryServeAction(c: RequestHandlerCtx): Promise<boolean> {\n if (!c.url.startsWith('/api/__actions/')) return false\n c.res.setHeader('x-request-id', c.requestId)\n\n if (applyRateLimit(c, c.req.method ?? 'POST')) return true\n\n const pathAfterPrefix = c.url.slice('/api/__actions/'.length).split('?')[0]\n const segments = pathAfterPrefix.split('/').filter(Boolean)\n if (segments.length < 2) {\n sendError(\n c.res,\n 'BAD_REQUEST',\n 'Action URL must be /api/__actions/{file}/{exportName}',\n 400,\n undefined,\n c.requestId,\n )\n logRequest({\n method: c.req.method ?? 'POST',\n url: c.url,\n status: 400,\n duration: Date.now() - c.startTime,\n requestId: c.requestId,\n })\n return true\n }\n const exportName = segments[segments.length - 1]\n const actionPath = segments.slice(0, -1).join('/')\n const action = c.cachedActions.find((a) => a.actionPath === actionPath)\n if (!action) {\n const actionPaths = c.cachedActions.map((a) => a.actionPath)\n const suggestion = findSuggestion(actionPath, actionPaths)\n const msg = suggestion\n ? `Action \"${actionPath}\" not found. Did you mean: ${suggestion}?`\n : `Action \"${actionPath}\" not found`\n sendError(c.res, 'NOT_FOUND', msg, 404, undefined, c.requestId)\n logRequest({\n method: c.req.method ?? 'POST',\n url: c.url,\n status: 404,\n duration: Date.now() - c.startTime,\n requestId: c.requestId,\n })\n return true\n }\n await executeAction(\n action.filePath,\n exportName,\n c.req,\n c.res,\n c.loadModule,\n c.serverDir,\n c.requestId,\n c.pluginRunner,\n c.csrfMode,\n c.disallowed,\n )\n logRequest({\n method: c.req.method ?? 'POST',\n url: c.url,\n status: c.res.statusCode,\n duration: Date.now() - c.startTime,\n requestId: c.requestId,\n })\n return true\n}\n\n/** Branch 2: API routes (`/api/*` excluding actions). */\nexport async function tryServeApiRoute(c: RequestHandlerCtx): Promise<boolean> {\n if (!c.url.startsWith('/api/')) return false\n c.res.setHeader('x-request-id', c.requestId)\n\n if (applyRateLimit(c, c.req.method ?? 'GET')) return true\n\n const match = matchRoute(c.url, c.cachedRoutes)\n if (!match) {\n const urlPath = c.url.split('?')[0]\n const routePaths = c.cachedRoutes.map((r) => r.routePath)\n const suggestion = findSuggestion(urlPath, routePaths)\n const msg = suggestion\n ? `API route not found: ${urlPath}. Did you mean: ${suggestion}?`\n : 'API route not found'\n sendError(c.res, 'NOT_FOUND', msg, 404, undefined, c.requestId)\n logRequest({\n method: c.req.method ?? 'GET',\n url: c.url,\n status: 404,\n duration: Date.now() - c.startTime,\n requestId: c.requestId,\n })\n return true\n }\n const method = (c.req.method ?? 'GET').toUpperCase()\n // T3.1 (ADR-0016) — context object replaces 12 positional args\n await executeRoute({\n route: match.route,\n method,\n params: match.params,\n req: c.req,\n res: c.res,\n loadModule: c.loadModule,\n serverDir: c.serverDir,\n requestId: c.requestId,\n pluginRunner: c.pluginRunner,\n transformer: c.transformer,\n csrfMode: c.csrfMode,\n disallowed: c.disallowed,\n })\n logRequest({\n method,\n url: c.url,\n status: c.res.statusCode,\n duration: Date.now() - c.startTime,\n requestId: c.requestId,\n })\n return true\n}\n\n/** Branch 3: static files (returns true if a static asset was served). */\nexport function tryServeStatic(c: RequestHandlerCtx): boolean {\n return serveStaticFile(c.req, c.res, c.clientDir)\n}\n\n/** Branch 4: custom 404 for URLs that look like missing assets. */\nexport function tryServeCustom404(c: RequestHandlerCtx): boolean {\n const urlPath = c.url.split('?')[0]\n if (c.custom404Html && extname(urlPath)) {\n c.res.writeHead(404, { 'Content-Type': 'text/html' })\n c.res.end(c.custom404Html)\n return true\n }\n return false\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Static-file server. The URL path IS user-controlled, BUT before any fs\n * call we resolve to absolute and reject with 403 if the resolved path\n * escapes `clientDir` (see EC-1 guard at line below). The guard is\n * authoritative; the rule cannot see it.\n */\nimport { existsSync, readFileSync, statSync } from 'node:fs'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport { resolve, extname } from 'node:path'\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html',\n '.js': 'application/javascript',\n '.mjs': 'application/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.txt': 'text/plain',\n '.map': 'application/json',\n}\n\nexport function serveStaticFile(\n req: IncomingMessage,\n res: ServerResponse,\n clientDir: string,\n): boolean {\n const urlPath = (req.url ?? '/').split('?')[0]\n\n // Path traversal prevention (EC-1)\n const filePath = resolve(clientDir, '.' + urlPath)\n if (!filePath.startsWith(clientDir)) {\n res.writeHead(403)\n res.end('Forbidden')\n return true\n }\n\n if (!existsSync(filePath)) return false\n\n const stat = statSync(filePath)\n if (!stat.isFile()) return false\n\n const ext = extname(filePath)\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream'\n const content = readFileSync(filePath)\n\n res.writeHead(200, {\n 'Content-Type': contentType,\n 'Content-Length': content.length,\n })\n res.end(content)\n return true\n}\n","/**\n * SSR setup stage for `theokit start` (T4.2 architecture-cleanup).\n *\n * Loads the SSR entry-server module if configured + builds template split\n * around the React root div. Returns null renderers when SSR is disabled.\n */\n\nimport type { ServerResponse } from 'node:http'\n\nimport { resolveSsrEntry } from './bootstrap-stages.js'\n\nexport interface SsrRenderResult {\n html: string\n hydrationData: {\n loaderData?: unknown\n actionData?: unknown\n errors?: unknown\n }\n}\n\nexport type RenderStreamingResult = { redirect: Response } | { streaming: true } | undefined\n\nexport type SsrRender = (\n url: string,\n options?: { nonce?: string },\n) => Promise<SsrRenderResult | { redirect: Response } | string>\n\nexport type SsrRenderStreaming = (\n url: string,\n response: ServerResponse,\n options?: { signal?: AbortSignal; nonce?: string },\n) => Promise<RenderStreamingResult>\n\nexport interface SsrSetupResult {\n enabled: boolean\n streamingEnabled: boolean\n render: SsrRender | null\n renderStreaming: SsrRenderStreaming | null\n htmlHead: string\n htmlTail: string\n}\n\nexport function isSsrRenderResult(value: unknown): value is SsrRenderResult {\n if (typeof value !== 'object' || value === null) return false\n if (!('html' in value)) return false\n const html = (value as Record<string, unknown>).html\n if (typeof html !== 'string') return false\n return true\n}\n\ninterface SsrEntryServer {\n render: SsrRender\n renderStreaming?: SsrRenderStreaming\n}\n\nexport async function setupSsr(opts: {\n distDir: string\n indexHtml: string\n ssrConfigEnabled: boolean\n ssrStreamingConfig: boolean | undefined\n}): Promise<SsrSetupResult> {\n const ssrServerPath: string | null = opts.ssrConfigEnabled ? resolveSsrEntry(opts.distDir) : null\n const enabled = ssrServerPath !== null\n const streamingEnabled = enabled && Boolean(opts.ssrStreamingConfig)\n\n if (ssrServerPath === null) {\n return {\n enabled: false,\n streamingEnabled: false,\n render: null,\n renderStreaming: null,\n htmlHead: '',\n htmlTail: '',\n }\n }\n\n const mod = (await import(ssrServerPath)) as SsrEntryServer\n const render = mod.render\n const renderStreaming = typeof mod.renderStreaming === 'function' ? mod.renderStreaming : null\n\n // Split HTML template on root div\n let htmlHead = ''\n let htmlTail = ''\n const rootDivMatch = /<div id=[\"']root[\"'][^>]*>/.exec(opts.indexHtml)\n if (rootDivMatch) {\n const splitIdx = opts.indexHtml.indexOf(rootDivMatch[0]) + rootDivMatch[0].length\n htmlHead = opts.indexHtml.slice(0, splitIdx)\n htmlTail = opts.indexHtml.slice(splitIdx)\n }\n\n return { enabled, streamingEnabled, render, renderStreaming, htmlHead, htmlTail }\n}\n","/**\n * WebSocket upgrade handler for `theokit start` (T4.2 architecture-cleanup).\n *\n * Wires `server.on('upgrade')` for declared WS routes. Opt-in: only attached\n * when `wsRoutes.length > 0`. Lazy-imports `ws` package — throws an actionable\n * error when wsRoutes declared but `ws` not installed.\n */\n\nimport type { Server as HttpServer } from 'node:http'\n\nimport type * as WsLib from 'ws'\n\nimport type { WebSocketHandler } from '../../../server/define/define-websocket.js'\nimport type { LoadModule } from '../../../server/scan/module-loader.js'\nimport type { WebSocketRouteNode } from '../../../server/scan/ws-scan.js'\n\nexport async function attachWebSocketHandler(\n server: HttpServer,\n wsRoutes: WebSocketRouteNode[],\n loadModule: LoadModule,\n): Promise<void> {\n if (wsRoutes.length === 0) return\n\n let WebSocketServerCtor: typeof WsLib.WebSocketServer\n try {\n const wsModule = await import('ws')\n WebSocketServerCtor = wsModule.WebSocketServer\n } catch {\n throw new Error('WebSocket routes found but \"ws\" package is not installed. Run: npm install ws')\n }\n\n const wss = new WebSocketServerCtor({ noServer: true })\n\n server.on('upgrade', (request, socket, head) => {\n void (async () => {\n const url = request.url ?? '/'\n if (!url.startsWith('/ws/')) {\n socket.destroy()\n return\n }\n\n const wsPath = url.split('?')[0]\n const match = wsRoutes.find((r) => r.wsPath === wsPath)\n if (!match) {\n socket.destroy()\n return\n }\n\n try {\n const mod = await loadModule(match.filePath)\n const handler = ((mod as { default?: unknown }).default ?? mod) as WebSocketHandler\n\n wss.handleUpgrade(request, socket, head, (ws) => {\n handler.onOpen?.(ws, request)\n ws.on('message', (data: Buffer) => {\n handler.onMessage?.(ws, data.toString())\n })\n ws.on('close', (code: number, reason: Buffer) => {\n handler.onClose?.(ws, code, reason)\n })\n ws.on('error', (err: Error) => {\n handler.onError?.(ws, err)\n })\n })\n } catch {\n socket.destroy()\n }\n })()\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,SAAS,cAAAA,aAAY,gBAAAC,qBAAoB;AACzC,SAAS,oBAAoB;AAC7B,SAAS,QAAAC,OAAM,WAAAC,gBAAe;;;ACF9B,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AAgBxB,eAAsB,iCACpB,gBACe;AACf,MAAI,mBAAmB,OAAW;AAClC,MAAI;AACF,UAAM,MAAO,MAAM,OAAO,oBAAc,EAAE,MAAM,MAAM,IAAI;AAC1D,UAAM,eAAe,KAAK,OAAO,UAAU;AAC3C,QAAI,iBAAiB,OAAW;AAChC,UAAM,EAAE,2BAA2B,IACjC,MAAM,OAAO,wCAAmD;AAClE;AAAA,MACE;AAAA,QACE,WAAW,CAAC,SAAS;AACnB,uBAAa,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAS,iCAAiC;AAAA,MACxC,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAOA,eAAsB,kCAAkC,eAAuC;AAC7F,MAAI,kBAAkB,UAAa,kBAAkB,KAAM;AAC3D,MAAI;AACF,UAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,+BAA4C;AACvF,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,sBAA2B;AAGlE,UAAM,SAAS,cAAc,MAAM,aAAa;AAChD,sBAAkB,EAAE,UAAU,MAAM;AAAA,EACtC,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAS,0BAA0B;AAAA,MACjC,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAEA,IAAM,iBAAiB,CAAC,QAAQ,KAAK;AAU9B,SAAS,gBAAgB,SAAgC;AAC9D,aAAW,OAAO,gBAAgB;AAChC,UAAM,OAAO,QAAQ,SAAS,sBAAsB,GAAG,EAAE;AAEzD,QAAI,WAAW,IAAI,EAAG,QAAO;AAAA,EAC/B;AACA,SAAO;AACT;;;ACjFO,SAAS,wBAAwB,QAA0B;AAChE,MAAI,eAAe;AACnB,QAAM,WAAW,CAAC,WAAiC;AACjD,QAAI,aAAc;AAClB,mBAAe;AACf,YAAQ,IAAI;AAAA,cAAiB,MAAM,kCAA6B;AAChE,UAAM,YAAY;AAGhB,UAAI;AACF,cAAM,MAAO,MAAM,OAAO,oBAAc,EAAE,MAAM,MAAM,IAAI;AAG1D,YAAI,KAAK,OAAO,UAAU,aAAa,QAAW;AAChD,gBAAM,IAAI,MAAM,SAAS,SAAS;AAAA,QACpC;AAAA,MACF,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,iBAAS,wBAAwB;AAAA,UAC/B,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAIA,UAAI;AACF,cAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,+BAA4C;AACvF,cAAM,UAAU,kBAAkB;AAClC,cAAM,QAAQ,QAAQ;AAAA,MACxB,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,iBAAS,0BAA0B;AAAA,UACjC,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AACA,cAAQ,IAAI,+BAA+B;AAC3C,aAAO,MAAM,MAAM;AACjB,gBAAQ,KAAK,CAAC;AAAA,MAChB,CAAC;AACD,iBAAW,MAAM;AACf,iBAAS,wBAAwB;AAAA,UAC/B,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AACD,gBAAQ,KAAK,CAAC;AAAA,MAChB,GAAG,IAAM,EAAE,MAAM;AAAA,IACnB,GAAG;AAAA,EACL;AACA,UAAQ,GAAG,WAAW,MAAM;AAC1B,aAAS,SAAS;AAAA,EACpB,CAAC;AACD,UAAQ,GAAG,UAAU,MAAM;AACzB,aAAS,QAAQ;AAAA,EACnB,CAAC;AACH;;;ACjEA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,YAAY;AAiBd,SAAS,qBAAqB,SAAiB,WAAiC;AACrF,QAAM,eAAe,KAAK,SAAS,eAAe;AAElD,MAAIC,YAAW,YAAY,GAAG;AAC5B,UAAM,WAAW,aAAa,SAAS,SAAS;AAChD,WAAO;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB,SAAS,SAAS;AAAA,MAClB,UAAU,SAAS;AAAA,IACrB;AAAA,EACF;AACA,WAAS,gCAAgC;AAAA,IACvC,OAAO;AAAA,IACP,SACE;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO;AAAA,IACL,QAAQ,iBAAiB,SAAS;AAAA,IAClC,SAAS,kBAAkB,SAAS;AAAA,IACpC,UAAU,oBAAoB,SAAS;AAAA,EACzC;AACF;;;ACxCA,SAAS,kBAAkB;;;ACN3B,SAAS,WAAAC,gBAAe;;;ACKxB,SAAS,cAAAC,aAAY,cAAc,gBAAgB;AAEnD,SAAS,WAAAC,UAAS,eAAe;AAEjC,IAAM,aAAqC;AAAA,EACzC,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,SAAS,gBACd,KACA,KACA,WACS;AACT,QAAM,WAAW,IAAI,OAAO,KAAK,MAAM,GAAG,EAAE,CAAC;AAG7C,QAAM,WAAWA,SAAQ,WAAW,MAAM,OAAO;AACjD,MAAI,CAAC,SAAS,WAAW,SAAS,GAAG;AACnC,QAAI,UAAU,GAAG;AACjB,QAAI,IAAI,WAAW;AACnB,WAAO;AAAA,EACT;AAEA,MAAI,CAACD,YAAW,QAAQ,EAAG,QAAO;AAElC,QAAM,OAAO,SAAS,QAAQ;AAC9B,MAAI,CAAC,KAAK,OAAO,EAAG,QAAO;AAE3B,QAAM,MAAM,QAAQ,QAAQ;AAC5B,QAAM,cAAc,WAAW,GAAG,KAAK;AACvC,QAAM,UAAU,aAAa,QAAQ;AAErC,MAAI,UAAU,KAAK;AAAA,IACjB,gBAAgB;AAAA,IAChB,kBAAkB,QAAQ;AAAA,EAC5B,CAAC;AACD,MAAI,IAAI,OAAO;AACf,SAAO;AACT;;;ADTA,SAAS,eAAe,GAAsB,QAAyB;AACrE,MAAI,CAAC,EAAE,YAAa,QAAO;AAC3B,QAAM,QAAQ,EAAE,YAAY,EAAE,GAAG;AACjC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,OAAO,EAAG,GAAE,IAAI,UAAU,GAAG,CAAC;AACxE,MAAI,MAAM,SAAS;AACjB,cAAU,EAAE,KAAK,gBAAgB,qBAAqB,KAAK,QAAW,EAAE,SAAS;AACjF,eAAW;AAAA,MACT;AAAA,MACA,KAAK,EAAE;AAAA,MACP,QAAQ;AAAA,MACR,UAAU,KAAK,IAAI,IAAI,EAAE;AAAA,MACzB,WAAW,EAAE;AAAA,IACf,CAAC;AACD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGA,eAAsB,eAAe,GAAwC;AAC3E,MAAI,CAAC,EAAE,IAAI,WAAW,iBAAiB,EAAG,QAAO;AACjD,IAAE,IAAI,UAAU,gBAAgB,EAAE,SAAS;AAE3C,MAAI,eAAe,GAAG,EAAE,IAAI,UAAU,MAAM,EAAG,QAAO;AAEtD,QAAM,kBAAkB,EAAE,IAAI,MAAM,kBAAkB,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC;AAC1E,QAAM,WAAW,gBAAgB,MAAM,GAAG,EAAE,OAAO,OAAO;AAC1D,MAAI,SAAS,SAAS,GAAG;AACvB;AAAA,MACE,EAAE;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE;AAAA,IACJ;AACA,eAAW;AAAA,MACT,QAAQ,EAAE,IAAI,UAAU;AAAA,MACxB,KAAK,EAAE;AAAA,MACP,QAAQ;AAAA,MACR,UAAU,KAAK,IAAI,IAAI,EAAE;AAAA,MACzB,WAAW,EAAE;AAAA,IACf,CAAC;AACD,WAAO;AAAA,EACT;AACA,QAAM,aAAa,SAAS,SAAS,SAAS,CAAC;AAC/C,QAAM,aAAa,SAAS,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AACjD,QAAM,SAAS,EAAE,cAAc,KAAK,CAAC,MAAM,EAAE,eAAe,UAAU;AACtE,MAAI,CAAC,QAAQ;AACX,UAAM,cAAc,EAAE,cAAc,IAAI,CAAC,MAAM,EAAE,UAAU;AAC3D,UAAM,aAAa,eAAe,YAAY,WAAW;AACzD,UAAM,MAAM,aACR,WAAW,UAAU,8BAA8B,UAAU,MAC7D,WAAW,UAAU;AACzB,cAAU,EAAE,KAAK,aAAa,KAAK,KAAK,QAAW,EAAE,SAAS;AAC9D,eAAW;AAAA,MACT,QAAQ,EAAE,IAAI,UAAU;AAAA,MACxB,KAAK,EAAE;AAAA,MACP,QAAQ;AAAA,MACR,UAAU,KAAK,IAAI,IAAI,EAAE;AAAA,MACzB,WAAW,EAAE;AAAA,IACf,CAAC;AACD,WAAO;AAAA,EACT;AACA,QAAM;AAAA,IACJ,OAAO;AAAA,IACP;AAAA,IACA,EAAE;AAAA,IACF,EAAE;AAAA,IACF,EAAE;AAAA,IACF,EAAE;AAAA,IACF,EAAE;AAAA,IACF,EAAE;AAAA,IACF,EAAE;AAAA,IACF,EAAE;AAAA,EACJ;AACA,aAAW;AAAA,IACT,QAAQ,EAAE,IAAI,UAAU;AAAA,IACxB,KAAK,EAAE;AAAA,IACP,QAAQ,EAAE,IAAI;AAAA,IACd,UAAU,KAAK,IAAI,IAAI,EAAE;AAAA,IACzB,WAAW,EAAE;AAAA,EACf,CAAC;AACD,SAAO;AACT;AAGA,eAAsB,iBAAiB,GAAwC;AAC7E,MAAI,CAAC,EAAE,IAAI,WAAW,OAAO,EAAG,QAAO;AACvC,IAAE,IAAI,UAAU,gBAAgB,EAAE,SAAS;AAE3C,MAAI,eAAe,GAAG,EAAE,IAAI,UAAU,KAAK,EAAG,QAAO;AAErD,QAAM,QAAQ,WAAW,EAAE,KAAK,EAAE,YAAY;AAC9C,MAAI,CAAC,OAAO;AACV,UAAM,UAAU,EAAE,IAAI,MAAM,GAAG,EAAE,CAAC;AAClC,UAAM,aAAa,EAAE,aAAa,IAAI,CAAC,MAAM,EAAE,SAAS;AACxD,UAAM,aAAa,eAAe,SAAS,UAAU;AACrD,UAAM,MAAM,aACR,wBAAwB,OAAO,mBAAmB,UAAU,MAC5D;AACJ,cAAU,EAAE,KAAK,aAAa,KAAK,KAAK,QAAW,EAAE,SAAS;AAC9D,eAAW;AAAA,MACT,QAAQ,EAAE,IAAI,UAAU;AAAA,MACxB,KAAK,EAAE;AAAA,MACP,QAAQ;AAAA,MACR,UAAU,KAAK,IAAI,IAAI,EAAE;AAAA,MACzB,WAAW,EAAE;AAAA,IACf,CAAC;AACD,WAAO;AAAA,EACT;AACA,QAAM,UAAU,EAAE,IAAI,UAAU,OAAO,YAAY;AAEnD,QAAM,aAAa;AAAA,IACjB,OAAO,MAAM;AAAA,IACb;AAAA,IACA,QAAQ,MAAM;AAAA,IACd,KAAK,EAAE;AAAA,IACP,KAAK,EAAE;AAAA,IACP,YAAY,EAAE;AAAA,IACd,WAAW,EAAE;AAAA,IACb,WAAW,EAAE;AAAA,IACb,cAAc,EAAE;AAAA,IAChB,aAAa,EAAE;AAAA,IACf,UAAU,EAAE;AAAA,IACZ,YAAY,EAAE;AAAA,EAChB,CAAC;AACD,aAAW;AAAA,IACT;AAAA,IACA,KAAK,EAAE;AAAA,IACP,QAAQ,EAAE,IAAI;AAAA,IACd,UAAU,KAAK,IAAI,IAAI,EAAE;AAAA,IACzB,WAAW,EAAE;AAAA,EACf,CAAC;AACD,SAAO;AACT;AAGO,SAAS,eAAe,GAA+B;AAC5D,SAAO,gBAAgB,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS;AAClD;AAGO,SAAS,kBAAkB,GAA+B;AAC/D,QAAM,UAAU,EAAE,IAAI,MAAM,GAAG,EAAE,CAAC;AAClC,MAAI,EAAE,iBAAiBE,SAAQ,OAAO,GAAG;AACvC,MAAE,IAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AACpD,MAAE,IAAI,IAAI,EAAE,aAAa;AACzB,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;AE/JO,SAAS,kBAAkB,OAA0C;AAC1E,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,MAAI,EAAE,UAAU,OAAQ,QAAO;AAC/B,QAAM,OAAQ,MAAkC;AAChD,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,SAAO;AACT;AAOA,eAAsB,SAAS,MAKH;AAC1B,QAAM,gBAA+B,KAAK,mBAAmB,gBAAgB,KAAK,OAAO,IAAI;AAC7F,QAAM,UAAU,kBAAkB;AAClC,QAAM,mBAAmB,WAAW,QAAQ,KAAK,kBAAkB;AAEnE,MAAI,kBAAkB,MAAM;AAC1B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,kBAAkB;AAAA,MAClB,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,EACF;AAEA,QAAM,MAAO,MAAM,OAAO;AAC1B,QAAM,SAAS,IAAI;AACnB,QAAM,kBAAkB,OAAO,IAAI,oBAAoB,aAAa,IAAI,kBAAkB;AAG1F,MAAI,WAAW;AACf,MAAI,WAAW;AACf,QAAM,eAAe,6BAA6B,KAAK,KAAK,SAAS;AACrE,MAAI,cAAc;AAChB,UAAM,WAAW,KAAK,UAAU,QAAQ,aAAa,CAAC,CAAC,IAAI,aAAa,CAAC,EAAE;AAC3E,eAAW,KAAK,UAAU,MAAM,GAAG,QAAQ;AAC3C,eAAW,KAAK,UAAU,MAAM,QAAQ;AAAA,EAC1C;AAEA,SAAO,EAAE,SAAS,kBAAkB,QAAQ,iBAAiB,UAAU,SAAS;AAClF;;;AH9CA,SAAS,kBAAkB,OAAyC;AAClE,SAAO;AACT;AAKO,SAAS,qBACd,KACqD;AACrD,SAAO,CAAC,KAAsB,QAAwB;AACpD,UAAM,YAAY;AAChB,YAAM,MAAM,IAAI,OAAO;AACvB,YAAM,YAAY,WAAW;AAC7B,YAAM,QAAQ,KAAK,IAAI;AAGvB,YAAM,QAAQ,cAAc;AAC5B,YAAM,kBAAkB;AAAA,QACtB,IAAI;AAAA,QACJ,EAAE,YAAY,KAAK;AAAA,QACnB,EAAE,MAAM;AAAA,MACV;AACA,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,eAAe,GAAG;AACpD,YAAI,UAAU,GAAG,CAAC;AAAA,MACpB;AAEA,YAAM,aAAa,IAAI,SAAS,KAAK,KAAK,WAAW,KAAK;AAE1D,UAAI;AACF,YAAI,MAAM,eAAe,UAAU,EAAG;AACtC,YAAI,MAAM,iBAAiB,UAAU,EAAG;AACxC,YAAI,eAAe,UAAU,EAAG;AAChC,YAAI,kBAAkB,UAAU,EAAG;AAGnC,YAAI,IAAI,uBAAuB,IAAI,oBAAoB;AACrD,gBAAM,aAAa,IAAI,gBAAgB;AACvC,gBAAM,UAAU,MAAY;AAC1B,uBAAW,MAAM;AAAA,UACnB;AACA,cAAI,GAAG,SAAS,OAAO;AACvB,cAAI;AACF,kBAAM,SAAS,MAAM,IAAI,mBAAmB,KAAK,KAAK;AAAA,cACpD,QAAQ,WAAW;AAAA,cACnB;AAAA,YACF,CAAC;AACD,gBAAI,UAAU,OAAO,WAAW,YAAY,cAAc,QAAQ;AAChE,kBAAI,UAAU,KAAK,EAAE,UAAU,OAAO,SAAS,QAAQ,IAAI,UAAU,KAAK,IAAI,CAAC;AAC/E,kBAAI,IAAI;AACR;AAAA,YACF;AACA;AAAA,UACF,SAAS,WAAW;AAClB,oBAAQ,MAAM,sBAAuB,UAAoB,OAAO;AAChE,gBAAI,CAAC,IAAI,aAAa;AACpB,kBAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAAA,YACpD;AACA,gBAAI,CAAC,IAAI,eAAe;AACtB,kBAAI,IAAI,IAAI,iBAAiB,kCAA6B;AAAA,YAC5D;AACA;AAAA,UACF,UAAE;AACA,gBAAI,eAAe,SAAS,OAAO;AAAA,UACrC;AAAA,QACF;AAGA,YAAI,IAAI,WAAW;AACjB,cAAI;AACF,kBAAM,SAAS,MAAM,IAAI,UAAU,KAAK,EAAE,MAAM,CAAC;AACjD,gBAAI,UAAU,OAAO,WAAW,YAAY,cAAc,QAAQ;AAChE,kBAAI,UAAU,KAAK,EAAE,UAAU,OAAO,SAAS,QAAQ,IAAI,UAAU,KAAK,IAAI,CAAC;AAC/E,kBAAI,IAAI;AACR;AAAA,YACF;AACA,gBAAI,UAAU;AACd,gBAAI,kBAAkB;AACtB,gBAAI,OAAO,WAAW,UAAU;AAC9B,wBAAU;AAAA,YACZ,WAAW,kBAAkB,MAAM,GAAG;AACpC,oBAAM,WAAW,kBAAkB,MAAM;AACzC,wBAAU,SAAS;AACnB,oBAAM,WAAW,KAAK,UAAU,SAAS,aAAa,EAAE,QAAQ,MAAM,SAAS;AAC/E,gCAAkB,UAChB,QAAQ,WAAW,KAAK,MAAM,EAChC,uCAAuC,QAAQ;AAAA,YACjD;AACA,gBAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,gBAAI,IAAI,IAAI,WAAW,UAAU,kBAAkB,IAAI,QAAQ;AAC/D;AAAA,UACF,SAAS,QAAQ;AACf,oBAAQ,MAAM,oCAAqC,OAAiB,OAAO;AAAA,UAE7E;AAAA,QACF;AAGA,YAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,YAAI,IAAI,IAAI,SAAS;AAAA,MACvB,SAAS,KAAK;AACZ,YAAI,IAAI,iBAAiB,CAAC,IAAI,aAAa;AACzC,cAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,cAAI,IAAI,IAAI,aAAa;AAAA,QAC3B,WAAW,CAAC,IAAI,aAAa;AAC3B,oBAAU,KAAK,kBAAmB,IAAc,SAAS,GAAG;AAAA,QAC9D,OAAO;AACL,cAAI,IAAI;AAAA,QACV;AAAA,MACF;AAAA,IACF,GAAG;AAAA,EACL;AACF;;;AI7IA,eAAsB,uBACpB,QACA,UACA,YACe;AACf,MAAI,SAAS,WAAW,EAAG;AAE3B,MAAI;AACJ,MAAI;AACF,UAAM,WAAW,MAAM,OAAO,IAAI;AAClC,0BAAsB,SAAS;AAAA,EACjC,QAAQ;AACN,UAAM,IAAI,MAAM,+EAA+E;AAAA,EACjG;AAEA,QAAM,MAAM,IAAI,oBAAoB,EAAE,UAAU,KAAK,CAAC;AAEtD,SAAO,GAAG,WAAW,CAAC,SAAS,QAAQ,SAAS;AAC9C,UAAM,YAAY;AAChB,YAAM,MAAM,QAAQ,OAAO;AAC3B,UAAI,CAAC,IAAI,WAAW,MAAM,GAAG;AAC3B,eAAO,QAAQ;AACf;AAAA,MACF;AAEA,YAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC;AAC/B,YAAM,QAAQ,SAAS,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM;AACtD,UAAI,CAAC,OAAO;AACV,eAAO,QAAQ;AACf;AAAA,MACF;AAEA,UAAI;AACF,cAAM,MAAM,MAAM,WAAW,MAAM,QAAQ;AAC3C,cAAM,UAAY,IAA8B,WAAW;AAE3D,YAAI,cAAc,SAAS,QAAQ,MAAM,CAAC,OAAO;AAC/C,kBAAQ,SAAS,IAAI,OAAO;AAC5B,aAAG,GAAG,WAAW,CAAC,SAAiB;AACjC,oBAAQ,YAAY,IAAI,KAAK,SAAS,CAAC;AAAA,UACzC,CAAC;AACD,aAAG,GAAG,SAAS,CAAC,MAAc,WAAmB;AAC/C,oBAAQ,UAAU,IAAI,MAAM,MAAM;AAAA,UACpC,CAAC;AACD,aAAG,GAAG,SAAS,CAAC,QAAe;AAC7B,oBAAQ,UAAU,IAAI,GAAG;AAAA,UAC3B,CAAC;AAAA,QACH,CAAC;AAAA,MACH,QAAQ;AACN,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF,GAAG;AAAA,EACL,CAAC;AACH;;;AR1BA,eAAsB,aAAa,SAAsC;AACvE,QAAM,MAAM,QAAQ,IAAI;AAExB,2BAAyB,GAAG;AAC5B,UAAQ,EAAE,KAAK,MAAM,aAAa,CAAC;AACnC,QAAM,SAAS,MAAM,WAAW,GAAG;AAEnC,QAAM,iCAAiC,OAAO,QAAQ,QAAQ;AAC9D,QAAM,kCAAkC,OAAO,OAAO;AAEtD,QAAM,UAAUC,SAAQ,KAAK,OAAO;AACpC,QAAM,YAAYA,SAAQ,SAAS,QAAQ;AAC3C,QAAM,YAAYA,SAAQ,KAAK,QAAQ;AAEvC,MAAI,CAACC,YAAW,SAAS,GAAG;AAC1B,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AAEA,QAAM,YAAYC,cAAaC,MAAK,WAAW,YAAY,GAAG,OAAO;AACrE,QAAM,aAAa,uBAAuB;AAC1C,QAAM,OAAO,QAAQ,QAAQ,OAAO;AACpC,QAAM,eAAe,MAAM,6BAA6B,OAAO,OAAO;AACtE,QAAM,cAAc,mBAAmB,OAAO,aAAa;AAE3D,QAAM,gBAAgBA,MAAK,WAAW,UAAU;AAChD,QAAM,gBAAgBA,MAAK,WAAW,UAAU;AAChD,QAAM,gBAAgBF,YAAW,aAAa,IAAIC,cAAa,eAAe,OAAO,IAAI;AACzF,QAAM,gBAAgBD,YAAW,aAAa,IAAIC,cAAa,eAAe,OAAO,IAAI;AAEzF,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ,IAAI,qBAAqB,SAAS,SAAS;AAI3C,QAAM,gBACJ,OAAO,aAAa,cAAc,OAAO,aAAa,SAAS,OAAO,YAClE,OAAO,YACP;AACN,QAAM,cAAc,gBAAgB,kBAAkB,aAAa,IAAI;AAEvE,QAAM,MAAM,MAAM,SAAS;AAAA,IACzB;AAAA,IACA;AAAA,IACA,kBAAkB,OAAO;AAAA,IACzB,oBAAoB,OAAO;AAAA,EAC7B,CAAC;AAED,QAAM,SAAS;AAAA,IACb,qBAAqB;AAAA,MACnB,UAAU,CAAC,KAAK,KAAK,WAAW,eAAkC;AAAA,QAChE;AAAA,QACA;AAAA,QACA,KAAK,IAAI,OAAO;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,OAAO,UAAU,QAAQ;AAAA,QACnC,YAAY,OAAO,UAAU;AAAA,QAC7B;AAAA,MACF;AAAA,MACA,uBAAuB,OAAO,UAAU,WAAW,CAAC;AAAA,MACpD,WAAW,IAAI;AAAA,MACf,oBAAoB,IAAI;AAAA,MACxB,qBAAqB,IAAI;AAAA,MACzB,UAAU,IAAI;AAAA,MACd,UAAU,IAAI;AAAA,MACd;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,uBAAuB,QAAQ,gBAAgB,UAAU;AAE/D,SAAO,OAAO,MAAM,MAAM;AACxB,YAAQ,IAAI;AAAA,yBAA4B;AACxC,YAAQ,IAAI,6BAAwB,OAAO,IAAI,CAAC;AAAA,CAAI;AAAA,EACtD,CAAC;AAED,0BAAwB,MAAM;AAChC;","names":["existsSync","readFileSync","join","resolve","existsSync","existsSync","extname","existsSync","resolve","extname","resolve","existsSync","readFileSync","join"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/static.ts","../src/adapters/static-paths.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * All filesystem inputs in this file are derived from:\n * - `process.cwd()` resolved at build time, OR\n * - directory tree walks rooted in `serverDir`/`appDir` (themselves\n * resolved from cwd), OR\n * - file paths produced by `collectStaticPaths` (a controlled router\n * scanner).\n * No path here originates from HTTP input, environment variables, or\n * deserialized user data. The path-traversal vector the rule guards\n * against does not apply — this is a build-time tool, not a request\n * handler.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve, relative } from 'node:path'\nimport { pathToFileURL } from 'node:url'\n\nimport type { TheoConfig } from '../config/schema.js'\nimport { scanRoutes } from '../router/scan.js'\nimport type { RouteNode } from '../router/types.js'\nimport { assertServicesUnsupported, readManifest } from '../services/index.js'\n\nimport { nodeAdapter } from './node.js'\nimport {\n collectStaticPaths,\n type CollectOptions,\n type LoadStaticPaths,\n type ResolvedPath,\n} from './static-paths.js'\nimport type { AdapterBuildContext, DeployAdapter } from './types.js'\n\nexport class StaticApiRoutesDetectedError extends Error {\n constructor(routes: string[]) {\n super(\n `Static adapter cannot build a project with API routes. Found: ${routes.join(\n ', ',\n )}. Use 'node', 'vercel', 'cloudflare' or another runtime adapter.`,\n )\n this.name = 'StaticApiRoutesDetectedError'\n }\n}\n\nexport class StaticRenderError extends Error {\n constructor(url: string, cause: unknown) {\n const causeMsg = cause instanceof Error ? cause.message : String(cause)\n super(`SSR render failed for ${url}: ${causeMsg}`)\n this.name = 'StaticRenderError'\n if (cause instanceof Error) {\n this.cause = cause\n }\n }\n}\n\nexport interface StaticBuildDeps {\n detectApiRoutes?: (serverDir: string) => string[]\n scanAppRoutes?: (appDir: string) => RouteNode\n collectPaths?: (tree: RouteNode, options: CollectOptions) => Promise<ResolvedPath[]>\n loadStaticPaths?: LoadStaticPaths\n renderHtml?: (url: string, cwd: string) => Promise<string>\n ensureDir?: (path: string) => Promise<void>\n writeFile?: (path: string, content: string) => Promise<void>\n runNodeBuild?: (config: TheoConfig, cwd: string, ctx?: AdapterBuildContext) => Promise<void>\n}\n\nexport function detectApiRoutes(serverDir: string): string[] {\n const routesDir = resolve(serverDir, 'routes')\n if (!existsSync(routesDir)) return []\n if (!statSync(routesDir).isDirectory()) return []\n\n const out: string[] = []\n walkRoutes(routesDir, routesDir, out)\n return out\n}\n\nfunction walkRoutes(root: string, dir: string, out: string[]): void {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.name.startsWith('.') || entry.name.startsWith('_')) continue\n const full = resolve(dir, entry.name)\n if (entry.isDirectory()) {\n walkRoutes(root, full, out)\n } else if (entry.isFile() && /\\.(ts|tsx|js|jsx|mjs)$/.test(entry.name)) {\n const rel = relative(root, full).split(/[\\\\/]/).join('/')\n out.push(rel)\n }\n }\n}\n\n/* eslint-disable @typescript-eslint/require-await -- DI contract is async; default impl uses sync fs */\n\n// The DI surface exposes async helpers (so consumers can override with\n// real async IO — e.g. S3 uploads). The defaults use sync fs because\n// every caller awaits the result anyway.\nconst defaultEnsureDir = async (path: string): Promise<void> => {\n mkdirSync(path, { recursive: true })\n}\n\nconst defaultWriteFile = async (path: string, content: string): Promise<void> => {\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, content)\n}\n\n/* eslint-enable @typescript-eslint/require-await */\n\n/**\n * Default loader: dynamic-imports the file at `paramsFilePath` and invokes\n * its default export. Returns null if the file does not exist (the caller\n * will throw StaticPathsRequiredError with a clear message in that case).\n */\nconst defaultLoadStaticPaths: LoadStaticPaths = async (paramsFilePath) => {\n if (!existsSync(paramsFilePath)) return null\n try {\n const mod = (await import(pathToFileURL(paramsFilePath).href)) as {\n default?: LoadStaticPaths | (() => Awaited<ReturnType<LoadStaticPaths>>)\n }\n if (typeof mod.default !== 'function') return null\n // The user's `static-paths.ts` may export `default` as either sync or\n // async — `await` accepts both, but ESLint's `await-thenable` cannot\n // see through the union.\n const value = mod.default(paramsFilePath)\n const result = value instanceof Promise ? await value : value\n return result ?? null\n } catch {\n return null\n }\n}\n\n/**\n * Default renderer: loads the built SSR entry (`.theo/server/entry-server.js`)\n * and calls its `render(url)` export, wrapping the result in the client\n * `index.html` template. Falls back to a minimal HTML shell when no SSR build\n * is present (so the static adapter still emits something usable even without\n * SSR enabled).\n */\nfunction createDefaultRenderHtml(cwd: string): (url: string) => Promise<string> {\n return async (url: string): Promise<string> => {\n const clientDir = resolve(cwd, '.theo/client')\n const indexPath = resolve(clientDir, 'index.html')\n const ssrEntryPath = resolve(cwd, '.theo/server/entry-server.js')\n\n let baseHtml = '<!doctype html><html><body><div id=\"root\"></div></body></html>'\n if (existsSync(indexPath)) {\n baseHtml = readFileSync(indexPath, 'utf-8')\n }\n\n if (!existsSync(ssrEntryPath)) {\n // No SSR build — emit the client shell. Hydration on the client will\n // render the route once JS loads. Acceptable degradation when the user\n // chose static + ssr: false.\n return baseHtml\n }\n\n try {\n const mod = (await import(pathToFileURL(ssrEntryPath).href)) as {\n render?: (u: string) => Promise<string | { redirect: Response }>\n }\n if (typeof mod.render !== 'function') return baseHtml\n const result = await mod.render(url)\n if (typeof result === 'string') {\n const rootMatch = /<div id=[\"']root[\"'][^>]*>/.exec(baseHtml)\n if (rootMatch) {\n const splitIdx = baseHtml.indexOf(rootMatch[0]) + rootMatch[0].length\n return baseHtml.slice(0, splitIdx) + result + baseHtml.slice(splitIdx)\n }\n return baseHtml.replace('</body>', result + '</body>')\n }\n // redirect — emit a meta refresh fallback for static export\n return `<!doctype html><meta http-equiv=\"refresh\" content=\"0; url=/\" />`\n } catch (err) {\n throw new StaticRenderError(url, err)\n }\n }\n}\n\nexport async function buildStatic(\n config: TheoConfig,\n cwd: string,\n deps: StaticBuildDeps = {},\n ctx?: AdapterBuildContext,\n): Promise<void> {\n // Wave 2 (T2.2) — reject polyglot services on this adapter.\n assertServicesUnsupported('static', readManifest(cwd))\n\n const detect = deps.detectApiRoutes ?? detectApiRoutes\n const apiRoutes = detect(resolve(cwd, 'server'))\n if (apiRoutes.length > 0) {\n throw new StaticApiRoutesDetectedError(apiRoutes)\n }\n\n const runNodeBuild = deps.runNodeBuild ?? nodeAdapter.build.bind(nodeAdapter)\n await runNodeBuild(config, cwd, ctx)\n\n const scan = deps.scanAppRoutes ?? scanRoutes\n const appDir = resolve(cwd, 'app')\n const tree = scan(appDir)\n\n const loadStaticPaths = deps.loadStaticPaths ?? defaultLoadStaticPaths\n const collect = deps.collectPaths ?? collectStaticPaths\n const paths = await collect(tree, { appDir, loadStaticPaths })\n\n if (paths.length === 0) return\n\n const renderHtml = deps.renderHtml ?? createDefaultRenderHtml(cwd)\n const ensureDir = deps.ensureDir ?? defaultEnsureDir\n const writeFile = deps.writeFile ?? defaultWriteFile\n\n const outDir = resolve(cwd, '.theo/static')\n await ensureDir(outDir)\n\n for (const path of paths) {\n let html: string\n try {\n html = await renderHtml(path.url, cwd)\n } catch (err) {\n throw new StaticRenderError(path.url, err)\n }\n const outPath = resolve(outDir, path.filename)\n await writeFile(outPath, html)\n }\n}\n\nexport const staticAdapter: DeployAdapter = {\n name: 'static',\n build(config, cwd, ctx) {\n return buildStatic(config, cwd, {}, ctx)\n },\n}\n","import type { RouteNode } from '../router/types.js'\n\nexport interface ResolvedPath {\n /** URL path to render, e.g. '/blog/123' */\n url: string\n /** Output file path relative to .theo/static/, e.g. 'blog/123.html' */\n filename: string\n}\n\nexport type StaticPathParams = Record<string, string | string[]>\n\nexport type LoadStaticPaths = (paramsFilePath: string) => Promise<StaticPathParams[] | null>\n\nexport class StaticPathsRequiredError extends Error {\n constructor(routePath: string, paramsFile: string) {\n super(\n `Route ${routePath} has dynamic segments and requires ${paramsFile}. ` +\n `Export default function returning Array<{ <param>: string | string[] }>.`,\n )\n this.name = 'StaticPathsRequiredError'\n }\n}\n\nexport interface CollectOptions {\n appDir: string\n loadStaticPaths: LoadStaticPaths\n}\n\nexport type ParsedSegment =\n | { kind: 'static' }\n | { kind: 'param'; name: string }\n | { kind: 'catch-all'; name: string }\n\nconst CATCH_ALL = /^\\[\\.\\.\\.(.+)\\]$/\nconst PARAM = /^\\[(.+)\\]$/\n\nexport function parseSegment(segment: string): ParsedSegment {\n const catchAll = CATCH_ALL.exec(segment)\n if (catchAll) return { kind: 'catch-all', name: catchAll[1] }\n const param = PARAM.exec(segment)\n if (param) return { kind: 'param', name: param[1] }\n return { kind: 'static' }\n}\n\nexport async function collectStaticPaths(\n tree: RouteNode,\n options: CollectOptions,\n): Promise<ResolvedPath[]> {\n const out: ResolvedPath[] = []\n await walk(tree, [], out, options)\n return out\n}\n\nasync function walk(\n node: RouteNode,\n parentSegments: string[],\n out: ResolvedPath[],\n options: CollectOptions,\n): Promise<void> {\n const segments = node.segment === '' ? parentSegments : [...parentSegments, node.segment]\n\n if (node.page) {\n const resolved = await resolveNodePaths(segments, options)\n out.push(...resolved)\n }\n\n for (const child of node.children) {\n await walk(child, segments, out, options)\n }\n}\n\nasync function resolveNodePaths(\n segments: string[],\n options: CollectOptions,\n): Promise<ResolvedPath[]> {\n if (segments.length === 0) {\n return [{ url: '/', filename: 'index.html' }]\n }\n\n const parsed = segments.map(parseSegment)\n const hasDynamic = parsed.some((p) => p.kind !== 'static')\n\n if (!hasDynamic) {\n const joined = segments.join('/')\n return [{ url: '/' + joined, filename: joined + '.html' }]\n }\n\n let lastDynamicIdx = 0\n for (let i = 0; i < parsed.length; i++) {\n if (parsed[i].kind !== 'static') lastDynamicIdx = i\n }\n\n const dirSegments = segments.slice(0, lastDynamicIdx + 1)\n const paramsFile = `${options.appDir}/${dirSegments.join('/')}/static-paths.ts`\n const params = await options.loadStaticPaths(paramsFile)\n\n if (!params) {\n const routePath = '/' + segments.join('/')\n throw new StaticPathsRequiredError(routePath, paramsFile)\n }\n\n return params.map((paramSet) => {\n const filled: string[] = []\n for (let i = 0; i < segments.length; i++) {\n const p = parsed[i]\n if (p.kind === 'static') {\n filled.push(segments[i])\n } else {\n const value = paramSet[p.name]\n if (Array.isArray(value)) {\n filled.push(...value)\n } else {\n filled.push(value)\n }\n }\n }\n const joined = filled.join('/')\n return { url: '/' + joined, filename: joined + '.html' }\n })\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/theo-cloud.ts"],"sourcesContent":["/**\n * TheoCloud deploy adapter (Wave 3 v2.0 thin validator).\n *\n * Per ADR-0012 (mission expansion) + 2026-06-05 owner architectural decision,\n * TheoKit OSS does NOT emit K8s manifests. This adapter is intentionally thin:\n * 1. Validates the `.theo/services.json` manifest shape (existing zod gate)\n * 2. Logs the services that will be deployed (visibility)\n * 3. Returns — bundle is ready for upload\n *\n * K8s manifest emission lives ENTIRELY inside TheoCloud (proprietary Go code)\n * upon receiving the upload. Rationale: OSS framework MUST emit formats\n * consumed by public/open systems OR neutral exchange formats; NÃO formats\n * consumed by proprietary closed systems. Exposing K8s shape here would leak\n * TheoCloud-internal infrastructure choices into the OSS surface.\n */\nimport type { TheoConfig } from '../config/schema.js'\nimport { prepareTheoCloudArtifacts, readManifest } from '../services/index.js'\n\nimport type { DeployAdapter } from './types.js'\n\nexport const theoCloudAdapter: DeployAdapter = {\n name: 'theo-cloud',\n\n build(_config: TheoConfig, cwd: string): Promise<void> {\n const manifest = readManifest(cwd)\n const artifacts = prepareTheoCloudArtifacts(manifest)\n const summary =\n artifacts.services.length === 0 ? 'TS-only app (no services)' : artifacts.services.join(', ')\n // eslint-disable-next-line no-console -- CLI build progress\n console.log(\n `[theo-cloud] Wave 3 v2.0: manifest schemaVersion=${String(artifacts.manifestVersion)}, ` +\n `services=${summary}. Bundle ready for upload — TheoCloud emits K8s manifests internally upon deploy.`,\n )\n return Promise.resolve()\n },\n}\n"],"mappings":";;;;;;;;;AAoBO,IAAM,mBAAkC;AAAA,EAC7C,MAAM;AAAA,EAEN,MAAM,SAAqB,KAA4B;AACrD,UAAM,WAAW,aAAa,GAAG;AACjC,UAAM,YAAY,0BAA0B,QAAQ;AACpD,UAAM,UACJ,UAAU,SAAS,WAAW,IAAI,8BAA8B,UAAU,SAAS,KAAK,IAAI;AAE9F,YAAQ;AAAA,MACN,oDAAoD,OAAO,UAAU,eAAe,CAAC,cACvE,OAAO;AAAA,IACvB;AACA,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/vercel.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Vercel deploy adapter. All paths derived from `cwd` and a fixed\n * `.theo/vercel/` output layout. Build-time tool — no HTTP input.\n */\nimport { existsSync, mkdirSync, writeFileSync, cpSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport type { TheoConfig } from '../config/schema.js'\nimport { assertServicesUnsupported, readManifest } from '../services/index.js'\n\nimport { nodeAdapter } from './node.js'\nimport type { AdapterBuildContext, DeployAdapter } from './types.js'\n\n/**\n * T2.2 — Vercel adapter rewritten to consume `theokit/adapters/web-shim`\n * instead of emitting an inline plain-object Request/Response shim and\n * lazy-importing internal `theo-server/` paths.\n */\n\nexport function renderVercelFunctionEntry(): string {\n return [\n `// Generated by Theo — Vercel Functions adapter`,\n `// Environment variables are resolved at RUNTIME, not build time.`,\n ``,\n `import { randomUUID } from 'node:crypto'`,\n `import { resolve } from 'node:path'`,\n `import { scanServerRoutes, matchRoute, executeRoute, createProductionLoader } from 'theokit/server'`,\n `import { createWebShim } from 'theokit/adapters/web-shim'`,\n ``,\n `// Cold-start cache`,\n `let routesCache = null`,\n `let loaderCache = null`,\n `const serverDir = resolve(process.cwd(), 'server')`,\n ``,\n `// Vercel Functions invoke this default export with a (req, res) pair`,\n `// (Node IncomingMessage-style). We convert it to a Web Request, run the`,\n `// pipeline through the shim, and pipe the Response back.`,\n `export default async function handler(nodeReq, nodeRes) {`,\n ` const url = new URL(nodeReq.url ?? '/', 'http://' + (nodeReq.headers?.host ?? 'localhost'))`,\n ``,\n ` if (!url.pathname.startsWith('/api/')) {`,\n ` nodeRes.statusCode = 404`,\n ` nodeRes.end('Not Found')`,\n ` return`,\n ` }`,\n ``,\n ` if (!routesCache) routesCache = scanServerRoutes(serverDir)`,\n ` if (!loaderCache) loaderCache = createProductionLoader()`,\n ``,\n ` const match = matchRoute(url.pathname, routesCache)`,\n ` if (!match) {`,\n ` nodeRes.statusCode = 404`,\n ` nodeRes.setHeader('Content-Type', 'application/json')`,\n ` nodeRes.end(JSON.stringify({ error: { code: 'NOT_FOUND' } }))`,\n ` return`,\n ` }`,\n ``,\n ` // Convert Node-style req to Web Request for the shim`,\n ` const headers = new Headers()`,\n ` for (const [k, v] of Object.entries(nodeReq.headers ?? {})) {`,\n ` if (typeof v === 'string') headers.set(k, v)`,\n ` }`,\n ` let body`,\n ` const method = (nodeReq.method ?? 'GET').toUpperCase()`,\n ` if (method !== 'GET' && method !== 'HEAD') {`,\n ` const chunks = []`,\n ` await new Promise((resolveProm, rejectProm) => {`,\n ` nodeReq.on('data', (c) => chunks.push(c))`,\n ` nodeReq.on('end', () => resolveProm())`,\n ` nodeReq.on('error', rejectProm)`,\n ` })`,\n ` body = Buffer.concat(chunks)`,\n ` }`,\n ` const webRequest = new Request(url.toString(), { method, headers, body })`,\n ``,\n ` const { req, res, toResponse } = createWebShim(webRequest)`,\n ` const requestId = randomUUID()`,\n ` await executeRoute({`,\n ` route: match.route, method, params: match.params,`,\n ` req, res, loadModule: loaderCache, serverDir, requestId,`,\n ` })`,\n ` const webResponse = await toResponse()`,\n ``,\n ` nodeRes.statusCode = webResponse.status`,\n ` webResponse.headers.forEach((v, k) => nodeRes.setHeader(k, v))`,\n ` const text = await webResponse.text()`,\n ` nodeRes.end(text)`,\n `}`,\n ].join('\\n')\n}\n\nexport interface VercelRoutingRule {\n src?: string\n dest?: string\n handle?: string\n}\n\nexport function renderVercelConfigJson(): {\n version: number\n routes: VercelRoutingRule[]\n} {\n return {\n version: 3,\n routes: [\n { src: '/api/(.*)', dest: '/api' },\n { handle: 'filesystem' },\n { src: '/(.*)', dest: '/index.html' },\n ],\n }\n}\n\nexport function renderVercelVcConfigJson(): {\n runtime: string\n handler: string\n launcherType: string\n shouldAddHelpers: boolean\n} {\n return {\n runtime: 'nodejs22.x',\n handler: 'index.mjs',\n launcherType: 'Nodejs',\n shouldAddHelpers: true,\n }\n}\n\nexport const vercelAdapter: DeployAdapter = {\n name: 'vercel',\n\n async build(config: TheoConfig, cwd: string, ctx?: AdapterBuildContext): Promise<void> {\n // Wave 2 (T2.2) — reject polyglot services on this adapter.\n // Per 2026-05-27 owner decision, polyglot is wired via `node` (local\n // docker-compose harness) + `theo-cloud` (Wave 3). Vercel adapter\n // wire-up is deferred to a fresh ADR with demand evidence.\n assertServicesUnsupported('vercel', readManifest(cwd))\n\n // 1. Run the standard Node build first (ctx forwarded so nodeAdapter has makeVitePlugins)\n await nodeAdapter.build(config, cwd, ctx)\n\n const clientDir = resolve(cwd, '.theo/client')\n const outputDir = resolve(cwd, '.vercel/output')\n\n // 2. Create .vercel/output structure\n mkdirSync(resolve(outputDir, 'static'), { recursive: true })\n mkdirSync(resolve(outputDir, 'functions/api.func'), { recursive: true })\n\n // 3. Copy static assets\n if (existsSync(clientDir)) {\n cpSync(clientDir, resolve(outputDir, 'static'), { recursive: true })\n }\n\n // 4. Emit serverless function entry (now uses shared web-shim)\n writeFileSync(resolve(outputDir, 'functions/api.func/index.mjs'), renderVercelFunctionEntry())\n\n // 5. Emit .vc-config.json\n writeFileSync(\n resolve(outputDir, 'functions/api.func/.vc-config.json'),\n JSON.stringify(renderVercelVcConfigJson(), null, 2),\n )\n\n // 6. Emit config.json (routing)\n writeFileSync(\n resolve(outputDir, 'config.json'),\n JSON.stringify(renderVercelConfigJson(), null, 2),\n )\n\n // eslint-disable-next-line no-console -- CLI build progress\n console.log('\\n ✓ Vercel output → .vercel/output/\\n')\n },\n}\n"],"mappings":";;;;;;;;;;;;AAIA,SAAS,YAAY,WAAW,eAAe,cAAc;AAC7D,SAAS,eAAe;AAcjB,SAAS,4BAAoC;AAClD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAQO,SAAS,yBAGd;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ;AAAA,MACN,EAAE,KAAK,aAAa,MAAM,OAAO;AAAA,MACjC,EAAE,QAAQ,aAAa;AAAA,MACvB,EAAE,KAAK,SAAS,MAAM,cAAc;AAAA,IACtC;AAAA,EACF;AACF;AAEO,SAAS,2BAKd;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,IACT,cAAc;AAAA,IACd,kBAAkB;AAAA,EACpB;AACF;AAEO,IAAM,gBAA+B;AAAA,EAC1C,MAAM;AAAA,EAEN,MAAM,MAAM,QAAoB,KAAa,KAA0C;AAKrF,8BAA0B,UAAU,aAAa,GAAG,CAAC;AAGrD,UAAM,YAAY,MAAM,QAAQ,KAAK,GAAG;AAExC,UAAM,YAAY,QAAQ,KAAK,cAAc;AAC7C,UAAM,YAAY,QAAQ,KAAK,gBAAgB;AAG/C,cAAU,QAAQ,WAAW,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAC3D,cAAU,QAAQ,WAAW,oBAAoB,GAAG,EAAE,WAAW,KAAK,CAAC;AAGvE,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO,WAAW,QAAQ,WAAW,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAAA,IACrE;AAGA,kBAAc,QAAQ,WAAW,8BAA8B,GAAG,0BAA0B,CAAC;AAG7F;AAAA,MACE,QAAQ,WAAW,oCAAoC;AAAA,MACvD,KAAK,UAAU,yBAAyB,GAAG,MAAM,CAAC;AAAA,IACpD;AAGA;AAAA,MACE,QAAQ,WAAW,aAAa;AAAA,MAChC,KAAK,UAAU,uBAAuB,GAAG,MAAM,CAAC;AAAA,IAClD;AAGA,YAAQ,IAAI,mDAAyC;AAAA,EACvD;AACF;","names":[]}