theokit 0.74.2 → 0.74.4

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 (97) hide show
  1. package/dist/{actions-virtual-module-JV7URROJ.js → actions-virtual-module-4J7Z37Y4.js} +2 -2
  2. package/dist/{actions-virtual-module-J2HYO7QZ.js → actions-virtual-module-MIQJEHKJ.js} +2 -2
  3. package/dist/adapters/agent-mount.js +2 -2
  4. package/dist/{agent-5J7CQAYR.js → agent-QJINXU6U.js} +2 -2
  5. package/dist/{app-typed-client-XD4DZBV7.js → app-typed-client-AZMUYIYV.js} +2 -2
  6. package/dist/{app-typed-client-EOA3A2AR.js → app-typed-client-DSS23KDC.js} +2 -2
  7. package/dist/{aws-lambda-ZYSPTD3O.js → aws-lambda-K5Y6XS5V.js} +4 -4
  8. package/dist/{build-7YZSJGP2.js → build-AKN2NCFW.js} +23 -19
  9. package/dist/build-AKN2NCFW.js.map +1 -0
  10. package/dist/{bun-I7YM3RDB.js → bun-VPXMWFBA.js} +6 -4
  11. package/dist/bun-VPXMWFBA.js.map +1 -0
  12. package/dist/{chunk-SG62LZOJ.js → chunk-25OXNMVO.js} +4 -4
  13. package/dist/{chunk-QX5Q3FBJ.js → chunk-7FIK5NKN.js} +10 -10
  14. package/dist/{chunk-SHIXTMQE.js → chunk-DA3GGICE.js} +16 -2
  15. package/dist/{chunk-SHIXTMQE.js.map → chunk-DA3GGICE.js.map} +1 -1
  16. package/dist/{chunk-ZNZISJDZ.js → chunk-L4V5V2TI.js} +1 -1
  17. package/dist/{chunk-ZNZISJDZ.js.map → chunk-L4V5V2TI.js.map} +1 -1
  18. package/dist/{chunk-UFBBFP75.js → chunk-NLHAYGQQ.js} +2 -2
  19. package/dist/{chunk-X2LFNDJQ.js → chunk-NX3P5MLH.js} +2 -2
  20. package/dist/{chunk-2NG5T77O.js → chunk-R4AMIBZL.js} +16 -2
  21. package/dist/{chunk-2NG5T77O.js.map → chunk-R4AMIBZL.js.map} +1 -1
  22. package/dist/{chunk-NQZIQJFH.js → chunk-SHFZKJCU.js} +7 -7
  23. package/dist/{chunk-QAS5SKZP.js → chunk-VD3BCME6.js} +2 -2
  24. package/dist/{chunk-SZWGXHY3.js → chunk-VOXLI66L.js} +2 -2
  25. package/dist/{chunk-HK57MPSZ.js → chunk-VPK7ABMB.js} +2 -2
  26. package/dist/cli/index.js +9 -9
  27. package/dist/{cloudflare-Q5SUXRXY.js → cloudflare-PRTTYWRD.js} +3 -3
  28. package/dist/{config-support-MOZYHRWG.js → config-support-HUZ4DXR7.js} +3 -3
  29. package/dist/{deno-deploy-XW3Q6OMD.js → deno-deploy-M5V3PYWU.js} +68 -12
  30. package/dist/deno-deploy-M5V3PYWU.js.map +1 -0
  31. package/dist/{dev-FZ4OTCPT.js → dev-LMZGOV4M.js} +7 -7
  32. package/dist/index.js +3 -3
  33. package/dist/{info-SUX7QVA3.js → info-XURFOBRF.js} +4 -4
  34. package/dist/{internal-api-GKPJYL3G.js → internal-api-ATSPOXI2.js} +2 -2
  35. package/dist/{internal-api-ZUBUYGCQ.js → internal-api-XPT4GLYX.js} +2 -2
  36. package/dist/{load-config-52H3EKAA.js → load-config-2DXLI7NW.js} +4 -4
  37. package/dist/{mcp-VUHRRX36.js → mcp-4CXNOZA4.js} +3 -3
  38. package/dist/{netlify-ALPCTQFO.js → netlify-NI4HYDKN.js} +28 -9
  39. package/dist/netlify-NI4HYDKN.js.map +1 -0
  40. package/dist/node-LORYECWI.js +10 -0
  41. package/dist/{openapi-C4UX2SFV.js → openapi-UJSUQPNT.js} +4 -4
  42. package/dist/{preview-II33QNAC.js → preview-WTPUW47O.js} +3 -3
  43. package/dist/registry-SUE4HJXL.js +34 -0
  44. package/dist/{routes-3PTNISSO.js → routes-ENMU4GAN.js} +4 -4
  45. package/dist/{schema-LHNWUR4V.js → schema-DJH3IOVR.js} +3 -3
  46. package/dist/{server-boundary-QCJNECJP.js → server-boundary-JM72DQLA.js} +2 -2
  47. package/dist/{server-boundary-RTRPHX5I.js → server-boundary-K4YQXDQT.js} +2 -2
  48. package/dist/{services-typed-client-XGT5SUUN.js → services-typed-client-FOBFCRD6.js} +2 -2
  49. package/dist/{start-EREUCSN6.js → start-GAULIE5E.js} +7 -7
  50. package/dist/{static-7LP7LPGN.js → static-O2RZ5NLR.js} +3 -3
  51. package/dist/{theo-cloud-GIA67L4Q.js → theo-cloud-B4R7GCWK.js} +3 -3
  52. package/dist/{vercel-VLR52RXT.js → vercel-INHLOCSZ.js} +3 -3
  53. package/dist/vite-plugin/index.js +3 -3
  54. package/dist/{vite-plugin-3LTZJTUM.js → vite-plugin-NXWE2AVM.js} +7 -7
  55. package/package.json +3 -3
  56. package/dist/build-7YZSJGP2.js.map +0 -1
  57. package/dist/bun-I7YM3RDB.js.map +0 -1
  58. package/dist/deno-deploy-XW3Q6OMD.js.map +0 -1
  59. package/dist/netlify-ALPCTQFO.js.map +0 -1
  60. package/dist/node-4HQO6KKZ.js +0 -10
  61. package/dist/registry-WVUO2WNR.js +0 -34
  62. /package/dist/{actions-virtual-module-JV7URROJ.js.map → actions-virtual-module-4J7Z37Y4.js.map} +0 -0
  63. /package/dist/{actions-virtual-module-J2HYO7QZ.js.map → actions-virtual-module-MIQJEHKJ.js.map} +0 -0
  64. /package/dist/{agent-5J7CQAYR.js.map → agent-QJINXU6U.js.map} +0 -0
  65. /package/dist/{app-typed-client-XD4DZBV7.js.map → app-typed-client-AZMUYIYV.js.map} +0 -0
  66. /package/dist/{app-typed-client-EOA3A2AR.js.map → app-typed-client-DSS23KDC.js.map} +0 -0
  67. /package/dist/{aws-lambda-ZYSPTD3O.js.map → aws-lambda-K5Y6XS5V.js.map} +0 -0
  68. /package/dist/{chunk-SG62LZOJ.js.map → chunk-25OXNMVO.js.map} +0 -0
  69. /package/dist/{chunk-QX5Q3FBJ.js.map → chunk-7FIK5NKN.js.map} +0 -0
  70. /package/dist/{chunk-UFBBFP75.js.map → chunk-NLHAYGQQ.js.map} +0 -0
  71. /package/dist/{chunk-X2LFNDJQ.js.map → chunk-NX3P5MLH.js.map} +0 -0
  72. /package/dist/{chunk-NQZIQJFH.js.map → chunk-SHFZKJCU.js.map} +0 -0
  73. /package/dist/{chunk-QAS5SKZP.js.map → chunk-VD3BCME6.js.map} +0 -0
  74. /package/dist/{chunk-SZWGXHY3.js.map → chunk-VOXLI66L.js.map} +0 -0
  75. /package/dist/{chunk-HK57MPSZ.js.map → chunk-VPK7ABMB.js.map} +0 -0
  76. /package/dist/{cloudflare-Q5SUXRXY.js.map → cloudflare-PRTTYWRD.js.map} +0 -0
  77. /package/dist/{config-support-MOZYHRWG.js.map → config-support-HUZ4DXR7.js.map} +0 -0
  78. /package/dist/{dev-FZ4OTCPT.js.map → dev-LMZGOV4M.js.map} +0 -0
  79. /package/dist/{info-SUX7QVA3.js.map → info-XURFOBRF.js.map} +0 -0
  80. /package/dist/{internal-api-GKPJYL3G.js.map → internal-api-ATSPOXI2.js.map} +0 -0
  81. /package/dist/{internal-api-ZUBUYGCQ.js.map → internal-api-XPT4GLYX.js.map} +0 -0
  82. /package/dist/{load-config-52H3EKAA.js.map → load-config-2DXLI7NW.js.map} +0 -0
  83. /package/dist/{mcp-VUHRRX36.js.map → mcp-4CXNOZA4.js.map} +0 -0
  84. /package/dist/{node-4HQO6KKZ.js.map → node-LORYECWI.js.map} +0 -0
  85. /package/dist/{openapi-C4UX2SFV.js.map → openapi-UJSUQPNT.js.map} +0 -0
  86. /package/dist/{preview-II33QNAC.js.map → preview-WTPUW47O.js.map} +0 -0
  87. /package/dist/{registry-WVUO2WNR.js.map → registry-SUE4HJXL.js.map} +0 -0
  88. /package/dist/{routes-3PTNISSO.js.map → routes-ENMU4GAN.js.map} +0 -0
  89. /package/dist/{schema-LHNWUR4V.js.map → schema-DJH3IOVR.js.map} +0 -0
  90. /package/dist/{server-boundary-QCJNECJP.js.map → server-boundary-JM72DQLA.js.map} +0 -0
  91. /package/dist/{server-boundary-RTRPHX5I.js.map → server-boundary-K4YQXDQT.js.map} +0 -0
  92. /package/dist/{services-typed-client-XGT5SUUN.js.map → services-typed-client-FOBFCRD6.js.map} +0 -0
  93. /package/dist/{start-EREUCSN6.js.map → start-GAULIE5E.js.map} +0 -0
  94. /package/dist/{static-7LP7LPGN.js.map → static-O2RZ5NLR.js.map} +0 -0
  95. /package/dist/{theo-cloud-GIA67L4Q.js.map → theo-cloud-B4R7GCWK.js.map} +0 -0
  96. /package/dist/{vercel-VLR52RXT.js.map → vercel-INHLOCSZ.js.map} +0 -0
  97. /package/dist/{vite-plugin-3LTZJTUM.js.map → vite-plugin-NXWE2AVM.js.map} +0 -0
@@ -0,0 +1 @@
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 * `.theokit/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 type { SecurityHeadersConfig } from '../core/contracts/security-headers.js'\nimport { assertServicesUnsupported, readManifest } from '../services/index.js'\n\nimport {\n bundleDeployedFunction,\n type BundleDeployedFunctionOptions,\n} from './bundle-deployed-function.js'\nimport { deployedAgentsFragment, JSON_NOT_FOUND_RESPONSE } from './deployed-agents.js'\nimport { renderBakedRoutes, routeRuntimeLines, type BakedRoute } from './deployed-baked-routes.js'\nimport { type DeployedCorsOptions } from './deployed-cors.js'\nimport { type DeployedCsrfOptions } from './deployed-csrf.js'\nimport { deployedEntryPreamble } from './deployed-preamble.js'\nimport { deployedRateLimitFragment, rateLimitCheckFragment } from './deployed-rate-limit.js'\nimport type { DeployedRateLimitOptions } from './deployed-rate-limit.js'\nimport {\n deployedRuntimeConfigFragment,\n type DeployedRuntimeConfigOptions,\n serverDirLiteral,\n type DeployedServerDirOptions,\n} from './deployed-runtime-config.js'\nimport { deployedTraceFragment } from './deployed-trace.js'\nimport { nodeAdapter } from './node.js'\nimport { buildSecurityHeaders, describeDeployedSecurityHeaders } from './security-headers.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 class NetlifyFunctionsConflictError extends Error {\n constructor(key: string, declared: string, required: string) {\n super(\n `netlify.toml declares \\`[functions] ${key} = \"${declared}\"\\`, and this adapter needs ` +\n `\"${required}\". Measured on the Netlify emulator: \\`directory\\` is what makes the generated ` +\n `function discoverable at all (without it the redirect answers \"Function not found\"), and ` +\n `\\`node_bundler = \"none\"\\` is what stops Netlify re-bundling a function theokit already ` +\n `bundled — which produces a SyntaxError. Change the value, or remove the key and let this ` +\n `adapter write it.`,\n )\n this.name = 'NetlifyFunctionsConflictError'\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 * Seam for the bundling step, alongside `runNodeBuild` above.\n *\n * The entry cannot be written as source: it imports `theokit/server/scan` and five sibling\n * sub-paths by bare specifier, and Netlify's own bundler breaks on the result (measured on the\n * emulator — see `the-netlify-function-ships-pre-bundled.test.ts`). Bundling here rather than\n * through `writeFile` is what lets the toml then say `node_bundler = \"none\"`.\n */\n bundleFunction?: (options: BundleDeployedFunctionOptions) => Promise<void>\n}\n\nexport function renderNetlifyFunction(\n opts: { securityHeaders?: SecurityHeadersConfig } & DeployedCsrfOptions &\n DeployedRuntimeConfigOptions &\n DeployedCorsOptions &\n DeployedRateLimitOptions &\n DeployedServerDirOptions & {\n routes?: readonly BakedRoute[]\n /**\n * The agents, baked at build time — for the same reason the routes are (B-339).\n *\n * Netlify uploads a BUNDLE now, so the runtime scan cannot work here at any value: there is no\n * source tree to read, and `createProductionLoader()` would `import()` a path that was never\n * shipped. Vercel's own comment on this says it best — a fallback \"would preserve a behaviour\n * that is broken by construction: an entry that scans, finds nothing, and answers 404 while\n * looking like it tried.\"\n */\n agents?: readonly { filePath: string; agentPath: string; name: string }[]\n contextModule?: string\n } = {},\n): string {\n // B-338 — the routes are baked, not scanned. The scan was a `readdirSync` over the server directory,\n // and on the Netlify emulator it FOUND `src/server/routes/health.ts` and answered 500\n // `SyntaxError: Unexpected token ')'` — a TypeScript source a plain JS runtime cannot compile. On a real\n // deploy it finds nothing at all, because Netlify uploads the bundled function. The fix B-319 made for\n // Vercel and #369 for Cloudflare, on the fourth target; the emitter is shared and its own docblock says\n // \"the target only supplies what its own error message says\".\n const { routeImports, routeModuleEntries, routeTableEntries } = renderBakedRoutes(\n opts.routes ?? [],\n )\n const runtimeConfig = deployedRuntimeConfigFragment(opts)\n // B-235. Netlify's handler is `(request, context)` and already RECEIVES a Web `Request`, which\n // is the shape this branch needs — the item filed against it counted `new Request` occurrences\n // and concluded the opposite, measuring how the entry OBTAINS a request rather than whether it\n // has one. It used to take `scannedFromLoaderCache` with Deno as the model — same `loaderCache`,\n // same filesystem `serverDir`. That stopped being right when this target began bundling: the\n // emitted `if (!loaderCache) loaderCache = createProductionLoader()` referenced two names the\n // host no longer declared, which is a ReferenceError on the first /api/agents/<name> request and\n // is what `a-generated-entry-declares-every-identifier.test.ts` was written to catch.\n const agentsFragment = deployedAgentsFragment(\n { kind: 'baked', agents: opts.agents ?? [], contextModule: opts.contextModule },\n {\n // Netlify answers its own 404 inline rather than through a helper, so the fragment is given\n // the expression instead of a call it would have to declare.\n notFound: `new Response('Not Found', { status: 404 })`,\n },\n )\n return [\n `// Generated by Theo — Netlify Functions adapter`,\n `import { resolve } from 'node:path'`,\n `import { matchRoute, compilePattern } from 'theokit/server/scan'\\nimport { executeRoute, extractTraceIdFromRequest, TRACE_HEADER, createCorsWebHandler } from 'theokit/server/http'`,\n ...routeImports,\n `import { createWebShim } from 'theokit/adapters/web-shim'`,\n `import { buildSecurityHeaders, withSecurityHeaders } from 'theokit/adapters/security-headers'`,\n ``,\n `const cwd = process.cwd()`,\n // B-338 — was `resolve(cwd, 'server')`, a literal. A project declaring `src/server` got a function\n // scanning a directory that does not exist, and every `/api/*` answered 404 — measured on the Netlify\n // emulator. The FOURTH target with this shape: B-185 (bun, deno), B-235 (agentsDir here), B-315\n // (vercel, aws-lambda, cloudflare), and this file's own call site already names two of them.\n `const serverDir = resolve(cwd, ${serverDirLiteral(opts)})`,\n ...routeRuntimeLines(routeModuleEntries, routeTableEntries, 'netlify'),\n ``,\n `// #410 — the security baseline \\`theokit start\\` puts on every response,`,\n `// carried here as a literal because the deployed function has no`,\n `// theo.config.ts to read. The netlify.toml redirect routes only /api/* here,`,\n `// so this covers the API and not the document Netlify's static host serves`,\n `// (usetheokit/theokit#412).`,\n ...deployedEntryPreamble(runtimeConfig, agentsFragment, opts, 'netlify'),\n ``,\n // B-027 — emitted only when a limit is declared.\n ...(opts.rateLimit === undefined\n ? []\n : [\n // B-338 — the sub-path, not the umbrella. The umbrella re-exports the whole server half and\n // @swc/core's native .node addon is down that graph; the guard against it could not see this\n // adapter, because the shared comment stripper read this file's \"/*\" redirect glob as a\n // comment opener and deleted 36% of it before the sweep looked.\n `import { createRateLimiterWeb } from 'theokit/server/rate-limit'`,\n `import { resolveClientIpFromRequest } from 'theokit/server/rate-limit'`,\n ``,\n ]),\n ...deployedRateLimitFragment(\n opts.rateLimit,\n 'netlify',\n // `context.ip` is the platform's own answer, read from the handler context Netlify passes.\n // The forwarded fallback covers a function shape that carries no context, and returns\n // `undefined` unless a `trustProxy` was declared — which is the named 503, not a shared key.\n `context?.ip ?? resolveClientIpFromRequest(request, TRUST_PROXY)`,\n // Both names are bound in the OUTER handler, which is where the check runs. Threading\n // `context` into `handleRequest` — which the plan called for — buys nothing: the limiter\n // never runs in there.\n 'request, context',\n ),\n ``,\n `export default async (request, context) => {`,\n ` // #409 — the preflight is answered BEFORE anything routes: an OPTIONS the router`,\n ` // handles is an OPTIONS the browser never gets a CORS answer to.`,\n ` const preflight = corsPreflight(request)`,\n ` if (preflight !== null) return withSecurityHeaders(preflight, SECURITY_HEADERS)`,\n ...rateLimitCheckFragment(opts.rateLimit, ' ', 'request, context'),\n ` return withCors(request, withSecurityHeaders(await handleRequest(request), SECURITY_HEADERS))`,\n `}`,\n ``,\n `async function handleRequest(request) {`,\n ` const url = new URL(request.url)`,\n ` if (!url.pathname.startsWith('/api/')${agentsFragment.hostBypass}) {`,\n ` return new Response('Not Found', { status: 404 })`,\n ` }`,\n ``,\n\n ``,\n ...agentsFragment.branch,\n ``,\n ` const match = matchRoute(url.pathname, routes)`,\n ` if (!match) return ${JSON_NOT_FOUND_RESPONSE}`,\n ``,\n ` const { req, res, toResponse } = createWebShim(request)`,\n ...deployedTraceFragment('request', ' '),\n ` const method = request.method.toUpperCase()`,\n ` // #382 — the run is not awaited: toResponse() settles at the headers and`,\n ` // carries a live body, so Netlify streams while the handler writes.`,\n ` return toResponse(executeRoute({ route: match.route, method, params: match.params, req, res, loadModule, serverDir, requestId, ...CSRF_CONFIG, ${runtimeConfig.executeRouteSpread} }))`,\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\n/**\n * The `[functions]` keys this adapter requires, and why each one is not optional.\n *\n * `directory` — measured on the Netlify emulator 2026-09-29: without it the CLI scans its default\n * `netlify/functions/`, finds nothing, and `/api/*` answers `Function not found...` with a 404. The\n * adapter writes to `.netlify/functions/` deliberately (generated output belongs in an ignored\n * directory, not in the source tree the project commits), so the location has to be declared.\n *\n * `node_bundler` — the entry is already bundled here. Netlify re-bundling it produced\n * `SyntaxError: Invalid left-hand side in assignment`.\n */\nconst THEO_FUNCTIONS_DIR = '.netlify/functions'\nconst THEO_FUNCTION_NAME = 'theo'\nconst THEO_FUNCTIONS_KEYS: readonly (readonly [string, string])[] = [\n ['directory', THEO_FUNCTIONS_DIR],\n ['node_bundler', 'none'],\n]\nconst THEO_FUNCTIONS_TARGET = [\n '[functions]',\n ...THEO_FUNCTIONS_KEYS.map(([key, value]) => ` ${key} = \"${value}\"`),\n].join('\\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\n/**\n * The client router's fallback: a path that no file and no earlier rule answers gets the document.\n *\n * #949 — measured 2026-10-03 on Netlify production: `GET /about` answered 404 while the same build\n * answered 200 on Vercel and Cloudflare (whose `wrangler.toml` carries `not_found_handling =\n * \"single-page-application\"` for this). Unforced, so a real file such as `/assets/*.js` still wins,\n * and appended after `/api/*` because Netlify applies the first rule that matches.\n */\nconst THEO_SPA_FALLBACK_FROM = '/*'\nconst THEO_SPA_FALLBACK_TARGET = [\n '[[redirects]]',\n ' from = \"/*\"',\n ' to = \"/index.html\"',\n ' status = 200',\n].join('\\n')\n\n/** Append the fallback unless some `/*` rule exists — the project's own wins. */\nfunction withSpaFallback(source: string): string {\n const declared = parseRedirectBlocks(source.split(/\\r?\\n/)).some(\n (b) => b.from === THEO_SPA_FALLBACK_FROM,\n )\n if (declared) return source\n const sep = source.endsWith('\\n') ? '' : '\\n'\n return `${source}${sep}\\n${THEO_SPA_FALLBACK_TARGET}\\n`\n}\n\n/**\n * Marks the block this build owns, so it can be REGENERATED rather than merely not duplicated.\n *\n * Idempotence alone would be the wrong contract here: the block carries configuration, so a\n * `security.headers` change has to reach the file. Leaving an existing block in place — which is\n * what the redirect above correctly does, because its content is fixed — would silently pin the\n * baseline to whatever the first build emitted.\n */\nconst THEO_HEADERS_MARKER = '# Generated by Theo — security baseline (usetheokit/theokit#412)'\n\n/**\n * The `[[headers]]` block telling Netlify's static host the baseline.\n *\n * The emitted function applies these to every response IT returns, and it never returns the HTML\n * document: the `[[redirects]]` block routes only `/api/*`, so the page comes from Netlify's static\n * host and carried none of them. The values come from `buildSecurityHeaders` — the same function\n * the handler calls — rather than being written out here, because two lists of headers that must\n * agree are two lists that eventually do not.\n */\nfunction renderHeadersBlock(securityHeaders: SecurityHeadersConfig | undefined): string {\n const values = buildSecurityHeaders(securityHeaders ?? {}, { production: true })\n return [\n THEO_HEADERS_MARKER,\n '[[headers]]',\n ' for = \"/*\"',\n ' [headers.values]',\n ...Object.entries(values).map(([k, v]) => ` ${k} = ${JSON.stringify(v)}`),\n ].join('\\n')\n}\n\n/**\n * Drop a previously generated block, so the next one replaces it.\n *\n * Bounded by the marker and the next top-level section at column 0 (or EOF) — the shape TOML gives\n * a block. A user's own `[[headers]]` is untouched because it does not carry the marker: their\n * file, their rules, and Netlify applies both.\n */\nfunction withoutGeneratedHeaders(source: string): string {\n const lines = source.split(/\\r?\\n/)\n const start = lines.indexOf(THEO_HEADERS_MARKER)\n if (start < 0) return source\n\n const opensSection = (line: string | undefined): boolean => (line ?? '').startsWith('[')\n\n let end = start + 1\n while (end < lines.length && !opensSection(lines[end])) end += 1\n // The marker line itself opens the block, so `end` now sits on the NEXT section — but the block's\n // own `[[headers]]` is the first `[` after the marker, so step past it before scanning again.\n end += 1\n while (end < lines.length && !opensSection(lines[end])) end += 1\n\n return [...lines.slice(0, start), ...lines.slice(end)].join('\\n').replace(/\\n{3,}/gu, '\\n\\n')\n}\n\n/**\n * Declare the `[functions]` keys this adapter requires, without emitting a second table.\n *\n * A duplicate table is a TOML parse error, so this is not tidiness: a project that already declares\n * `[functions]` for `directory`, `included_files` or `external_node_modules` must keep it and gain\n * one key. Line-level like the rest of this merge, and for the same reason — no TOML parser\n * dependency. `[functions.\"name\"]` is a DIFFERENT table and is left alone, which is why the match\n * is exact rather than a prefix.\n *\n * An explicit conflicting value is refused rather than overwritten, on the same argument\n * `NetlifyConflictError` makes about a `/api/*` redirect pointing elsewhere: it is a deliberate\n * declaration, and silently replacing it breaks their build for a reason nothing states.\n */\n/**\n * Read a TOML scalar exactly as written, with no parser.\n *\n * Neither \"strip the quotes\" nor \"cut at the first #\" is correct alone: TOML allows an inline\n * comment after a value, and a `#` INSIDE a quoted value is legal. Stripping quotes alone read\n * `node_bundler = \"none\" # keep` as `none\" # keep` and refused a legal file; cutting at `#` alone\n * would mangle `directory = \"a#b\"`. Both cases are asserted, in both directions, in\n * `the-netlify-function-ships-pre-bundled.test.ts`.\n */\nfunction readTomlScalar(raw: string): string {\n for (const quote of ['\"', \"'\"]) {\n if (!raw.startsWith(quote)) continue\n const close = raw.indexOf(quote, 1)\n return close < 0 ? raw.slice(1) : raw.slice(1, close)\n }\n const hash = raw.indexOf('#')\n return (hash < 0 ? raw : raw.slice(0, hash)).trim()\n}\n\n/**\n * The value a key carries inside one table's line range, or `null` when the table does not set it.\n *\n * Split rather than matched: the rest of this merge is line-level by design, and a regex with `\\s*`\n * either side of a lazy group backtracks (sonarjs/slow-regex) for no gain here. A commented-out\n * `# node_bundler = …` reads as the key `# node_bundler`, which matches nothing — correct, and free.\n */\nfunction declaredIn(\n lines: readonly string[],\n from: number,\n to: number,\n key: string,\n): string | null {\n for (let i = from; i < to; i += 1) {\n const line = lines[i] ?? ''\n const eq = line.indexOf('=')\n if (eq < 0 || line.slice(0, eq).trim() !== key) continue\n return readTomlScalar(line.slice(eq + 1).trim())\n }\n return null\n}\n\nfunction withFunctionsDeclared(source: string): string {\n const lines = source.split(/\\r?\\n/)\n const at = lines.findIndex((line) => line.trimEnd() === '[functions]')\n\n if (at < 0) {\n const sep = source.endsWith('\\n') ? '' : '\\n'\n return `${source}${sep}\\n${THEO_FUNCTIONS_TARGET}\\n`\n }\n\n let end = at + 1\n while (end < lines.length && !(lines[end] ?? '').startsWith('[')) end += 1\n\n const missing: string[] = []\n for (const [key, required] of THEO_FUNCTIONS_KEYS) {\n const declared = declaredIn(lines, at + 1, end, key)\n if (declared === null) {\n missing.push(` ${key} = \"${required}\"`)\n continue\n }\n if (declared !== required) throw new NetlifyFunctionsConflictError(key, declared, required)\n }\n\n if (missing.length === 0) return source\n return [...lines.slice(0, at + 1), ...missing, ...lines.slice(at + 1)].join('\\n')\n}\n\nexport function mergeNetlifyToml(\n existing: string | null,\n securityHeaders?: SecurityHeadersConfig,\n): string {\n const headersBlock = renderHeadersBlock(securityHeaders)\n\n if (existing === null || existing.trim().length === 0) {\n return withFunctionsDeclared(withSpaFallback(`${THEO_REDIRECT_TARGET}\\n\\n${headersBlock}\\n`))\n }\n\n existing = withoutGeneratedHeaders(existing)\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 // The redirect is already there. The headers block is regenerated regardless, because it\n // carries configuration and the redirect does not.\n const sep = existing.endsWith('\\n') ? '' : '\\n'\n return withFunctionsDeclared(withSpaFallback(`${existing}${sep}\\n${headersBlock}\\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 withFunctionsDeclared(\n withSpaFallback(`${existing}${sep}\\n${THEO_REDIRECT_TARGET}\\n\\n${headersBlock}\\n`),\n )\n}\n\n/**\n * Resolve the build's effective dependencies once.\n *\n * Extracted when `buildNetlify` crossed the complexity ceiling after B-339 added a fifth seam. The\n * defaults are a separate concern from the build's sequence (SRP), and the sequence is the part a\n * reader comes here to follow.\n */\nfunction resolveNetlifyDeps(\n cwd: string,\n deps: NetlifyBuildDeps,\n): {\n runNodeBuild: NonNullable<NetlifyBuildDeps['runNodeBuild']>\n writeFile: NonNullable<NetlifyBuildDeps['writeFile']>\n ensureDir: NonNullable<NetlifyBuildDeps['ensureDir']>\n readTomlIfExists: NonNullable<NetlifyBuildDeps['readTomlIfExists']>\n bundleFunction: NonNullable<NetlifyBuildDeps['bundleFunction']>\n} {\n return {\n runNodeBuild: deps.runNodeBuild ?? nodeAdapter.build.bind(nodeAdapter),\n writeFile:\n deps.writeFile ??\n ((path, content) => {\n writeFileSync(path, content)\n }),\n ensureDir: deps.ensureDir ?? ((path: string) => mkdirSync(path, { recursive: true })),\n readTomlIfExists:\n deps.readTomlIfExists ??\n (() => {\n const path = resolve(cwd, 'netlify.toml')\n return existsSync(path) ? readFileSync(path, 'utf-8') : null\n }),\n bundleFunction: deps.bundleFunction ?? bundleDeployedFunction,\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, writeFile, ensureDir, readTomlIfExists, bundleFunction } =\n resolveNetlifyDeps(cwd, deps)\n\n const merged = mergeNetlifyToml(readTomlIfExists(), config.security?.headers)\n\n await runNodeBuild(config, cwd, ctx)\n\n const scanned = ctx?.scanRoutes?.(config.serverDir)\n\n const fnDir = resolve(cwd, THEO_FUNCTIONS_DIR)\n ensureDir(fnDir)\n // B-339 — bundled, not written as source. The entry imports `theokit/server/scan` and five\n // sibling sub-paths by bare specifier; Netlify's own bundler produced a `ReferenceError` on\n // an identifier that was base64 of the source, and re-bundled an already-bundled file into a\n // `SyntaxError`. Measured on the emulator: bundled here plus `node_bundler = \"none\"` below,\n // `GET /api/health` answers 200. Cloudflare and Vercel already bundle; this was the target\n // shipping raw source and trusting the platform to resolve it.\n await bundleFunction({\n projectRoot: cwd,\n entrySource: renderNetlifyFunction({\n routes: scanned?.routes,\n // B-339 — from the same scan as the routes, for the same reason: this target bundles, so a\n // runtime agents scan has no source tree to read.\n agents: scanned?.agents,\n contextModule: scanned?.contextModule,\n securityHeaders: config.security?.headers,\n // B-235 wired `agentsDir` through to this renderer, and B-339 made it unreadable here: the\n // agents are baked from the BUILD's scan now, so the entry never resolves a directory. An\n // option a renderer accepts and ignores is the defect `rules/foreign-config-surfaces.md` is\n // about, so it is dropped rather than left looking wired. The scan the build performs still\n // honours `config.agentsDir` — that is where the option belongs.\n // B-338 — the same pillar as the comment above, one option over. The sweep in\n // `every-deployed-entry-is-told-its-server-dir.test.ts` could not see this adapter: its\n // population was the adapters that CALL `serverDirLiteral(opts)`, so the one that never\n // adopted it was outside the population the case iterates.\n serverDir: config.serverDir,\n csrf: config.security?.csrf,\n disallowed: config.security?.disallowed,\n cors: config.security?.cors,\n // #425 — a selector, not a transformer, so it rides as a literal like the values above.\n serialization: config.serialization,\n }),\n stagePath: '.theokit/netlify/entry.mjs',\n // A DIRECTORY, not a bare file. The bundler code-splits: this project emitted `theo.mjs` plus\n // 40 chunks under `assets/`, which `theo.mjs` imports. Netlify zips a directory-shaped function\n // whole, so the chunks travel; a bare `theo.mjs` with a sibling `assets/` loads in `netlify dev`\n // (it reads from disk) and would reach a deploy without them. Vercel already uses a dedicated\n // `functions/api.func` for the same reason.\n outDir: resolve(fnDir, THEO_FUNCTION_NAME),\n entryFileName: `${THEO_FUNCTION_NAME}.mjs`,\n })\n\n writeFile(resolve(cwd, 'netlify.toml'), merged)\n\n // eslint-disable-next-line no-console -- CLI build progress\n console.log(`\\n ✓ Netlify output → ${THEO_FUNCTIONS_DIR}/${THEO_FUNCTION_NAME}/ + netlify.toml`)\n // eslint-disable-next-line no-console -- CLI build progress\n console.log(\n `${describeDeployedSecurityHeaders({\n target: 'netlify',\n securityHeaders: config.security?.headers,\n mintsNonce: false,\n documentHeaders: 'platform-configured',\n })}\\n`,\n )\n}\n\nexport const netlifyAdapter: DeployAdapter = {\n // B-339 / B-341 / B-343 — measured on the Netlify emulator. Its own bundler turned the raw\n // source into a `ReferenceError`, and re-bundled an already-bundled file into a `SyntaxError`;\n // the toml declares `node_bundler = \"none\"` so the bundle this adapter produces ships intact.\n readsSourceAtRunTime: false,\n specifiersResolvedBy: 'this-adapter',\n name: 'netlify',\n streamsResponses: true,\n // #409 / #410 — the generated entry calls `executeRoute` with routes, loader\n // and serverDir only. CSRF, route policy, file middleware and Zod validation\n // still run because they live inside `executeRoute`; none of the remaining\n // configurable concerns reach it. Declared explicitly rather than omitted so\n // the gap is a statement in the source and not an absence.\n //\n // `securityHeaders` IS applied -- to every response this function returns.\n // The document is served by Netlify's static host and does not pass through\n // it (usetheokit/theokit#412).\n appliesConfig: ['securityHeaders', 'csrf', 'disallowed', 'cors', 'serialization'],\n // B-257 — per-invocation: an in-process counter does not survive, so a declared limit needs a durable store.\n enforcesRateLimit: 'with-a-store',\n build(config, cwd, ctx) {\n return buildNetlify(config, cwd, {}, ctx)\n },\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,eAAe;AA4BjB,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAC9C,YAAY,MAAc,WAAmB;AAC3C;AAAA,MACE,6CAA6C,IAAI,aAAQ,SAAS;AAAA,IAGpE;AACA,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,gCAAN,cAA4C,MAAM;AAAA,EACvD,YAAY,KAAa,UAAkB,UAAkB;AAC3D;AAAA,MACE,uCAAuC,GAAG,OAAO,QAAQ,gCACnD,QAAQ;AAAA,IAKhB;AACA,SAAK,OAAO;AAAA,EACd;AACF;AAkBO,SAAS,sBACd,OAiBM,CAAC,GACC;AAOR,QAAM,EAAE,cAAc,oBAAoB,kBAAkB,IAAI;AAAA,IAC9D,KAAK,UAAU,CAAC;AAAA,EAClB;AACA,QAAM,gBAAgB,8BAA8B,IAAI;AASxD,QAAM,iBAAiB;AAAA,IACrB,EAAE,MAAM,SAAS,QAAQ,KAAK,UAAU,CAAC,GAAG,eAAe,KAAK,cAAc;AAAA,IAC9E;AAAA;AAAA;AAAA,MAGE,UAAU;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,kCAAkC,iBAAiB,IAAI,CAAC;AAAA,IACxD,GAAG,kBAAkB,oBAAoB,mBAAmB,SAAS;AAAA,IACrE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,sBAAsB,eAAe,gBAAgB,MAAM,SAAS;AAAA,IACvE;AAAA;AAAA,IAEA,GAAI,KAAK,cAAc,SACnB,CAAC,IACD;AAAA;AAAA;AAAA;AAAA;AAAA,MAKE;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACJ,GAAG;AAAA,MACD,KAAK;AAAA,MACL;AAAA;AAAA;AAAA;AAAA,MAIA;AAAA;AAAA;AAAA;AAAA,MAIA;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,uBAAuB,KAAK,WAAW,MAAM,kBAAkB;AAAA,IAClE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,0CAA0C,eAAe,UAAU;AAAA,IACnE;AAAA,IACA;AAAA,IACA;AAAA,IAEA;AAAA,IACA,GAAG,eAAe;AAAA,IAClB;AAAA,IACA;AAAA,IACA,wBAAwB,uBAAuB;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,GAAG,sBAAsB,WAAW,IAAI;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA,oJAAoJ,cAAc,kBAAkB;AAAA,IACpL;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,IAAM,qBAAqB;AAC3B,IAAM,mBAAmB;AAsBzB,SAAS,oBAAoB,OAAkD;AAC7E,QAAM,SAAiC,CAAC;AACxC,MAAI,UAAuC;AAE3C,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,UAAU,MAAM,CAAC,EAAE,KAAK;AAC9B,QAAI,YAAY,iBAAiB;AAC/B,UAAI,SAAS;AACX,gBAAQ,UAAU,IAAI;AACtB,eAAO,KAAK,OAAO;AAAA,MACrB;AACA,gBAAU,EAAE,WAAW,GAAG,SAAS,EAAE;AACrC;AAAA,IACF;AACA,QAAI,WAAW,eAAe,KAAK,OAAO,GAAG;AAE3C,cAAQ,UAAU,IAAI;AACtB,aAAO,KAAK,OAAO;AACnB,gBAAU;AAAA,IACZ;AACA,QAAI,SAAS;AACX,YAAM,YAAY,wBAAwB,KAAK,OAAO;AACtD,UAAI,UAAW,SAAQ,OAAO,UAAU,CAAC;AACzC,YAAM,UAAU,sBAAsB,KAAK,OAAO;AAClD,UAAI,QAAS,SAAQ,KAAK,QAAQ,CAAC;AACnC,cAAQ,UAAU;AAAA,IACpB;AAAA,EACF;AACA,MAAI,QAAS,QAAO,KAAK,OAAO;AAChC,SAAO;AACT;AAaA,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAC3B,IAAM,sBAA8D;AAAA,EAClE,CAAC,aAAa,kBAAkB;AAAA,EAChC,CAAC,gBAAgB,MAAM;AACzB;AACA,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA,GAAG,oBAAoB,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,KAAK,GAAG,OAAO,KAAK,GAAG;AACtE,EAAE,KAAK,IAAI;AAEX,IAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AAUX,IAAM,yBAAyB;AAC/B,IAAM,2BAA2B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AAGX,SAAS,gBAAgB,QAAwB;AAC/C,QAAM,WAAW,oBAAoB,OAAO,MAAM,OAAO,CAAC,EAAE;AAAA,IAC1D,CAAC,MAAM,EAAE,SAAS;AAAA,EACpB;AACA,MAAI,SAAU,QAAO;AACrB,QAAM,MAAM,OAAO,SAAS,IAAI,IAAI,KAAK;AACzC,SAAO,GAAG,MAAM,GAAG,GAAG;AAAA,EAAK,wBAAwB;AAAA;AACrD;AAUA,IAAM,sBAAsB;AAW5B,SAAS,mBAAmB,iBAA4D;AACtF,QAAM,SAAS,qBAAqB,mBAAmB,CAAC,GAAG,EAAE,YAAY,KAAK,CAAC;AAC/E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,EAAE;AAAA,EAC7E,EAAE,KAAK,IAAI;AACb;AASA,SAAS,wBAAwB,QAAwB;AACvD,QAAM,QAAQ,OAAO,MAAM,OAAO;AAClC,QAAM,QAAQ,MAAM,QAAQ,mBAAmB;AAC/C,MAAI,QAAQ,EAAG,QAAO;AAEtB,QAAM,eAAe,CAAC,UAAuC,QAAQ,IAAI,WAAW,GAAG;AAEvF,MAAI,MAAM,QAAQ;AAClB,SAAO,MAAM,MAAM,UAAU,CAAC,aAAa,MAAM,GAAG,CAAC,EAAG,QAAO;AAG/D,SAAO;AACP,SAAO,MAAM,MAAM,UAAU,CAAC,aAAa,MAAM,GAAG,CAAC,EAAG,QAAO;AAE/D,SAAO,CAAC,GAAG,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG,MAAM,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,EAAE,QAAQ,YAAY,MAAM;AAC9F;AAwBA,SAAS,eAAe,KAAqB;AAC3C,aAAW,SAAS,CAAC,KAAK,GAAG,GAAG;AAC9B,QAAI,CAAC,IAAI,WAAW,KAAK,EAAG;AAC5B,UAAM,QAAQ,IAAI,QAAQ,OAAO,CAAC;AAClC,WAAO,QAAQ,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,GAAG,KAAK;AAAA,EACtD;AACA,QAAM,OAAO,IAAI,QAAQ,GAAG;AAC5B,UAAQ,OAAO,IAAI,MAAM,IAAI,MAAM,GAAG,IAAI,GAAG,KAAK;AACpD;AASA,SAAS,WACP,OACA,MACA,IACA,KACe;AACf,WAAS,IAAI,MAAM,IAAI,IAAI,KAAK,GAAG;AACjC,UAAM,OAAO,MAAM,CAAC,KAAK;AACzB,UAAM,KAAK,KAAK,QAAQ,GAAG;AAC3B,QAAI,KAAK,KAAK,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK,MAAM,IAAK;AAChD,WAAO,eAAe,KAAK,MAAM,KAAK,CAAC,EAAE,KAAK,CAAC;AAAA,EACjD;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,QAAwB;AACrD,QAAM,QAAQ,OAAO,MAAM,OAAO;AAClC,QAAM,KAAK,MAAM,UAAU,CAAC,SAAS,KAAK,QAAQ,MAAM,aAAa;AAErE,MAAI,KAAK,GAAG;AACV,UAAM,MAAM,OAAO,SAAS,IAAI,IAAI,KAAK;AACzC,WAAO,GAAG,MAAM,GAAG,GAAG;AAAA,EAAK,qBAAqB;AAAA;AAAA,EAClD;AAEA,MAAI,MAAM,KAAK;AACf,SAAO,MAAM,MAAM,UAAU,EAAE,MAAM,GAAG,KAAK,IAAI,WAAW,GAAG,EAAG,QAAO;AAEzE,QAAM,UAAoB,CAAC;AAC3B,aAAW,CAAC,KAAK,QAAQ,KAAK,qBAAqB;AACjD,UAAM,WAAW,WAAW,OAAO,KAAK,GAAG,KAAK,GAAG;AACnD,QAAI,aAAa,MAAM;AACrB,cAAQ,KAAK,KAAK,GAAG,OAAO,QAAQ,GAAG;AACvC;AAAA,IACF;AACA,QAAI,aAAa,SAAU,OAAM,IAAI,8BAA8B,KAAK,UAAU,QAAQ;AAAA,EAC5F;AAEA,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SAAO,CAAC,GAAG,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,GAAG,SAAS,GAAG,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,KAAK,IAAI;AAClF;AAEO,SAAS,iBACd,UACA,iBACQ;AACR,QAAM,eAAe,mBAAmB,eAAe;AAEvD,MAAI,aAAa,QAAQ,SAAS,KAAK,EAAE,WAAW,GAAG;AACrD,WAAO,sBAAsB,gBAAgB,GAAG,oBAAoB;AAAA;AAAA,EAAO,YAAY;AAAA,CAAI,CAAC;AAAA,EAC9F;AAEA,aAAW,wBAAwB,QAAQ;AAE3C,QAAM,SAAS,oBAAoB,SAAS,MAAM,OAAO,CAAC;AAG1D,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAE,SAAS,mBAAoB;AACnC,QAAI,EAAE,OAAO,kBAAkB;AAG7B,YAAMA,OAAM,SAAS,SAAS,IAAI,IAAI,KAAK;AAC3C,aAAO,sBAAsB,gBAAgB,GAAG,QAAQ,GAAGA,IAAG;AAAA,EAAK,YAAY;AAAA,CAAI,CAAC;AAAA,IACtF;AACA,UAAM,IAAI,qBAAqB,EAAE,MAAM,EAAE,MAAM,WAAW;AAAA,EAC5D;AAGA,QAAM,MAAM,SAAS,SAAS,IAAI,IAAI,KAAK;AAC3C,SAAO;AAAA,IACL,gBAAgB,GAAG,QAAQ,GAAG,GAAG;AAAA,EAAK,oBAAoB;AAAA;AAAA,EAAO,YAAY;AAAA,CAAI;AAAA,EACnF;AACF;AASA,SAAS,mBACP,KACA,MAOA;AACA,SAAO;AAAA,IACL,cAAc,KAAK,gBAAgB,YAAY,MAAM,KAAK,WAAW;AAAA,IACrE,WACE,KAAK,cACJ,CAAC,MAAM,YAAY;AAClB,oBAAc,MAAM,OAAO;AAAA,IAC7B;AAAA,IACF,WAAW,KAAK,cAAc,CAAC,SAAiB,UAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AAAA,IACnF,kBACE,KAAK,qBACJ,MAAM;AACL,YAAM,OAAO,QAAQ,KAAK,cAAc;AACxC,aAAO,WAAW,IAAI,IAAI,aAAa,MAAM,OAAO,IAAI;AAAA,IAC1D;AAAA,IACF,gBAAgB,KAAK,kBAAkB;AAAA,EACzC;AACF;AAEA,eAAsB,aACpB,QACA,KACA,OAAyB,CAAC,GAC1B,KACe;AAEf,4BAA0B,WAAW,aAAa,GAAG,CAAC;AAEtD,QAAM,EAAE,cAAc,WAAW,WAAW,kBAAkB,eAAe,IAC3E,mBAAmB,KAAK,IAAI;AAE9B,QAAM,SAAS,iBAAiB,iBAAiB,GAAG,OAAO,UAAU,OAAO;AAE5E,QAAM,aAAa,QAAQ,KAAK,GAAG;AAEnC,QAAM,UAAU,KAAK,aAAa,OAAO,SAAS;AAElD,QAAM,QAAQ,QAAQ,KAAK,kBAAkB;AAC7C,YAAU,KAAK;AAOf,QAAM,eAAe;AAAA,IACnB,aAAa;AAAA,IACb,aAAa,sBAAsB;AAAA,MACjC,QAAQ,SAAS;AAAA;AAAA;AAAA,MAGjB,QAAQ,SAAS;AAAA,MACjB,eAAe,SAAS;AAAA,MACxB,iBAAiB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUlC,WAAW,OAAO;AAAA,MAClB,MAAM,OAAO,UAAU;AAAA,MACvB,YAAY,OAAO,UAAU;AAAA,MAC7B,MAAM,OAAO,UAAU;AAAA;AAAA,MAEvB,eAAe,OAAO;AAAA,IACxB,CAAC;AAAA,IACD,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMX,QAAQ,QAAQ,OAAO,kBAAkB;AAAA,IACzC,eAAe,GAAG,kBAAkB;AAAA,EACtC,CAAC;AAED,YAAU,QAAQ,KAAK,cAAc,GAAG,MAAM;AAG9C,UAAQ,IAAI;AAAA,iCAA0B,kBAAkB,IAAI,kBAAkB,kBAAkB;AAEhG,UAAQ;AAAA,IACN,GAAG,gCAAgC;AAAA,MACjC,QAAQ;AAAA,MACR,iBAAiB,OAAO,UAAU;AAAA,MAClC,YAAY;AAAA,MACZ,iBAAiB;AAAA,IACnB,CAAC,CAAC;AAAA;AAAA,EACJ;AACF;AAEO,IAAM,iBAAgC;AAAA;AAAA;AAAA;AAAA,EAI3C,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,MAAM;AAAA,EACN,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUlB,eAAe,CAAC,mBAAmB,QAAQ,cAAc,QAAQ,eAAe;AAAA;AAAA,EAEhF,mBAAmB;AAAA,EACnB,MAAM,QAAQ,KAAK,KAAK;AACtB,WAAO,aAAa,QAAQ,KAAK,CAAC,GAAG,GAAG;AAAA,EAC1C;AACF;","names":["sep"]}
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import "tsx/esm";
3
+ import {
4
+ nodeAdapter
5
+ } from "./chunk-NLHAYGQQ.js";
6
+ import "./chunk-L4V5V2TI.js";
7
+ export {
8
+ nodeAdapter
9
+ };
10
+ //# sourceMappingURL=node-LORYECWI.js.map
@@ -12,11 +12,11 @@ import "./chunk-4WP7A7RX.js";
12
12
  import "./chunk-Z7CJHDLS.js";
13
13
  import {
14
14
  loadConfig
15
- } from "./chunk-SZWGXHY3.js";
15
+ } from "./chunk-VOXLI66L.js";
16
16
  import "./chunk-3QPVEJ7D.js";
17
17
  import "./chunk-U5PWXS3J.js";
18
- import "./chunk-X2LFNDJQ.js";
19
- import "./chunk-ZNZISJDZ.js";
18
+ import "./chunk-NX3P5MLH.js";
19
+ import "./chunk-L4V5V2TI.js";
20
20
  import "./chunk-D2R5SJEL.js";
21
21
 
22
22
  // src/cli/commands/openapi.ts
@@ -84,4 +84,4 @@ function emitOpenApiInMemory(manifest, config) {
84
84
  export {
85
85
  openapiCommand
86
86
  };
87
- //# sourceMappingURL=openapi-C4UX2SFV.js.map
87
+ //# sourceMappingURL=openapi-UJSUQPNT.js.map
@@ -4,8 +4,8 @@ import "tsx/esm";
4
4
  // src/cli/commands/preview.ts
5
5
  async function defaultSteps() {
6
6
  const [{ buildCommand }, { startCommand }] = await Promise.all([
7
- import("./build-7YZSJGP2.js"),
8
- import("./start-EREUCSN6.js")
7
+ import("./build-AKN2NCFW.js"),
8
+ import("./start-GAULIE5E.js")
9
9
  ]);
10
10
  return {
11
11
  build: (opts) => buildCommand(opts),
@@ -20,4 +20,4 @@ async function previewCommand(options = {}, steps) {
20
20
  export {
21
21
  previewCommand
22
22
  };
23
- //# sourceMappingURL=preview-II33QNAC.js.map
23
+ //# sourceMappingURL=preview-WTPUW47O.js.map
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ import "tsx/esm";
3
+ import {
4
+ VALID_TARGETS
5
+ } from "./chunk-4X43VTST.js";
6
+
7
+ // src/adapters/registry.ts
8
+ var adapterRegistry = {
9
+ node: async () => (await import("./node-LORYECWI.js")).nodeAdapter,
10
+ vercel: async () => (await import("./vercel-INHLOCSZ.js")).vercelAdapter,
11
+ cloudflare: async () => (await import("./cloudflare-PRTTYWRD.js")).cloudflareAdapter,
12
+ static: async () => (await import("./static-O2RZ5NLR.js")).staticAdapter,
13
+ bun: async () => (await import("./bun-VPXMWFBA.js")).bunAdapter,
14
+ "deno-deploy": async () => (await import("./deno-deploy-M5V3PYWU.js")).denoDeployAdapter,
15
+ netlify: async () => (await import("./netlify-NI4HYDKN.js")).netlifyAdapter,
16
+ "aws-lambda": async () => (await import("./aws-lambda-K5Y6XS5V.js")).awsLambdaAdapter,
17
+ "theo-cloud": async () => (await import("./theo-cloud-B4R7GCWK.js")).theoCloudAdapter
18
+ };
19
+ async function resolveAdapter(target) {
20
+ const factory = adapterRegistry[target];
21
+ return factory();
22
+ }
23
+ async function streamingTargets() {
24
+ const out = [];
25
+ for (const target of VALID_TARGETS) {
26
+ if ((await resolveAdapter(target)).streamsResponses === true) out.push(target);
27
+ }
28
+ return out;
29
+ }
30
+ export {
31
+ resolveAdapter,
32
+ streamingTargets
33
+ };
34
+ //# sourceMappingURL=registry-SUE4HJXL.js.map
@@ -11,11 +11,11 @@ import {
11
11
  import "./chunk-Z7CJHDLS.js";
12
12
  import {
13
13
  loadConfig
14
- } from "./chunk-SZWGXHY3.js";
14
+ } from "./chunk-VOXLI66L.js";
15
15
  import "./chunk-3QPVEJ7D.js";
16
16
  import "./chunk-U5PWXS3J.js";
17
- import "./chunk-X2LFNDJQ.js";
18
- import "./chunk-ZNZISJDZ.js";
17
+ import "./chunk-NX3P5MLH.js";
18
+ import "./chunk-L4V5V2TI.js";
19
19
  import "./chunk-D2R5SJEL.js";
20
20
 
21
21
  // src/cli/commands/routes.ts
@@ -64,4 +64,4 @@ async function routesCommand() {
64
64
  export {
65
65
  routesCommand
66
66
  };
67
- //# sourceMappingURL=routes-3PTNISSO.js.map
67
+ //# sourceMappingURL=routes-ENMU4GAN.js.map
@@ -2,8 +2,8 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  theoConfigSchema
5
- } from "./chunk-X2LFNDJQ.js";
6
- import "./chunk-ZNZISJDZ.js";
5
+ } from "./chunk-NX3P5MLH.js";
6
+ import "./chunk-L4V5V2TI.js";
7
7
  import {
8
8
  cacheSchema,
9
9
  corsSchema,
@@ -17,4 +17,4 @@ export {
17
17
  storageSchema,
18
18
  theoConfigSchema
19
19
  };
20
- //# sourceMappingURL=schema-LHNWUR4V.js.map
20
+ //# sourceMappingURL=schema-DJH3IOVR.js.map
@@ -3,7 +3,7 @@ import "tsx/esm";
3
3
  import {
4
4
  resolveTheoRootDir
5
5
  } from "./chunk-FDOOBTXJ.js";
6
- import "./chunk-SHIXTMQE.js";
6
+ import "./chunk-DA3GGICE.js";
7
7
  import "./chunk-BINRCILF.js";
8
8
  import "./chunk-FNJVSFEC.js";
9
9
  import "./chunk-WSMLSIS5.js";
@@ -131,4 +131,4 @@ export {
131
131
  ServerOnlyImportError,
132
132
  serverOnlyImportBoundary
133
133
  };
134
- //# sourceMappingURL=server-boundary-QCJNECJP.js.map
134
+ //# sourceMappingURL=server-boundary-JM72DQLA.js.map
@@ -2,7 +2,7 @@ import {
2
2
  resolveTheoRootDir
3
3
  } from "./chunk-7NRFZBAL.js";
4
4
  import "./chunk-D7STTNQN.js";
5
- import "./chunk-2NG5T77O.js";
5
+ import "./chunk-R4AMIBZL.js";
6
6
  import "./chunk-WSOAN4KN.js";
7
7
  import "./chunk-ENSFCKP6.js";
8
8
  import "./chunk-2Z7TANA4.js";
@@ -147,4 +147,4 @@ export {
147
147
  ServerOnlyImportError,
148
148
  serverOnlyImportBoundary
149
149
  };
150
- //# sourceMappingURL=server-boundary-RTRPHX5I.js.map
150
+ //# sourceMappingURL=server-boundary-K4YQXDQT.js.map
@@ -2,7 +2,7 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  generateTypedClient
5
- } from "./chunk-ZNZISJDZ.js";
5
+ } from "./chunk-L4V5V2TI.js";
6
6
 
7
7
  // src/vite-plugin/services-typed-client.ts
8
8
  import { resolve } from "path";
@@ -44,4 +44,4 @@ function servicesTypedClientPlugin(opts) {
44
44
  export {
45
45
  servicesTypedClientPlugin
46
46
  };
47
- //# sourceMappingURL=services-typed-client-XGT5SUUN.js.map
47
+ //# sourceMappingURL=services-typed-client-FOBFCRD6.js.map
@@ -29,7 +29,7 @@ import {
29
29
  resolveTransformer,
30
30
  serveMatchedAuxRoute,
31
31
  serveThroughPluginLifecycle
32
- } from "./chunk-QAS5SKZP.js";
32
+ } from "./chunk-VD3BCME6.js";
33
33
  import "./chunk-BDH5GKFZ.js";
34
34
  import {
35
35
  findRootDiv
@@ -45,7 +45,7 @@ import {
45
45
  mountAgent,
46
46
  readAgentPolicy,
47
47
  writeWebResponseToServerResponse
48
- } from "./chunk-SHIXTMQE.js";
48
+ } from "./chunk-DA3GGICE.js";
49
49
  import {
50
50
  getApprovalRegistry,
51
51
  resolveProvider
@@ -85,13 +85,13 @@ import {
85
85
  import "./chunk-Z7CJHDLS.js";
86
86
  import {
87
87
  loadConfig
88
- } from "./chunk-SZWGXHY3.js";
88
+ } from "./chunk-VOXLI66L.js";
89
89
  import {
90
90
  loadEnv
91
91
  } from "./chunk-3QPVEJ7D.js";
92
92
  import "./chunk-U5PWXS3J.js";
93
- import "./chunk-X2LFNDJQ.js";
94
- import "./chunk-ZNZISJDZ.js";
93
+ import "./chunk-NX3P5MLH.js";
94
+ import "./chunk-L4V5V2TI.js";
95
95
  import "./chunk-D2R5SJEL.js";
96
96
  import "./chunk-VQIUTCK2.js";
97
97
 
@@ -436,7 +436,7 @@ async function configureStorageManagerFromConfig(storageConfig) {
436
436
  if (storageConfig === void 0 || storageConfig === null) return;
437
437
  try {
438
438
  const { getStorageManager } = await import("./storage-manager-3O5PDO6O.js");
439
- const { storageSchema } = await import("./schema-LHNWUR4V.js");
439
+ const { storageSchema } = await import("./schema-DJH3IOVR.js");
440
440
  const parsed = storageSchema.parse(storageConfig);
441
441
  getStorageManager().configure(parsed);
442
442
  } catch (err) {
@@ -1431,4 +1431,4 @@ export {
1431
1431
  resolveSsrEntry,
1432
1432
  startCommand
1433
1433
  };
1434
- //# sourceMappingURL=start-EREUCSN6.js.map
1434
+ //# sourceMappingURL=start-GAULIE5E.js.map
@@ -2,7 +2,7 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  nodeAdapter
5
- } from "./chunk-UFBBFP75.js";
5
+ } from "./chunk-NLHAYGQQ.js";
6
6
  import {
7
7
  findRootDiv
8
8
  } from "./chunk-3PWQQWT6.js";
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  assertServicesUnsupported,
14
14
  readManifest
15
- } from "./chunk-ZNZISJDZ.js";
15
+ } from "./chunk-L4V5V2TI.js";
16
16
 
17
17
  // src/adapters/static.ts
18
18
  import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
@@ -247,4 +247,4 @@ export {
247
247
  detectApiRoutes,
248
248
  staticAdapter
249
249
  };
250
- //# sourceMappingURL=static-7LP7LPGN.js.map
250
+ //# sourceMappingURL=static-O2RZ5NLR.js.map
@@ -2,11 +2,11 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  nodeAdapter
5
- } from "./chunk-UFBBFP75.js";
5
+ } from "./chunk-NLHAYGQQ.js";
6
6
  import {
7
7
  prepareTheoCloudArtifacts,
8
8
  readManifest
9
- } from "./chunk-ZNZISJDZ.js";
9
+ } from "./chunk-L4V5V2TI.js";
10
10
 
11
11
  // src/adapters/theo-cloud.ts
12
12
  async function buildTheoCloud(config, cwd, deps = {}, ctx) {
@@ -37,4 +37,4 @@ export {
37
37
  buildTheoCloud,
38
38
  theoCloudAdapter
39
39
  };
40
- //# sourceMappingURL=theo-cloud-GIA67L4Q.js.map
40
+ //# sourceMappingURL=theo-cloud-B4R7GCWK.js.map
@@ -25,7 +25,7 @@ import {
25
25
  } from "./chunk-EQJF2EH5.js";
26
26
  import {
27
27
  nodeAdapter
28
- } from "./chunk-UFBBFP75.js";
28
+ } from "./chunk-NLHAYGQQ.js";
29
29
  import "./chunk-3PWQQWT6.js";
30
30
  import {
31
31
  buildSecurityHeaders
@@ -33,7 +33,7 @@ import {
33
33
  import {
34
34
  assertServicesUnsupported,
35
35
  readManifest
36
- } from "./chunk-ZNZISJDZ.js";
36
+ } from "./chunk-L4V5V2TI.js";
37
37
 
38
38
  // src/adapters/vercel.ts
39
39
  import { existsSync, mkdirSync, writeFileSync, cpSync } from "fs";
@@ -437,4 +437,4 @@ export {
437
437
  shouldCopyIntoStatic,
438
438
  vercelAdapter
439
439
  };
440
- //# sourceMappingURL=vercel-VLR52RXT.js.map
440
+ //# sourceMappingURL=vercel-INHLOCSZ.js.map
@@ -6,12 +6,12 @@ import {
6
6
  defineTheoIntegration,
7
7
  theoPlugin,
8
8
  theoPluginAsync
9
- } from "../chunk-NQZIQJFH.js";
9
+ } from "../chunk-SHFZKJCU.js";
10
10
  import "../chunk-7NRFZBAL.js";
11
11
  import "../chunk-SSYDEKWF.js";
12
12
  import "../chunk-D7STTNQN.js";
13
- import "../chunk-HK57MPSZ.js";
14
- import "../chunk-2NG5T77O.js";
13
+ import "../chunk-VPK7ABMB.js";
14
+ import "../chunk-R4AMIBZL.js";
15
15
  import "../chunk-OIGJOYX6.js";
16
16
  import "../chunk-U3SPBLJF.js";
17
17
  import "../chunk-WSOAN4KN.js";
@@ -8,12 +8,12 @@ import {
8
8
  defineTheoIntegration,
9
9
  theoPlugin,
10
10
  theoPluginAsync
11
- } from "./chunk-QX5Q3FBJ.js";
12
- import "./chunk-QAS5SKZP.js";
11
+ } from "./chunk-7FIK5NKN.js";
12
+ import "./chunk-VD3BCME6.js";
13
13
  import "./chunk-BDH5GKFZ.js";
14
14
  import "./chunk-3PWQQWT6.js";
15
15
  import "./chunk-FDOOBTXJ.js";
16
- import "./chunk-SHIXTMQE.js";
16
+ import "./chunk-DA3GGICE.js";
17
17
  import "./chunk-BINRCILF.js";
18
18
  import "./chunk-FNJVSFEC.js";
19
19
  import "./chunk-WSMLSIS5.js";
@@ -25,11 +25,11 @@ import "./chunk-WR5B2XNT.js";
25
25
  import "./chunk-HKF6YNY4.js";
26
26
  import "./chunk-4WP7A7RX.js";
27
27
  import "./chunk-Z7CJHDLS.js";
28
- import "./chunk-SZWGXHY3.js";
28
+ import "./chunk-VOXLI66L.js";
29
29
  import "./chunk-3QPVEJ7D.js";
30
30
  import "./chunk-U5PWXS3J.js";
31
- import "./chunk-X2LFNDJQ.js";
32
- import "./chunk-ZNZISJDZ.js";
31
+ import "./chunk-NX3P5MLH.js";
32
+ import "./chunk-L4V5V2TI.js";
33
33
  import "./chunk-D2R5SJEL.js";
34
34
  import "./chunk-5ODOE6EF.js";
35
35
  import "./chunk-VQIUTCK2.js";
@@ -42,4 +42,4 @@ export {
42
42
  theoPlugin,
43
43
  theoPluginAsync
44
44
  };
45
- //# sourceMappingURL=vite-plugin-3LTZJTUM.js.map
45
+ //# sourceMappingURL=vite-plugin-NXWE2AVM.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "theokit",
3
- "version": "0.74.2",
3
+ "version": "0.74.4",
4
4
  "description": "The TheoKit web framework — file-based routing, typed server surfaces, the Vite plugin, the CLI and the deploy adapters, around agents served from agents/*.ts.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -151,8 +151,8 @@
151
151
  "typescript": "^5.9.3",
152
152
  "vite": "^7.0.0",
153
153
  "@theokit/agents": "^15.0.2",
154
- "@theokit/presenter": "^0.10.0",
155
- "@theokit/http": "^2.3.0"
154
+ "@theokit/http": "^2.3.0",
155
+ "@theokit/presenter": "^0.10.0"
156
156
  },
157
157
  "peerDependencies": {
158
158
  "@theokit/sdk": "^5.9.2",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/commands/build.ts","../src/server/cron/adapter-translators.ts","../src/server/_internal/atomic-write.ts","../src/server/cron/cron-manifest.ts","../src/server/cron/cron-scan.ts","../src/server/jobs/job-manifest.ts","../src/server/jobs/job-scan.ts","../src/cli/cleanup/cleanup.ts","../src/cli/commands/build-scan-routes.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\n// T1.1 (architecture-medium-deferrals) — nodeAdapter no longer static-imported.\n// All adapters dispatch via `adapterRegistry` (lazy-imported within runAdapterBuild).\nimport {\n VALID_TARGETS,\n targetRendersDocument,\n type BuildTarget,\n type AdapterBuildContext,\n type DeployAdapter,\n} from '../../adapters/types.js'\nimport { loadConfig } from '../../config/load-config.js'\nimport { loadEnv } from '../../config/load-env.js'\nimport { validateProjectStructure } from '../../config/validate-structure.js'\nimport {\n ExistingConfigUnparseableError,\n translateCronToAws,\n translateCronToCloudflare,\n translateCronToDeno,\n translateCronToVercel,\n} from '../../server/cron/adapter-translators.js'\nimport { writeCronManifest } from '../../server/cron/cron-manifest.js'\nimport { scanCronDirs } from '../../server/cron/cron-scan.js'\nimport { writeJobManifest } from '../../server/jobs/job-manifest.js'\nimport { scanJobs } from '../../server/jobs/job-scan.js'\nimport { generateManifest, writeManifest } from '../../server/scan/manifest.js'\nimport {\n buildManifest as buildServicesManifest,\n writeManifest as writeServicesManifest,\n} from '../../services/index.js'\n// G2 T2.2 — OpenAPI emit. Opt-in via `config.openapi`. Dual output:\n// 1. <distDir>/openapi.json (pre-Vite, dev surface + manifests sibling)\n// 2. dist/openapi.json (post-Vite, build artifact)\n// The dist emit awaits runAdapterBuild — if Vite fails, the second emit\n// never runs (EC-2 absorbed: no stale dist artifact).\nimport { emitOpenApi } from '../../vite-plugin/openapi-emit/emit.js'\nimport { loadRoutesForOpenApi } from '../../vite-plugin/openapi-emit/load-routes.js'\nimport { cleanOutDir } from '../cleanup/cleanup.js'\nimport { preflightNodeAndBindings } from '../preflight-node-version.js'\n\nimport { describeControllerArtifacts, emitControllerArtifacts } from './build/emit-controllers.js'\nimport { createBuildScanRoutes } from './build-scan-routes.js'\n\n// Adapters that do NOT support cron triggers natively. Build still\n// succeeds with crons declared, but emits a warning + skip note.\nconst CRON_NA_TARGETS = new Set<BuildTarget>(['bun', 'netlify', 'static'])\n\n// DERIVED, never restated. A hand-written list here went stale and told users\n// that three working targets were unsupported: it named node/vercel/cloudflare\n// while aws-lambda, deno-deploy and theo-cloud also translate crons. Deriving\n// from the two constants means adding a target cannot desynchronise the message.\nconst CRON_SUPPORTED_TARGETS = VALID_TARGETS.filter((t) => !CRON_NA_TARGETS.has(t))\n\nexport async function buildCommand(options?: { target?: string }): Promise<void> {\n const cwd = process.cwd()\n // Preflight (FIRST — BEFORE anything that touches native bindings).\n preflightNodeAndBindings(cwd)\n // Phase 1 (T1.2) — Load .env BEFORE config load.\n loadEnv({ cwd, mode: 'production' })\n\n const config = await loadConfig(cwd)\n // #95 — honor config.appDir so a custom frontend dir (e.g. apps/web) passes the structure gate.\n validateProjectStructure(cwd, config.appDir)\n\n // B-336 — EVERY refusal that is decidable from the target and the config alone runs BEFORE the\n // clean. `cleanOutDir` used to sit here, above even the check that the target EXISTS: measured on a\n // real project, `theokit build --target nao-existe` destroyed 302 files in `.theokit/client/assets`\n // and answered with a message about the typo. The comment above\n // `assertRateLimitEnforceable` already stated this intent in its own words — \"refused by name,\n // BEFORE the build writes anything\" — and the order defeated it.\n const target = (options?.target ?? 'node') as BuildTarget\n\n if (!VALID_TARGETS.includes(target)) {\n throw new Error(\n `Invalid build target \"${target}\". Available targets: ${VALID_TARGETS.join(', ')}`,\n )\n }\n\n const { resolveAdapter, streamingTargets } = await import('../../adapters/registry.js')\n const adapter = await resolveAdapter(target)\n const { assertRateLimitEnforceable, assertStreamingSupported } =\n await import('../../adapters/config-support.js')\n\n // #461 — a dropped `cors` degrades where someone can see it; a dropped RATE LIMIT looks exactly like\n // success until the abuse it was meant to stop. Refused by name, and now genuinely before anything is\n // written or destroyed.\n assertRateLimitEnforceable(config, adapter, target)\n assertStreamingSupported(config, adapter, target, await streamingTargets())\n\n // T2.2 — Clean .theokit/ at build start (Astro pattern). Skip .git*.\n const distDirAbs = resolve(cwd, config.distDir)\n await cleanOutDir({ dir: distDirAbs })\n\n // EC-201 — cross-reference note when config.adapters[] diverges from\n // the --target flag. --target is authoritative per ADR D2.\n const configAdapters = (config as { adapters?: readonly string[] }).adapters\n if (configAdapters && configAdapters.length > 0) {\n const otherAdapters = configAdapters.filter((a) => a !== target)\n if (otherAdapters.length > 0) {\n console.log(\n `\\n Note: theo.config.ts.adapters lists [${otherAdapters.join(', ')}]; ` +\n `this build translates for ${target} only. ` +\n `Run \\`theokit build --target=<adapter>\\` separately for each (cross-reference).`,\n )\n }\n }\n\n console.log(`\\n Building for ${target}...\\n`)\n\n // Manifests emit BEFORE adapter bundling (Vite). Why: manifests are\n // fast + deterministic + don't depend on Vite. If Vite fails (missing\n // dep, malformed entry), the user still gets manifests for diagnostics.\n const serverDir = resolve(cwd, config.serverDir)\n const distDir = distDirAbs\n // #95 follow-up — pass projectRoot (cwd) + config.agentsDir so agents scan honors a custom dir.\n const manifest = generateManifest(serverDir, cwd, config.agentsDir)\n writeManifest(manifest, distDir)\n\n const totalEndpoints =\n manifest.routes.length + manifest.actions.length + manifest.websockets.length\n console.log(\n ` ✓ Manifest: ${manifest.routes.length} routes, ${manifest.actions.length} actions, ${manifest.websockets.length} ws (${totalEndpoints} total)`,\n )\n\n // T1.1 — cron scan + manifest + per-target adapter translation\n await emitCronArtifacts({ cwd, serverDir, agentsDir: config.agentsDir, distDir, target })\n\n // T1.2 — job scan + manifest (no per-target translation needed)\n await emitJobArtifacts({ cwd, serverDir, distDir })\n\n // theokit#123 — compile `server/controllers/**` so `theokit start` can serve them.\n //\n // #122 made controllers first-class in dev, where Vite's swc transform compiles them on the fly.\n // Production has neither, so an uncompiled `.controller.ts` cannot load and its routes 404'd —\n // working in dev and failing in prod, which is the worst place for a gap to live.\n //\n // Deliberately NOT folded into `generateManifest` (ADR-5): the manifest is the deploy-adapter\n // contract, and a parallel route source in it would ripple through every adapter. This writes a\n // separate artifact only the Node start path reads. No controllers ⇒ no artifact at all.\n const controllerManifest = await emitControllerArtifacts({ serverDir, distDir })\n if (controllerManifest !== null) {\n console.log(` ${describeControllerArtifacts(controllerManifest)}`)\n }\n\n // Wave 2 (T1.2) — services manifest at <cwd>/.theokit/services.json. Always\n // emit (empty array when services: {} is empty) so adapters can rely on\n // the file existing. Topological order preserved by buildServicesManifest.\n //\n // Plan v1.2 T2.1 — when theo.config.ts declares `name`, emit services.json\n // v2 with that project identifier. Falling back to v1 (no project field)\n // keeps TheoCloud's deprecation warning path intact (services-bundle).\n const projectName = config.name\n const servicesManifest = buildServicesManifest(config.services, projectName)\n writeServicesManifest(cwd, servicesManifest)\n if (servicesManifest.services.length > 0) {\n const versionLabel = `v${String(servicesManifest.version)}`\n const projectLabel =\n servicesManifest.version === 2 ? ` project=\"${servicesManifest.project}\"` : ''\n console.log(\n ` ✓ Services manifest (${versionLabel}${projectLabel}): ${String(servicesManifest.services.length)} service(s) ` +\n `(${servicesManifest.services.map((s) => s.name).join(', ')})`,\n )\n } else if (servicesManifest.version === 1) {\n console.log(\n ' ⚠ services.json emitted as v1 (no `name` in theo.config.ts). ' +\n 'TheoCloud will accept this with a deprecation warning; sunset in theokit 0.6.0. ' +\n 'Run `theokit migrate services-json-v1-to-v2` to upgrade.',\n )\n }\n\n // G2 T2.2 — OpenAPI dev-surface emit (pre-Vite, sibling of manifests).\n // Opt-in: only when config.openapi is defined. Best-effort: a route load\n // failure produces a warning, not a build abort.\n if (config.openapi !== undefined) {\n const hydrated = await loadRoutesForOpenApi({ serverDir, routes: manifest.routes })\n const devResult = emitOpenApi({\n manifest: hydrated,\n config: { ...config.openapi, outDir: distDir },\n })\n console.log(` ✓ OpenAPI: ${String(hydrated.length)} ops → ${devResult.path}`)\n }\n\n // Now run the adapter-specific bundling (Vite + adapter-specific work).\n await runAdapterBuild(target, config, cwd, adapter)\n\n // G2 T2.2 — OpenAPI build-artifact emit (post-Vite, EC-2 gated on success).\n // If runAdapterBuild threw, execution never reaches this point — no stale\n // dist/openapi.json is written.\n if (config.openapi !== undefined) {\n const distOut = resolve(cwd, 'dist')\n const hydrated = await loadRoutesForOpenApi({ serverDir, routes: manifest.routes })\n const distResult = emitOpenApi({\n manifest: hydrated,\n config: { ...config.openapi, outDir: distOut },\n })\n console.log(` ✓ OpenAPI (dist): ${distResult.path}`)\n }\n\n // Derived, not asserted. This read `config.ssr` alone, so a target whose entry delegates the\n // document to a static host was announced as server-rendering — measured on `--target bun`, which\n // printed `(SSR)` and served an empty `<div id=\"root\">` (B-334).\n const ssrNote = config.ssr && targetRendersDocument(target) ? ' (SSR)' : ''\n console.log(`\\n ✓ Build complete → ${target}${ssrNote}\\n`)\n}\n\nasync function runAdapterBuild(\n target: BuildTarget,\n config: Awaited<ReturnType<typeof loadConfig>>,\n cwd: string,\n // Resolved by the caller, which needs it before `cleanOutDir` to run the refusals (B-336). Passing it\n // in rather than resolving again keeps one answer to \"which adapter is this build\".\n adapter: DeployAdapter,\n): Promise<void> {\n // T1.1 (architecture-cleanup) — CLI composes the Vite Plugin[] and INJECTS it into\n // the adapter via ctx.makeVitePlugins. This inverts the previous `adapters → vite-plugin`\n // edge — adapters no longer import from vite-plugin/ directly.\n //\n // theoPlugin AND `@vitejs/plugin-react` are dynamically imported so the deps are\n // materialized only when needed (adapter is `node`). This keeps the CLI's startup\n // path independent of optional build-time deps (so e.g. `theokit build --target=static`\n // does not need react installed). dep-cruiser's per-module rule allows `cli → vite-plugin`.\n //\n // 0.2.2 regression fix: switched sync `theoPlugin()` → `theoPluginAsync()` so the\n // returned Plugin[] includes the @theo/actions virtual module + typed-client +\n // services + @theokit/ui auto-chain. Without async, build-time Rollup couldn't\n // resolve `@theo/actions` even though dev-time Vite (which already used async)\n // could. See https://github.com/usetheo/theokit/commits — 0.2.2 changelog.\n const { theoPluginAsync } = await import('../../vite-plugin/index.js')\n const { default: react } = await import('@vitejs/plugin-react')\n const ctx: AdapterBuildContext = {\n // `react()` may return Plugin or Plugin[] depending on version; spread the\n // async chain so the contract returns a flat Plugin[] (AdapterBuildContext\n // type updated to `Plugin[] | Promise<Plugin[]>`).\n // #95 — inject the config dirs so the client build's router/entry + typed-client codegen honor\n // custom appDir/serverDir/agentsDir (e.g. \"apps/web\" / \"core\" / \"core/agents\").\n makeVitePlugins: async (opts) =>\n [\n react(),\n ...(await theoPluginAsync({\n ...opts,\n appDir: config.appDir,\n serverDir: config.serverDir,\n agentsDir: config.agentsDir,\n })),\n ].flat(),\n\n // #369 — the same inversion, for the same reason. A Worker has no filesystem, so the Cloudflare\n // entry bakes its routes at build time; importing the scanner from `adapters/` would add the\n // `adapters → server` edge that `adapters-may-only-depend-on-core-router-services` refuses. The\n // CLI already imports both sides, so it composes the scan and hands over the result.\n //\n // A module rather than a closure since B-312: the wrong argument it carried was unreachable from\n // any test while it lived in here, because reaching it meant running the whole build.\n scanRoutes: createBuildScanRoutes(cwd, config),\n }\n\n // T1.1 (architecture-medium-deferrals, ADR D1) — Adapter Registry replaces\n // the previous 9-case switch. New adapters add 1 line in `adapters/registry.ts`;\n // CLI is closed for modification (OCP).\n // #409 / #410 — a config key that validates and is then never read makes the\n // deployed app behave as if the operator had not written it, with nothing\n // anywhere saying so. Name it before the build output scrolls past.\n const { warnUnappliedConfig } = await import('../../adapters/config-support.js')\n\n // #461 / #321 / #322 — the rate-limit refusal moved to `buildCommand`, above `cleanOutDir`, because\n // this position made its own comment false: it claimed the combination was refused \"BEFORE the build\n // writes anything\" and it is reached a hundred lines after the output has been emptied (B-336).\n\n warnUnappliedConfig(config, adapter, target, (message) => {\n console.log(message)\n })\n\n await adapter.build(config, cwd, ctx)\n}\n\nasync function emitCronArtifacts(opts: {\n cwd: string\n serverDir: string\n agentsDir: string\n distDir: string\n target: BuildTarget\n}): Promise<void> {\n // Crons live in two conventional homes: `server/crons/` (a backend trigger) and\n // `agents/schedules/` (a scheduled agent run, kept in the agent domain). Both feed one manifest.\n const cronsDir = resolve(opts.serverDir, 'crons')\n const agentsSchedulesDir = resolve(opts.cwd, opts.agentsDir, 'schedules')\n\n const cronNodes = await scanCronDirs([cronsDir, agentsSchedulesDir])\n const manifestPath = resolve(opts.distDir, 'crons.json')\n writeCronManifest(manifestPath, cronNodes, opts.cwd)\n\n console.log(` ✓ Crons: ${cronNodes.length} declared`)\n\n if (cronNodes.length === 0) return\n\n // EC-201: target-specific translation. N/A targets emit a warning + skip.\n if (CRON_NA_TARGETS.has(opts.target)) {\n console.log(\n ` ⚠ Cron not supported by target \"${opts.target}\" — declared crons skipped. ` +\n `Supported targets: ${CRON_SUPPORTED_TARGETS.join(', ')}.`,\n )\n return\n }\n\n const manifestEntries = cronNodes.map((n) => ({\n name: n.name,\n filePath: relativize(n.filePath, opts.cwd),\n schedule: n.schedule,\n concurrency: n.concurrency,\n }))\n\n try {\n switch (opts.target) {\n case 'vercel':\n translateCronToVercel(resolve(opts.cwd, 'vercel.json'), manifestEntries)\n console.log(` ✓ Cron → vercel.json crons[] (${cronNodes.length} entries)`)\n break\n case 'cloudflare':\n translateCronToCloudflare(resolve(opts.cwd, 'wrangler.toml'), manifestEntries)\n console.log(` ✓ Cron → wrangler.toml [triggers] (${cronNodes.length})`)\n break\n case 'aws-lambda':\n translateCronToAws(resolve(opts.cwd, 'serverless.yml'), manifestEntries)\n console.log(` ✓ Cron → serverless.yml functions (${cronNodes.length})`)\n break\n case 'deno-deploy':\n translateCronToDeno(resolve(opts.distDir, 'crons-entry.ts'), manifestEntries)\n console.log(` ✓ Cron → ${opts.distDir}/crons-entry.ts (Deno.cron)`)\n break\n case 'node':\n console.log(` ✓ Cron → in-process scheduler (theokit start)`)\n break\n }\n } catch (err) {\n if (err instanceof ExistingConfigUnparseableError) throw err\n throw err\n }\n}\n\nasync function emitJobArtifacts(opts: {\n cwd: string\n serverDir: string\n distDir: string\n}): Promise<void> {\n const jobsDir = resolve(opts.serverDir, 'jobs')\n\n const jobNodes = existsSync(jobsDir) ? await scanJobs(jobsDir) : []\n const manifestPath = resolve(opts.distDir, 'jobs.json')\n writeJobManifest(manifestPath, jobNodes, opts.cwd)\n console.log(` ✓ Jobs: ${jobNodes.length} declared`)\n}\n\nfunction relativize(absPath: string, root: string): string {\n if (absPath.startsWith(root)) {\n const trimmed = absPath.slice(root.length)\n return trimmed.startsWith('/') ? trimmed.slice(1) : trimmed\n }\n return absPath\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time adapter translators: caller-controlled paths only.\n */\nimport { existsSync, readFileSync } from 'node:fs'\n\nimport { writeAtomic } from '../_internal/atomic-write.js'\n\nimport type { CronManifestEntry } from './cron-manifest.js'\n\n/**\n * Thrown when an existing platform-config file (vercel.json, wrangler.toml,\n * serverless.yml) cannot be parsed. Caller must fix the file before\n * re-running `theokit build`. We NEVER silently overwrite a user's config.\n */\nexport class ExistingConfigUnparseableError extends Error {\n readonly code = 'EXISTING_CONFIG_UNPARSEABLE'\n constructor(\n public readonly filePath: string,\n public readonly parseError: string,\n ) {\n super(\n `Existing config \"${filePath}\" could not be parsed: ${parseError}. ` +\n 'Fix or remove the file before re-running build — TheoKit never silently overwrites user configuration.',\n )\n this.name = 'ExistingConfigUnparseableError'\n }\n}\n\n// ──────────────────────────────────────────────────────────\n// Vercel — vercel.json crons[]\n// ──────────────────────────────────────────────────────────\n\ninterface VercelJson {\n crons?: { path: string; schedule: string }[]\n [key: string]: unknown\n}\n\n/**\n * Translate a TheoKit cron manifest into `vercel.json crons[]`.\n *\n * EC-105: existing fields (functions, headers, redirects, rewrites, env,\n * etc.) are preserved verbatim — ONLY the `crons[]` slice is replaced.\n */\nexport function translateCronToVercel(\n vercelJsonPath: string,\n crons: readonly CronManifestEntry[],\n): void {\n let existing: VercelJson = {}\n if (existsSync(vercelJsonPath)) {\n const raw = readFileSync(vercelJsonPath, 'utf8')\n try {\n existing = JSON.parse(raw) as VercelJson\n } catch (err) {\n throw new ExistingConfigUnparseableError(\n vercelJsonPath,\n err instanceof Error ? err.message : String(err),\n )\n }\n }\n const merged: VercelJson = {\n ...existing,\n crons: crons.map((c) => ({\n path: `/api/__crons/${c.name}`,\n schedule: c.schedule,\n })),\n }\n writeAtomic(vercelJsonPath, JSON.stringify(merged, null, 2))\n}\n\n// ──────────────────────────────────────────────────────────\n// Cloudflare — wrangler.toml [triggers] crons\n// ──────────────────────────────────────────────────────────\n\n/**\n * Translate a TheoKit cron manifest into `wrangler.toml [triggers] crons`.\n *\n * EC-105: regex-based mutation that preserves comments + other sections\n * verbatim. Replaces only the `[triggers]` block (or appends if absent).\n */\nexport function translateCronToCloudflare(\n wranglerTomlPath: string,\n crons: readonly CronManifestEntry[],\n): void {\n const schedules = crons.map((c) => `\"${c.schedule}\"`).join(', ')\n const triggersBlock = `[triggers]\\ncrons = [${schedules}]\\n`\n\n if (!existsSync(wranglerTomlPath)) {\n writeAtomic(wranglerTomlPath, triggersBlock)\n return\n }\n\n const existing = readFileSync(wranglerTomlPath, 'utf8')\n\n // Replace existing [triggers] section if present. Strategy: split into\n // line array, find the [triggers] header line, drop subsequent lines\n // until the next section header (line starting with `[`) or EOF.\n const lines = existing.split('\\n')\n const triggersIdx = lines.findIndex((l) => l.trim() === '[triggers]')\n\n let next: string\n if (triggersIdx !== -1) {\n let endIdx = lines.length\n for (let i = triggersIdx + 1; i < lines.length; i++) {\n if (lines[i].trim().startsWith('[')) {\n endIdx = i\n break\n }\n }\n const before = lines.slice(0, triggersIdx).join('\\n')\n const after = lines.slice(endIdx).join('\\n')\n next = `${before}\\n${triggersBlock.trimEnd()}\\n${after}`.replace(/\\n{3,}/g, '\\n\\n')\n } else {\n next = existing.endsWith('\\n')\n ? `${existing}\\n${triggersBlock}`\n : `${existing}\\n\\n${triggersBlock}`\n }\n writeAtomic(wranglerTomlPath, next)\n}\n\n// ──────────────────────────────────────────────────────────\n// AWS Lambda — serverless.yml functions.<fn>.events: schedule\n// ──────────────────────────────────────────────────────────\n\n/**\n * Convert TheoKit's 5-field UTC cron to AWS EventBridge's 6-field format.\n * EventBridge requires `?` in EITHER day-of-month OR day-of-week (not both `*`).\n *\n * Algorithm:\n * - If DOM is \"*\" and DOW is \"*\" → insert ? in DOW (default)\n * - If DOM is \"*\" and DOW is specific → insert ? in DOM\n * - If DOM is specific and DOW is \"*\" → insert ? in DOW\n * - Append \"*\" year field at end.\n */\nexport function convertToAwsCron(schedule: string): string {\n const parts = schedule.trim().split(/\\s+/)\n if (parts.length !== 5) {\n throw new Error(`Invalid 5-field schedule for AWS conversion: \"${schedule}\"`)\n }\n const [minute, hour, dom, month, dow] = parts\n let awsDom = dom\n let awsDow = dow\n if (dom === '*' && dow === '*') {\n awsDow = '?'\n } else if (dom === '*') {\n awsDom = '?'\n } else if (dow === '*') {\n awsDow = '?'\n }\n return `cron(${minute} ${hour} ${awsDom} ${month} ${awsDow} *)`\n}\n\n/**\n * Translate a TheoKit cron manifest into a `serverless.yml` functions\n * map with `events: - schedule: cron(...)` entries.\n *\n * EC-105: appends to `functions:` block, preserving all existing\n * functions/sections. Cron functions are named `cron_<name>` to avoid\n * collision with user-declared functions.\n */\nexport function translateCronToAws(\n serverlessYmlPath: string,\n crons: readonly CronManifestEntry[],\n): void {\n const cronFunctionsYaml = crons\n .map(\n (c) => ` cron_${c.name}:\n handler: .theokit/server/crons/${c.name}.handler\n events:\n - schedule: ${convertToAwsCron(c.schedule)}`,\n )\n .join('\\n')\n\n const block = `\\nfunctions:\\n${cronFunctionsYaml}\\n`\n\n if (!existsSync(serverlessYmlPath)) {\n // Minimal serverless.yml scaffold\n writeAtomic(\n serverlessYmlPath,\n `service: theokit-app\\nprovider:\\n name: aws\\n runtime: nodejs22.x\\n${block}`,\n )\n return\n }\n\n const existing = readFileSync(serverlessYmlPath, 'utf8')\n\n // Look for an existing top-level `functions:` block; if present, append our\n // cron entries under it (don't replace user-declared functions).\n const functionsRe = /^functions:\\s*\\n/m\n let next: string\n if (functionsRe.test(existing)) {\n next = existing.replace(functionsRe, (match) => `${match}${cronFunctionsYaml}\\n`)\n } else {\n next = existing.endsWith('\\n') ? `${existing}${block}` : `${existing}\\n${block}`\n }\n writeAtomic(serverlessYmlPath, next)\n}\n\n// ──────────────────────────────────────────────────────────\n// Deno Deploy — Deno.cron registrations\n// ──────────────────────────────────────────────────────────\n\n/**\n * Emit a Deno entry file that registers each cron via `Deno.cron`.\n *\n * Unlike Vercel/CF/AWS, Deno.cron is an in-process runtime API — the\n * entry file is a managed artifact (overwritten each build), not a user\n * config (so EC-105 doesn't apply here).\n */\nexport function translateCronToDeno(entryPath: string, crons: readonly CronManifestEntry[]): void {\n const lines = crons.map(\n (c) =>\n `Deno.cron(\"${c.name}\", \"${c.schedule}\", async () => {\n const mod = await import(\"../${c.filePath}\");\n const def = mod.default;\n await def.handler({\n traceId: crypto.randomUUID().replace(/-/g, \"\"),\n scheduledAt: new Date(),\n signal: AbortSignal.timeout(60_000),\n });\n});`,\n )\n const content = `// AUTOGENERATED by TheoKit cron build — DO NOT EDIT.\n// Source: server/crons/*.ts → .theokit/crons.json → this file.\n${lines.join('\\n\\n')}\n`\n writeAtomic(entryPath, content)\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time atomic write: caller-controlled paths only. No HTTP input\n * reaches these fs calls.\n */\n// T5a.1b — Web Crypto migration. Build-time only; node:fs + node:path stay\n// because this is a manifest-write leaf (e.g. .theokit/jobs.json) and per\n// ADR-0028 the runtime-portable boundary is the request handler, not the\n// scanner. Only node:crypto is swapped out — Web Crypto's\n// getRandomValues works in every supported runtime.\nimport { mkdirSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\n/**\n * Write `content` to `path` atomically via the tmp + rename pattern.\n *\n * Two concurrent calls to `writeAtomic(path, ...)` are guaranteed to\n * leave `path` containing valid content from ONE of the calls (never\n * truncated, never interleaved). POSIX rename is atomic on the same\n * filesystem.\n *\n * EC-106 (jobs-crons-webhooks-cost-tracking-plan) — shared helper for\n * `.theokit/crons.json` and `.theokit/jobs.json` manifest writes so a\n * concurrent dev-server scan + build manifest emit never produces\n * partial JSON.\n *\n * @param path destination path\n * @param content bytes (UTF-8 string) to write\n */\nexport function writeAtomic(path: string, content: string): void {\n mkdirSync(dirname(path), { recursive: true })\n // Include a random suffix so two concurrent writes don't trample each\n // other's tmp file. Web Crypto getRandomValues is non-blocking +\n // collision-safe for the tiny entropy we need (8 hex chars = 32 bits).\n // Hex-encoded manually to avoid Buffer (runtime-agnostic per ADR-0028).\n const randBuf = new Uint8Array(4)\n globalThis.crypto.getRandomValues(randBuf)\n let suffix = ''\n for (const b of randBuf) suffix += b.toString(16).padStart(2, '0')\n const tmp = `${path}.tmp-${process.pid}-${suffix}`\n writeFileSync(tmp, content, 'utf8')\n renameSync(tmp, path)\n}\n","import { writeAtomic } from '../_internal/atomic-write.js'\n\nimport type { CronNode } from './cron-scan.js'\n\nexport const CRON_MANIFEST_SCHEMA_VERSION = 1 as const\n\nexport interface CronManifestEntry {\n readonly name: string\n readonly filePath: string\n readonly schedule: string\n readonly concurrency: 'forbid' | 'allow'\n}\n\nexport interface CronManifest {\n readonly schemaVersion: typeof CRON_MANIFEST_SCHEMA_VERSION\n readonly generatedAt: string\n readonly crons: readonly CronManifestEntry[]\n}\n\n/**\n * Build a `CronManifest` from scanned `CronNode[]`. Filepaths are kept\n * relative to the caller's project root for portability.\n */\nexport function buildCronManifest(nodes: readonly CronNode[], projectRoot?: string): CronManifest {\n const crons: CronManifestEntry[] = nodes.map((n) => ({\n name: n.name,\n filePath: projectRoot ? relativize(n.filePath, projectRoot) : n.filePath,\n schedule: n.schedule,\n concurrency: n.concurrency,\n }))\n return {\n schemaVersion: CRON_MANIFEST_SCHEMA_VERSION,\n generatedAt: new Date().toISOString(),\n crons,\n }\n}\n\n/**\n * Write the cron manifest to `path` atomically (EC-106).\n *\n * Accepts either a pre-built `CronManifest` OR an array of `CronNode[]`\n * (which gets converted via `buildCronManifest`). The atomic-write\n * helper guarantees `path` always contains valid JSON, even under\n * concurrent writes (e.g., dev-server rescan + build).\n */\nexport function writeCronManifest(\n path: string,\n input: readonly CronNode[] | CronManifest,\n projectRoot?: string,\n): void {\n const manifest: CronManifest = isManifest(input) ? input : buildCronManifest(input, projectRoot)\n writeAtomic(path, JSON.stringify(manifest, null, 2))\n}\n\nfunction isManifest(value: unknown): value is CronManifest {\n return typeof value === 'object' && value !== null && 'schemaVersion' in value && 'crons' in value\n}\n\nfunction relativize(absPath: string, root: string): string {\n if (absPath.startsWith(root)) {\n const trimmed = absPath.slice(root.length)\n return trimmed.startsWith('/') ? trimmed.slice(1) : trimmed\n }\n return absPath\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: caller-controlled directory paths only. No HTTP\n * input ever reaches these fs calls.\n */\nimport { existsSync } from 'node:fs'\nimport { basename } from 'node:path'\n\nimport { importUserModule } from '../../config/import-user-module.js'\nimport { compareByCodeUnit } from '../_internal/compare-by-code-unit.js'\nimport { walkSourceFiles } from '../_internal/scan-walker.js'\n\nimport type { CronConcurrencyPolicy, CronDefinition } from './cron-types.js'\n\n/**\n * One discovered cron from build-time scan. The handler is intentionally\n * NOT included — manifest is platform-neutral and consumed by adapters\n * that emit static config. Runtime dispatch loads the handler at fire time.\n */\nexport interface CronNode {\n readonly name: string\n readonly filePath: string\n readonly schedule: string\n readonly concurrency: CronConcurrencyPolicy\n}\n\nexport class DuplicateCronNameError extends Error {\n readonly code = 'DUPLICATE_CRON_NAME'\n constructor(\n public readonly cronName: string,\n public readonly filePaths: readonly string[],\n ) {\n super(\n `Duplicate cron name \"${cronName}\" defined in: ${filePaths.join(', ')}. ` +\n 'Cron names must be unique across server/crons/ and agents/schedules/.',\n )\n this.name = 'DuplicateCronNameError'\n }\n}\n\nconst CRON_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.mjs'])\n\ninterface CronModule {\n default?: unknown\n}\n\nfunction isCronDefinition(value: unknown): value is CronDefinition {\n if (typeof value !== 'object' || value === null) return false\n const def = value as Record<string, unknown>\n return (\n typeof def.name === 'string' &&\n typeof def.schedule === 'string' &&\n typeof def.handler === 'function' &&\n (def.concurrency === 'forbid' || def.concurrency === 'allow')\n )\n}\n\n/**\n * Scan a directory for cron definition files and return the discovered\n * `CronNode[]` sorted by name. Throws `DuplicateCronNameError` on name\n * collision and `Error` on missing default export.\n *\n * Sequential by design — module imports are awaited one-by-one to keep\n * error messages anchored to the file that failed.\n */\nexport async function scanCrons(cronsDir: string): Promise<CronNode[]> {\n return scanCronDirs([cronsDir])\n}\n\n/**\n * Scan MULTIPLE cron directories and merge the results with a UNIFIED\n * duplicate-name guard across all of them. The framework discovers crons in\n * two conventional homes: `server/crons/` (a backend trigger) and\n * `agents/schedules/` (a scheduled agent run — kept in the agent domain). Both\n * feed the same manifest + deploy translation; a name may not collide across\n * the two dirs. Missing dirs are skipped (no error). Nodes are returned sorted\n * by name for a stable manifest.\n */\nexport async function scanCronDirs(dirs: readonly string[]): Promise<CronNode[]> {\n const filePaths: string[] = []\n for (const dir of dirs) {\n if (!existsSync(dir)) continue\n walkSourceFiles(dir, { extensions: CRON_EXTENSIONS }, (p) => {\n const base = basename(p)\n // Skip private helpers (`_helper.ts`) and OS junk (`.DS_Store`).\n if (base.startsWith('_') || base.startsWith('.')) return\n filePaths.push(p)\n })\n }\n\n const nodes: CronNode[] = []\n for (const filePath of filePaths) {\n let mod: CronModule\n try {\n mod = await importUserModule(filePath)\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to import cron file \"${filePath}\": ${reason}`)\n }\n const exported = mod.default\n if (!isCronDefinition(exported)) {\n throw new Error(\n `Cron file \"${filePath}\" is missing a valid default export. ` +\n 'Expected `export default defineCron(name, { schedule, handler })`.',\n )\n }\n nodes.push({\n name: exported.name,\n filePath,\n schedule: exported.schedule,\n concurrency: exported.concurrency,\n })\n }\n\n // Dup-name detection (unified across every scanned dir).\n const byName = new Map<string, string[]>()\n for (const node of nodes) {\n const bucket = byName.get(node.name) ?? []\n bucket.push(node.filePath)\n byName.set(node.name, bucket)\n }\n for (const [name, paths] of byName) {\n if (paths.length > 1) {\n throw new DuplicateCronNameError(name, paths)\n }\n }\n\n return nodes.sort((a, b) => compareByCodeUnit(a.name, b.name))\n}\n","import { writeAtomic } from '../_internal/atomic-write.js'\n\nimport type { JobNode } from './job-scan.js'\n\nexport const JOB_MANIFEST_SCHEMA_VERSION = 1 as const\n\nexport interface JobManifestEntry {\n readonly name: string\n readonly filePath: string\n readonly maxAttempts: number\n readonly hasInputSchema: boolean\n}\n\nexport interface JobManifest {\n readonly schemaVersion: typeof JOB_MANIFEST_SCHEMA_VERSION\n readonly generatedAt: string\n readonly jobs: readonly JobManifestEntry[]\n}\n\nexport function buildJobManifest(nodes: readonly JobNode[], projectRoot?: string): JobManifest {\n const jobs: JobManifestEntry[] = nodes.map((n) => ({\n name: n.name,\n filePath: projectRoot ? relativize(n.filePath, projectRoot) : n.filePath,\n maxAttempts: n.maxAttempts,\n hasInputSchema: n.hasInputSchema,\n }))\n return {\n schemaVersion: JOB_MANIFEST_SCHEMA_VERSION,\n generatedAt: new Date().toISOString(),\n jobs,\n }\n}\n\nexport function writeJobManifest(\n path: string,\n input: readonly JobNode[] | JobManifest,\n projectRoot?: string,\n): void {\n const manifest: JobManifest = isManifest(input) ? input : buildJobManifest(input, projectRoot)\n writeAtomic(path, JSON.stringify(manifest, null, 2))\n}\n\nfunction isManifest(value: unknown): value is JobManifest {\n return typeof value === 'object' && value !== null && 'schemaVersion' in value && 'jobs' in value\n}\n\nfunction relativize(absPath: string, root: string): string {\n if (absPath.startsWith(root)) {\n const trimmed = absPath.slice(root.length)\n return trimmed.startsWith('/') ? trimmed.slice(1) : trimmed\n }\n return absPath\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: caller-controlled directory paths only.\n */\nimport { existsSync } from 'node:fs'\nimport { basename } from 'node:path'\n\nimport { importUserModule } from '../../config/import-user-module.js'\nimport { compareByCodeUnit } from '../_internal/compare-by-code-unit.js'\nimport { walkSourceFiles } from '../_internal/scan-walker.js'\n\nimport type { JobDefinition } from './job-types.js'\n\nexport interface JobNode {\n readonly name: string\n readonly filePath: string\n readonly maxAttempts: number\n readonly hasInputSchema: boolean\n}\n\nexport class DuplicateJobNameError extends Error {\n readonly code = 'DUPLICATE_JOB_NAME'\n constructor(\n public readonly jobName: string,\n public readonly filePaths: readonly string[],\n ) {\n super(\n `Duplicate job name \"${jobName}\" defined in: ${filePaths.join(', ')}. ` +\n 'Job names must be unique across server/jobs/.',\n )\n this.name = 'DuplicateJobNameError'\n }\n}\n\nconst JOB_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.mjs'])\n\ninterface JobModule {\n default?: unknown\n}\n\nfunction isJobDefinition(value: unknown): value is JobDefinition {\n if (typeof value !== 'object' || value === null) return false\n const def = value as Record<string, unknown>\n return (\n typeof def.name === 'string' &&\n typeof def.handler === 'function' &&\n typeof def.maxAttempts === 'number' &&\n typeof def.hasInputSchema === 'boolean'\n )\n}\n\nexport async function scanJobs(jobsDir: string): Promise<JobNode[]> {\n if (!existsSync(jobsDir)) return []\n\n const filePaths: string[] = []\n walkSourceFiles(jobsDir, { extensions: JOB_EXTENSIONS }, (p) => {\n const base = basename(p)\n if (base.startsWith('_') || base.startsWith('.')) return\n filePaths.push(p)\n })\n\n const nodes: JobNode[] = []\n for (const filePath of filePaths) {\n let mod: JobModule\n try {\n mod = await importUserModule(filePath)\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to import job file \"${filePath}\": ${reason}`)\n }\n const exported = mod.default\n if (!isJobDefinition(exported)) {\n throw new Error(\n `Job file \"${filePath}\" is missing a valid default export. ` +\n 'Expected `export default defineJob(name, { handler })`.',\n )\n }\n nodes.push({\n name: exported.name,\n filePath,\n maxAttempts: exported.maxAttempts,\n hasInputSchema: exported.hasInputSchema,\n })\n }\n\n const byName = new Map<string, string[]>()\n for (const node of nodes) {\n const bucket = byName.get(node.name) ?? []\n bucket.push(node.filePath)\n byName.set(node.name, bucket)\n }\n for (const [name, paths] of byName) {\n if (paths.length > 1) {\n throw new DuplicateJobNameError(name, paths)\n }\n }\n\n return nodes.sort((a, b) => compareByCodeUnit(a.name, b.name))\n}\n","/**\n * State cleanup utilities (Phase 2 of\n *\n * - `cleanOutDir` — Astro pattern: empty a directory except a skip list,\n * used at `theokit build` start.\n * - `gcAgentRegistry` — Nuxt LRU pattern: delete oldest agent dirs when\n * count exceeds cap, used at `theokit dev` startup.\n *\n * EC-3 (MUST FIX, CRITICAL): cleanOutDir refuses to wipe anything outside\n * the current cwd. Prevents catastrophic `distDir: '/'` data loss.\n * EC-9 (SHOULD TEST): gcAgentRegistry handles dirs with mtime=0 (Docker overlay).\n * EC-11 (SHOULD TEST): cleanOutDir normalizes trailing-slash in skip basenames.\n * EC-12 (SHOULD TEST): cleanOutDir catches EROFS and continues.\n */\n\nimport { promises as fs } from 'node:fs'\nimport { basename, resolve as resolvePath, sep } from 'node:path'\n\nimport type {\n CleanOutDirOptions,\n CleanOutDirResult,\n GcAgentRegistryOptions,\n GcAgentRegistryResult,\n} from './cleanup-types.js'\n\nconst DEFAULT_SKIP = ['.git', '.gitkeep', '.gitignore']\n// DEFAULT_MAX_AGENTS removed in Phase 7 — gcAgentRegistry is a tombstone.\n\nfunction normalizeSkipName(name: string): string {\n // EC-11 — strip trailing slash + leading `./`\n return basename(name.replace(/\\/$/, ''))\n}\n\n/**\n * Empty a directory, preserving entries in the skip list.\n *\n * Throws if `opts.dir` is not inside `process.cwd()` (EC-3 path safety).\n * Returns `{deleted:0, kept:0}` when the directory does not exist.\n */\nexport async function cleanOutDir(opts: CleanOutDirOptions): Promise<CleanOutDirResult> {\n const resolvedDir = resolvePath(opts.dir)\n const resolvedCwd = resolvePath(process.cwd())\n\n // EC-3 — path safety guard. CRITICAL.\n if (resolvedDir === resolvedCwd) {\n throw new Error(\n `cleanOutDir refused to wipe ${resolvedDir} — must be a child of cwd, not cwd itself`,\n )\n }\n if (!resolvedDir.startsWith(resolvedCwd + sep)) {\n throw new Error(\n `cleanOutDir refused to wipe ${resolvedDir} — must be inside cwd (${resolvedCwd})`,\n )\n }\n\n const skip = new Set((opts.skip ?? DEFAULT_SKIP).map(normalizeSkipName))\n\n let entries: { name: string }[]\n try {\n entries = await fs.readdir(resolvedDir, { withFileTypes: true })\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ENOENT') return { deleted: 0, kept: 0 }\n throw err\n }\n\n let deleted = 0\n let kept = 0\n for (const entry of entries) {\n const name = entry.name\n if (skip.has(name)) {\n kept++\n continue\n }\n const fullPath = resolvePath(resolvedDir, name)\n try {\n await fs.rm(fullPath, { recursive: true, force: true, maxRetries: 3 })\n deleted++\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ENOENT') {\n deleted++ // already gone\n continue\n }\n // EC-12 — EROFS or other rm failure: warn + continue, don't crash.\n console.warn(\n `[theokit] cleanOutDir could not remove ${fullPath} (${code ?? 'unknown'}); skipping`,\n )\n kept++\n }\n }\n\n return { deleted, kept }\n}\n\n/**\n * Phase 7 — TOMBSTONE for backward-compat. The SDK v1.1.0's `Agent.registry`\n * handles GC natively; this function is a no-op + emits a deprecation warning\n * ONCE per process (EC-10).\n *\n * Will be deleted entirely in TheoKit 0.4.0. Marked deprecated via runtime\n * warning rather than `@deprecated` JSDoc tag to avoid the eslint\n * sonarjs/deprecation flagging our own internal symbols.\n */\nlet warnedOnce = false\nexport async function gcAgentRegistry(\n _opts: GcAgentRegistryOptions,\n): Promise<GcAgentRegistryResult> {\n if (!warnedOnce) {\n warnedOnce = true\n console.warn(\n '[theokit] gcAgentRegistry is deprecated; SDK Agent.registry handles GC natively (configure via theo.config.ts > agents.registry)',\n )\n }\n return Promise.resolve({ deleted: 0, kept: 0 })\n}\n\n/**\n * @internal — testing helper. Resets the module-scoped warnedOnce flag.\n */\nexport function __resetGcDeprecationWarnedForTests(): void {\n warnedOnce = false\n}\n","import { existsSync } from 'node:fs'\nimport { join, relative, resolve, sep } from 'node:path'\n\nimport type { AdapterBuildContext } from '../../adapters/types.js'\nimport { scanAgents } from '../../server/scan/agent-scan.js'\nimport { scanServerRoutes } from '../../server/scan/scan.js'\nimport { scanWebSocketRoutes } from '../../server/scan/ws-scan.js'\n\n/**\n * What a scanned deploy target is handed instead of a filesystem.\n *\n * #369 — a Worker has no filesystem at request time, so the Cloudflare entry bakes its routes at\n * build time. Importing the scanner from `adapters/` would add the `adapters → server` edge that\n * `adapters-may-only-depend-on-core-router-services` refuses, so the CLI composes the scan and\n * hands over the result.\n *\n * ## Why this is a module rather than a closure inside `buildCommand`\n *\n * It was a closure, and the defect it carried was invisible to every test: `buildCommand` loads a\n * config, runs vite twice and writes a tree, so nothing could ask it one question about one call.\n * Extracted at B-312, whose whole content was a single argument being wrong.\n *\n * Paths are made relative to the project root here, where `projectRoot` is known: that string is\n * both the emitted import specifier and the key the executor looks a module up by, and the scanners\n * return absolute paths.\n */\nexport function createBuildScanRoutes(\n projectRoot: string,\n config: { agentsDir?: string },\n): NonNullable<AdapterBuildContext['scanRoutes']> {\n return (serverDir: string) => {\n const abs = resolve(projectRoot, serverDir)\n const toProjectRelative = (p: string): string => relative(projectRoot, p).split(sep).join('/')\n\n return {\n routes: scanServerRoutes(abs).map((route) => ({\n filePath: toProjectRelative(route.filePath),\n routePath: route.routePath,\n methods: route.methods ?? [],\n })),\n wsRoutes: scanWebSocketRoutes(abs).map((ws) =>\n toProjectRelative(typeof ws === 'string' ? ws : ws.filePath),\n ),\n // #367 — agents are a DIFFERENT scan served by a DIFFERENT function, which is why no adapter\n // had ever heard of them: the entries route `/api/` through `scanServerRoutes` +\n // `executeRoute` alone, so `/api/agents/<name>` matched nothing and 404'd on every target.\n // Scanned here, beside the routes, because the same inversion argument applies verbatim.\n //\n // B-312 — the root is the PROJECT ROOT, and was `dirname(abs)`. `config.agentsDir` is\n // documented and declared relative to the project root, while `dirname(serverDir)` is the\n // root only when `serverDir` is a direct child of it. The scaffold's own nested layout\n // (`serverDir: 'src/server'`, `agentsDir: 'src/server/agents'`) made the two disagree, and\n // `join()` produced `<root>/src/src/server/agents` — so `scanAgents` returned `[]` and every\n // `/api/agents/*` route 404'd on every scanned target. Measured on a live Cloudflare deploy,\n // 2026-09-26. Every other caller in the tree already passes the project root.\n agents: scanAgents(projectRoot, config.agentsDir).map((agent) => ({\n filePath: toProjectRelative(agent.filePath),\n agentPath: agent.agentPath,\n name: agent.name,\n })),\n // B-185 — the identity module, decided here for the same reason the agents are: this provider\n // is handed `serverDir`, and a Worker has no filesystem to look for it on. An app with no\n // `server/context.ts` yields `undefined`, and the generator then emits no import — importing\n // a file that is not there would fail the BUILD rather than one request.\n contextModule: existsSync(join(abs, 'context.ts'))\n ? toProjectRelative(join(abs, 'context.ts'))\n : undefined,\n }\n }\n}\n"],"mappings":"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","names":["existsSync","resolve","existsSync","existsSync","relativize","isManifest","existsSync","basename","existsSync","basename","basename","existsSync","sep","sep","existsSync","resolve","writeManifest","relativize","existsSync"]}