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.
- package/dist/{actions-virtual-module-JV7URROJ.js → actions-virtual-module-4J7Z37Y4.js} +2 -2
- package/dist/{actions-virtual-module-J2HYO7QZ.js → actions-virtual-module-MIQJEHKJ.js} +2 -2
- package/dist/adapters/agent-mount.js +2 -2
- package/dist/{agent-5J7CQAYR.js → agent-QJINXU6U.js} +2 -2
- package/dist/{app-typed-client-XD4DZBV7.js → app-typed-client-AZMUYIYV.js} +2 -2
- package/dist/{app-typed-client-EOA3A2AR.js → app-typed-client-DSS23KDC.js} +2 -2
- package/dist/{aws-lambda-ZYSPTD3O.js → aws-lambda-K5Y6XS5V.js} +4 -4
- package/dist/{build-7YZSJGP2.js → build-AKN2NCFW.js} +23 -19
- package/dist/build-AKN2NCFW.js.map +1 -0
- package/dist/{bun-I7YM3RDB.js → bun-VPXMWFBA.js} +6 -4
- package/dist/bun-VPXMWFBA.js.map +1 -0
- package/dist/{chunk-SG62LZOJ.js → chunk-25OXNMVO.js} +4 -4
- package/dist/{chunk-QX5Q3FBJ.js → chunk-7FIK5NKN.js} +10 -10
- package/dist/{chunk-SHIXTMQE.js → chunk-DA3GGICE.js} +16 -2
- package/dist/{chunk-SHIXTMQE.js.map → chunk-DA3GGICE.js.map} +1 -1
- package/dist/{chunk-ZNZISJDZ.js → chunk-L4V5V2TI.js} +1 -1
- package/dist/{chunk-ZNZISJDZ.js.map → chunk-L4V5V2TI.js.map} +1 -1
- package/dist/{chunk-UFBBFP75.js → chunk-NLHAYGQQ.js} +2 -2
- package/dist/{chunk-X2LFNDJQ.js → chunk-NX3P5MLH.js} +2 -2
- package/dist/{chunk-2NG5T77O.js → chunk-R4AMIBZL.js} +16 -2
- package/dist/{chunk-2NG5T77O.js.map → chunk-R4AMIBZL.js.map} +1 -1
- package/dist/{chunk-NQZIQJFH.js → chunk-SHFZKJCU.js} +7 -7
- package/dist/{chunk-QAS5SKZP.js → chunk-VD3BCME6.js} +2 -2
- package/dist/{chunk-SZWGXHY3.js → chunk-VOXLI66L.js} +2 -2
- package/dist/{chunk-HK57MPSZ.js → chunk-VPK7ABMB.js} +2 -2
- package/dist/cli/index.js +9 -9
- package/dist/{cloudflare-Q5SUXRXY.js → cloudflare-PRTTYWRD.js} +3 -3
- package/dist/{config-support-MOZYHRWG.js → config-support-HUZ4DXR7.js} +3 -3
- package/dist/{deno-deploy-XW3Q6OMD.js → deno-deploy-M5V3PYWU.js} +68 -12
- package/dist/deno-deploy-M5V3PYWU.js.map +1 -0
- package/dist/{dev-FZ4OTCPT.js → dev-LMZGOV4M.js} +7 -7
- package/dist/index.js +3 -3
- package/dist/{info-SUX7QVA3.js → info-XURFOBRF.js} +4 -4
- package/dist/{internal-api-GKPJYL3G.js → internal-api-ATSPOXI2.js} +2 -2
- package/dist/{internal-api-ZUBUYGCQ.js → internal-api-XPT4GLYX.js} +2 -2
- package/dist/{load-config-52H3EKAA.js → load-config-2DXLI7NW.js} +4 -4
- package/dist/{mcp-VUHRRX36.js → mcp-4CXNOZA4.js} +3 -3
- package/dist/{netlify-ALPCTQFO.js → netlify-NI4HYDKN.js} +28 -9
- package/dist/netlify-NI4HYDKN.js.map +1 -0
- package/dist/node-LORYECWI.js +10 -0
- package/dist/{openapi-C4UX2SFV.js → openapi-UJSUQPNT.js} +4 -4
- package/dist/{preview-II33QNAC.js → preview-WTPUW47O.js} +3 -3
- package/dist/registry-SUE4HJXL.js +34 -0
- package/dist/{routes-3PTNISSO.js → routes-ENMU4GAN.js} +4 -4
- package/dist/{schema-LHNWUR4V.js → schema-DJH3IOVR.js} +3 -3
- package/dist/{server-boundary-QCJNECJP.js → server-boundary-JM72DQLA.js} +2 -2
- package/dist/{server-boundary-RTRPHX5I.js → server-boundary-K4YQXDQT.js} +2 -2
- package/dist/{services-typed-client-XGT5SUUN.js → services-typed-client-FOBFCRD6.js} +2 -2
- package/dist/{start-EREUCSN6.js → start-GAULIE5E.js} +7 -7
- package/dist/{static-7LP7LPGN.js → static-O2RZ5NLR.js} +3 -3
- package/dist/{theo-cloud-GIA67L4Q.js → theo-cloud-B4R7GCWK.js} +3 -3
- package/dist/{vercel-VLR52RXT.js → vercel-INHLOCSZ.js} +3 -3
- package/dist/vite-plugin/index.js +3 -3
- package/dist/{vite-plugin-3LTZJTUM.js → vite-plugin-NXWE2AVM.js} +7 -7
- package/package.json +3 -3
- package/dist/build-7YZSJGP2.js.map +0 -1
- package/dist/bun-I7YM3RDB.js.map +0 -1
- package/dist/deno-deploy-XW3Q6OMD.js.map +0 -1
- package/dist/netlify-ALPCTQFO.js.map +0 -1
- package/dist/node-4HQO6KKZ.js +0 -10
- package/dist/registry-WVUO2WNR.js +0 -34
- /package/dist/{actions-virtual-module-JV7URROJ.js.map → actions-virtual-module-4J7Z37Y4.js.map} +0 -0
- /package/dist/{actions-virtual-module-J2HYO7QZ.js.map → actions-virtual-module-MIQJEHKJ.js.map} +0 -0
- /package/dist/{agent-5J7CQAYR.js.map → agent-QJINXU6U.js.map} +0 -0
- /package/dist/{app-typed-client-XD4DZBV7.js.map → app-typed-client-AZMUYIYV.js.map} +0 -0
- /package/dist/{app-typed-client-EOA3A2AR.js.map → app-typed-client-DSS23KDC.js.map} +0 -0
- /package/dist/{aws-lambda-ZYSPTD3O.js.map → aws-lambda-K5Y6XS5V.js.map} +0 -0
- /package/dist/{chunk-SG62LZOJ.js.map → chunk-25OXNMVO.js.map} +0 -0
- /package/dist/{chunk-QX5Q3FBJ.js.map → chunk-7FIK5NKN.js.map} +0 -0
- /package/dist/{chunk-UFBBFP75.js.map → chunk-NLHAYGQQ.js.map} +0 -0
- /package/dist/{chunk-X2LFNDJQ.js.map → chunk-NX3P5MLH.js.map} +0 -0
- /package/dist/{chunk-NQZIQJFH.js.map → chunk-SHFZKJCU.js.map} +0 -0
- /package/dist/{chunk-QAS5SKZP.js.map → chunk-VD3BCME6.js.map} +0 -0
- /package/dist/{chunk-SZWGXHY3.js.map → chunk-VOXLI66L.js.map} +0 -0
- /package/dist/{chunk-HK57MPSZ.js.map → chunk-VPK7ABMB.js.map} +0 -0
- /package/dist/{cloudflare-Q5SUXRXY.js.map → cloudflare-PRTTYWRD.js.map} +0 -0
- /package/dist/{config-support-MOZYHRWG.js.map → config-support-HUZ4DXR7.js.map} +0 -0
- /package/dist/{dev-FZ4OTCPT.js.map → dev-LMZGOV4M.js.map} +0 -0
- /package/dist/{info-SUX7QVA3.js.map → info-XURFOBRF.js.map} +0 -0
- /package/dist/{internal-api-GKPJYL3G.js.map → internal-api-ATSPOXI2.js.map} +0 -0
- /package/dist/{internal-api-ZUBUYGCQ.js.map → internal-api-XPT4GLYX.js.map} +0 -0
- /package/dist/{load-config-52H3EKAA.js.map → load-config-2DXLI7NW.js.map} +0 -0
- /package/dist/{mcp-VUHRRX36.js.map → mcp-4CXNOZA4.js.map} +0 -0
- /package/dist/{node-4HQO6KKZ.js.map → node-LORYECWI.js.map} +0 -0
- /package/dist/{openapi-C4UX2SFV.js.map → openapi-UJSUQPNT.js.map} +0 -0
- /package/dist/{preview-II33QNAC.js.map → preview-WTPUW47O.js.map} +0 -0
- /package/dist/{registry-WVUO2WNR.js.map → registry-SUE4HJXL.js.map} +0 -0
- /package/dist/{routes-3PTNISSO.js.map → routes-ENMU4GAN.js.map} +0 -0
- /package/dist/{schema-LHNWUR4V.js.map → schema-DJH3IOVR.js.map} +0 -0
- /package/dist/{server-boundary-QCJNECJP.js.map → server-boundary-JM72DQLA.js.map} +0 -0
- /package/dist/{server-boundary-RTRPHX5I.js.map → server-boundary-K4YQXDQT.js.map} +0 -0
- /package/dist/{services-typed-client-XGT5SUUN.js.map → services-typed-client-FOBFCRD6.js.map} +0 -0
- /package/dist/{start-EREUCSN6.js.map → start-GAULIE5E.js.map} +0 -0
- /package/dist/{static-7LP7LPGN.js.map → static-O2RZ5NLR.js.map} +0 -0
- /package/dist/{theo-cloud-GIA67L4Q.js.map → theo-cloud-B4R7GCWK.js.map} +0 -0
- /package/dist/{vercel-VLR52RXT.js.map → vercel-INHLOCSZ.js.map} +0 -0
- /package/dist/{vite-plugin-3LTZJTUM.js.map → vite-plugin-NXWE2AVM.js.map} +0 -0
package/dist/bun-I7YM3RDB.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/bun.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Bun deploy adapter. Writes to `cwd/.theokit/bun/`. Build-time.\n */\nimport { mkdirSync, 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 { deployedAgentsFragment } from './deployed-agents.js'\nimport { type DeployedCorsOptions } from './deployed-cors.js'\nimport { type DeployedCsrfOptions } from './deployed-csrf.js'\nimport { readDocumentShell } from './deployed-document-shell.js'\nimport { planDeployedPlugins } from './deployed-plugins-module.js'\nimport { deployedEntryPreamble } from './deployed-preamble.js'\nimport {\n deployedRateLimitFragment,\n rateLimitCheckFragment,\n type DeployedRateLimitOptions,\n} from './deployed-rate-limit.js'\nimport {\n deployedRuntimeConfigFragment,\n agentsDirLiteral,\n serverDirLiteral,\n type DeployedRuntimeConfigOptions,\n type DeployedAgentsDirOptions,\n type DeployedServerDirOptions,\n} from './deployed-runtime-config.js'\nimport { deployedTraceFragment } from './deployed-trace.js'\nimport { nodeAdapter } from './node.js'\nimport { describeDeployedSecurityHeaders } from './security-headers.js'\nimport type { AdapterBuildContext, DeployAdapter } from './types.js'\n\nexport interface BunBuildDeps {\n runNodeBuild?: (config: TheoConfig, cwd: string, ctx?: AdapterBuildContext) => Promise<void>\n writeEntry?: (path: string, content: string) => void\n ensureDir?: (path: string) => void\n}\n\n/**\n * The module-scope refusals: this entry is production-only and Bun-only.\n *\n * Extracted from `renderBunEntry` when adding the configured-directory literal pushed it past the\n * per-function line budget. They are a cohesive block — three checks that all refuse to start —\n * and lifting them keeps the budget a signal about the renderer rather than about its preamble.\n */\nconst RUNTIME_GUARDS: readonly string[] = [\n `// EC-1: dev-mode guard`,\n `if (process.env.NODE_ENV !== 'production') {`,\n ` console.error('TheoBunAdapter is production-only. Use \\\\'theokit dev\\\\' (Node) for development.')`,\n ` process.exit(1)`,\n `}`,\n ``,\n `// Version check: Bun >= 1.1`,\n `if (typeof Bun === 'undefined') {`,\n ` console.error('TheoBunAdapter must run inside Bun. Got Node.js or unknown runtime.')`,\n ` process.exit(1)`,\n `}`,\n `{`,\n ` const [maj, min] = (Bun.version ?? '0.0').split('.').map(Number)`,\n ` if (maj < 1 || (maj === 1 && min < 1)) {`,\n ` console.error('TheoBunAdapter requires Bun >= 1.1; got ' + Bun.version)`,\n ` process.exit(1)`,\n ` }`,\n `}`,\n]\n\nexport function renderBunEntry(\n port: number,\n opts: {\n ssrStreaming?: boolean\n /**\n * Whether this build renders the document on the server.\n *\n * Bun is the one Web target whose own handler answers the HTML document, and it answered it from\n * `.theokit/client/index.html` — the client shell. So an `ssr: true` project was served an empty\n * `<div id=\"root\">` while the build printed `(SSR)` (B-334).\n */\n ssr?: boolean\n /** The document up to `<div id=\"root\">`, read from the built client shell. */\n htmlHead?: string\n /** The document from `<div id=\"root\">` on. */\n htmlTail?: string\n securityHeaders?: SecurityHeadersConfig\n } & DeployedAgentsDirOptions &\n DeployedCsrfOptions &\n DeployedRuntimeConfigOptions &\n DeployedServerDirOptions &\n DeployedCorsOptions &\n DeployedRateLimitOptions = {},\n): string {\n // The whole implementation of `ssrStreaming` in this adapter used to be the text of this comment:\n // `opts.ssrStreaming` was read, and its only effect was which string landed on line 4 of the emitted\n // file. `rules/foreign-config-surfaces.md` names that exact failure — \"A surface is read, or it is\n // refused with a reason. It is never accepted and ignored\" — and it was in this adapter.\n const document =\n opts.ssr === true ? { htmlHead: opts.htmlHead, htmlTail: opts.htmlTail } : undefined\n const streamingComment =\n document !== undefined\n ? `// ssr on — the document is rendered by this handler, not read from .theokit/client`\n : `// ssr off — the document is the built client shell, served from disk`\n const runtimeConfig = deployedRuntimeConfigFragment(opts)\n const agentsFragment = deployedAgentsFragment(\n {\n kind: 'scan',\n projectRoot: 'cwd',\n loadModule: 'loadModule',\n serverDir: 'serverDir',\n agentsDirLiteral: agentsDirLiteral(opts),\n },\n {\n pathname: 'pathname',\n // B-185 — bound only when the runtime-config fragment declared the const, which is\n // exactly when a plugins module was emitted. Referencing it otherwise would emit an\n // identifier the entry never declares.\n pluginRunnerExpr:\n opts.runtimeConfigModule === undefined ? undefined : 'await THEO_PLUGIN_RUNNER',\n },\n )\n return [\n `// Generated by Theo — Bun Adapter`,\n `// Run: bun run .theokit/bun/server.mjs`,\n `// Requires Bun >= 1.1`,\n streamingComment,\n ``,\n ...RUNTIME_GUARDS,\n ``,\n `import { resolve, join } from 'node:path'`,\n `import { existsSync } from 'node:fs'`,\n // One element per emitted line, like every neighbour, and the conditional import is a spread\n // rather than an interpolated `\\n`. That is not a style preference: this line carried the\n // fragment inside a nested double-quoted string, where an escaped backslash is a backslash, so\n // the import reached the module joined by two characters and Bun refused it. A construct that\n // cannot express a malformed line beats one escaped correctly (B-325), and `sonarjs` refuses the\n // nesting outright — the lint was naming the cause.\n `import { scanServerRoutes, matchRoute, createProductionLoader } from 'theokit/server/scan'`,\n `import { executeRoute, extractTraceIdFromRequest, TRACE_HEADER, createCorsWebHandler } from 'theokit/server/http'`,\n ...(opts.rateLimit === undefined\n ? []\n : [`import { createRateLimiterWeb } from 'theokit/server/rate-limit'`]),\n `import { createWebShim } from 'theokit/adapters/web-shim'`,\n `import { buildSecurityHeaders, withSecurityHeaders } from 'theokit/adapters/security-headers'`,\n // The renderer the node build already emits for this target and nothing imported. Its own header\n // names Bun: \"Web Standards streaming entry for edge runtimes (Cloudflare, Bun, Deno, Vercel\n // Edge)\". Measured on a real build: `.theokit/server/entry-server.js` is 95513 bytes and exports\n // the render, and `.theokit/bun/server.mjs` referenced it zero times.\n ...(document === undefined\n ? []\n : [`import { renderStreamingWeb } from '../server/entry-server.js'`]),\n `// T3.2 — WS bridge for Bun runtime`,\n `import { createBunWsBridge } from 'theokit/adapters/ws-shim'`,\n `import { scanWebSocketRoutes } from 'theokit/server/scan'`,\n ``,\n `const cwd = process.cwd()`,\n `const clientDir = resolve(cwd, '.theokit/client')`,\n `const serverDir = resolve(cwd, ${serverDirLiteral(opts)})`,\n `const port = process.env.PORT ? Number(process.env.PORT) : ${port}`,\n ``,\n `// #410 — the security baseline \\`theokit start\\` puts on every response,`,\n `// carried here as a literal because the deployed process has no`,\n `// theo.config.ts to read. Bun is the one Web target whose own handler serves`,\n `// the HTML document (static file + SPA fallback below), so the document gets`,\n `// these headers too -- with a nonce-less CSP, because that HTML was written`,\n `// at build time and carries no nonce on its script tags (EC-4).`,\n ...deployedEntryPreamble(runtimeConfig, agentsFragment, opts, 'bun'),\n ``,\n ...deployedRateLimitFragment(opts.rateLimit, 'bun', 'server.requestIP(request)?.address'),\n ``,\n `const routes = existsSync(serverDir) ? scanServerRoutes(serverDir) : []`,\n `const wsRoutes = existsSync(serverDir) ? scanWebSocketRoutes(serverDir) : []`,\n `const loadModule = createProductionLoader()`,\n ``,\n `// Bun WebSocket config — single handler dispatches to first ws route,`,\n `// or a default no-op when none declared. Per-route routing happens above`,\n `// (the upgrade decision is made in fetch handler before Bun.serve hands off).`,\n `const wsBridge = wsRoutes.length > 0`,\n ` ? createBunWsBridge({`,\n ` onOpen: () => {},`,\n ` onMessage: (ws, data) => { ws.send(data) },`,\n ` onClose: () => {},`,\n ` })`,\n ` : { open: () => {}, message: () => {}, close: () => {} }`,\n ``,\n `function notFoundResponse() {`,\n ` return new Response(JSON.stringify({ error: { code: 'NOT_FOUND', message: 'Route not found' } }), {`,\n ` status: 404,`,\n ` headers: { 'Content-Type': 'application/json' },`,\n ` })`,\n `}`,\n ``,\n `Bun.serve({`,\n ` port,`,\n ` websocket: wsBridge,`,\n ` async fetch(request, server) {`,\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, ' '),\n ` return withCors(request, withSecurityHeaders(await handleRequest(request), SECURITY_HEADERS))`,\n ` },`,\n `})`,\n ``,\n ...bunHandleRequestFragment(runtimeConfig.executeRouteSpread, agentsFragment.branch, document),\n ].join('\\n')\n}\n\n/**\n * The request handler, as generated source.\n *\n * Extracted for the reason `vercel.ts` extracts its own fragments: the emitter is one array\n * literal, so every line the entry gains counts against `max-lines-per-function`, and #410 added\n * the CSRF literal to an emitter that was already sitting exactly at the ceiling.\n */\nfunction bunHandleRequestFragment(\n runtimeSpread: string,\n agentBranch: readonly string[],\n document: { htmlHead?: string; htmlTail?: string } | undefined,\n): string[] {\n return [\n `async function handleRequest(request) {`,\n ` const url = new URL(request.url)`,\n ` const pathname = url.pathname`,\n ``,\n ` // 1) Static assets`,\n ...(document === undefined\n ? [\n ` const staticPath = pathname === '/' ? '/index.html' : pathname`,\n ` const fullStatic = join(clientDir, staticPath)`,\n ` if (existsSync(fullStatic)) {`,\n ` const file = Bun.file(fullStatic)`,\n ` if (await file.exists()) return new Response(file)`,\n ` }`,\n ]\n : [\n ` // \\`/\\` is deliberately NOT mapped to index.html here: that file is the client shell,`,\n ` // and answering the document from it is what served an empty <div id=\"root\"> on an`,\n ` // ssr build. Real assets still come from disk; the document falls through to (3).`,\n ` if (pathname !== '/') {`,\n ` const fullStatic = join(clientDir, pathname)`,\n ` if (existsSync(fullStatic)) {`,\n ` const file = Bun.file(fullStatic)`,\n ` if (await file.exists()) return new Response(file)`,\n ` }`,\n ` }`,\n ]),\n ``,\n ` // 2) API routes through the full executeRoute pipeline via the shim`,\n ` if (pathname.startsWith('/api/') || __theoIsAgentCardPath(pathname)) {`,\n ...agentBranch,\n ``,\n ` const match = matchRoute(pathname, routes)`,\n ` if (!match) return notFoundResponse()`,\n ` const { req, res, toResponse } = createWebShim(request)`,\n ...deployedTraceFragment('request', ' '),\n ` const method = request.method.toUpperCase()`,\n ` // #382 — not awaited: toResponse() settles at the headers and carries`,\n ` // a live body, so Bun.serve streams while the handler writes.`,\n ` return toResponse(executeRoute({ route: match.route, method, params: match.params, req, res, loadModule, serverDir, requestId, ...CSRF_CONFIG, ${runtimeSpread} }))`,\n ` }`,\n ``,\n ...(document === undefined\n ? [\n ` // 3) SPA fallback`,\n ` const indexPath = join(clientDir, 'index.html')`,\n ` if (existsSync(indexPath)) return new Response(Bun.file(indexPath))`,\n ]\n : [\n ` // 3) The document, rendered here rather than read from disk.`,\n ` //`,\n ` // No nonce is minted: the outer wrapper applies a precomputed SECURITY_HEADERS constant,`,\n ` // so a per-request value would have to be threaded through it. That is a separate change`,\n ` // with its own blast radius, and the shell this replaces carries only external`,\n ` // <script src> tags, which \\`script-src 'self'\\` already allows.`,\n ` return await renderStreamingWeb(request, {`,\n ` htmlHead: ${JSON.stringify(document.htmlHead ?? '')},`,\n ` htmlTail: ${JSON.stringify(document.htmlTail ?? '')},`,\n ` })`,\n ]),\n ``,\n ` return notFoundResponse()`,\n `}`,\n ``,\n `console.log('Theo (Bun) listening on http://localhost:' + port)`,\n ]\n}\n\nexport async function buildBun(\n config: TheoConfig,\n cwd: string,\n deps: BunBuildDeps = {},\n ctx?: AdapterBuildContext,\n): Promise<void> {\n // Wave 2 (T2.2) — reject polyglot services on this adapter.\n assertServicesUnsupported('bun', readManifest(cwd))\n\n const runNodeBuild = deps.runNodeBuild ?? nodeAdapter.build.bind(nodeAdapter)\n await runNodeBuild(config, cwd, ctx)\n\n const outputDir = resolve(cwd, '.theokit/bun')\n const ensureDir = deps.ensureDir ?? ((p: string) => mkdirSync(p, { recursive: true }))\n ensureDir(outputDir)\n\n const pluginsPlan = planDeployedPlugins(config.plugins, 'bun')\n const entry = renderBunEntry(config.port, {\n ssrStreaming: config.ssrStreaming,\n // B-334 — the sixth time this shape has been fixed one target at a time: the renderer honoured an\n // option no build passed (B-185, B-235, B-312, B-315, B-317). Here it was worse — the option only\n // changed a comment. The shell is read HERE rather than in the emitter, because reading a file is\n // the build's job and not a string emitter's.\n ssr: config.ssr,\n ...readDocumentShell(cwd, config.ssr),\n securityHeaders: config.security?.headers,\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 // #425 — the ONE concern that is not a literal. A closure cannot be baked, so a plugin\n // declared by module specifier is imported by the emitted module instead; a constructed one\n // is refused by name at build time rather than dropped in silence.\n runtimeConfigModule: pluginsPlan?.moduleSpecifier,\n // #95 — the configured directories, which `build.ts:210` already threads into the Vite\n // plugins. Without these two lines the literals above fall to their defaults and a project\n // with a custom dir deploys an entry that resolves a directory it does not have.\n serverDir: config.serverDir,\n agentsDir: config.agentsDir,\n })\n const write =\n deps.writeEntry ??\n ((p, c) => {\n writeFileSync(p, c)\n })\n if (pluginsPlan !== undefined) {\n // Beside the entry, so the emitted import is a sibling. Written through the same seam as\n // the entry so a test that captures one captures both (#425).\n write(resolve(outputDir, 'theo.plugins.mjs'), pluginsPlan.source)\n }\n write(resolve(outputDir, 'server.mjs'), entry)\n\n // eslint-disable-next-line no-console -- CLI build progress\n console.log('\\n ✓ Bun output → .theokit/bun/server.mjs')\n // eslint-disable-next-line no-console -- CLI build progress\n console.log(\n `${describeDeployedSecurityHeaders({\n target: 'bun',\n securityHeaders: config.security?.headers,\n // Bun renders the document at request time when `ssr` is on (B-334), and still mints no nonce:\n // the outer wrapper applies a precomputed SECURITY_HEADERS constant, so a per-request value\n // would have to be threaded through it.\n //\n // This used to read \"No deploy target other than the streamed Cloudflare worker renders HTML at\n // request time, so none of the rest can mint a nonce.\" True when written, false the moment B-317\n // shipped — a CONSEQUENCE of the fleet at the time, never a prohibition, which is why rendering\n // here is consistent with the intent rather than against it.\n mintsNonce: false,\n // Bun serves `.theokit/client` itself, so the document DOES pass through\n // the handler these headers are attached to.\n documentHeaders: 'handler',\n })}\\n`,\n )\n}\n\nexport const bunAdapter: DeployAdapter = {\n // The entry runs IN the project: it resolves `serverDir` against `cwd`, so `node_modules` is\n // present and the scan has a tree to read. `docs/adr/0020` leaves this target alone for exactly\n // that reason.\n readsSourceAtRunTime: true,\n specifiersResolvedBy: 'the-project-at-run-time',\n name: 'bun',\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: the entry carries `security.headers` as a\n // literal and puts the built baseline on every response, the served document\n // included.\n servesAgents: true,\n appliesConfig: [\n 'securityHeaders',\n 'csrf',\n 'disallowed',\n 'cors',\n 'serialization',\n 'plugins',\n // #508 — bun is the first Web target to ENFORCE a declared limit rather than refuse the\n // build: `Bun.serve` is long-lived, so the in-process counter survives, and its handler\n // already receives `server`, whose `requestIP` gives the peer address without a header.\n 'rateLimit',\n ],\n // B-257 — a long-lived process: the in-process counter survives between requests.\n enforcesRateLimit: 'always',\n build(config, cwd, ctx) {\n return buildBun(config, cwd, {}, ctx)\n },\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/deno-deploy.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Deno Deploy adapter. Writes to `cwd/.theokit/deno-deploy/`. Build-time.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport type { TheoConfig } from '../config/schema.js'\nimport { assertServicesUnsupported, readManifest } from '../services/index.js'\n\nimport { deployedAgentsFragment, scannedFromLoaderCache } from './deployed-agents.js'\nimport { planDeployedPlugins } from './deployed-plugins-module.js'\nimport { deployedEntryPreamble } from './deployed-preamble.js'\nimport { deployedRateLimitFragment, rateLimitCheckFragment } from './deployed-rate-limit.js'\nimport {\n agentsDirLiteral,\n deployedRuntimeConfigFragment,\n serverDirLiteral,\n} from './deployed-runtime-config.js'\nimport { deployedTraceFragment } from './deployed-trace.js'\nimport { nodeAdapter } from './node.js'\nimport { describeDeployedSecurityHeaders } from './security-headers.js'\nimport type { AdapterBuildContext, DeployAdapter, DeployedEntryOptions } from './types.js'\n\nexport interface DenoBuildDeps {\n runNodeBuild?: (config: TheoConfig, cwd: string, ctx?: AdapterBuildContext) => Promise<void>\n writeEntry?: (path: string, content: string) => void\n ensureDir?: (path: string) => void\n /** The project's own source texts, whose bare imports the emitted map has to resolve. */\n readProjectSources?: (cwd: string, config: TheoConfig) => string[]\n /** The Deno config already on disk, merged rather than replaced. */\n readDenoConfig?: (cwd: string) => DenoConfig | undefined\n}\n\n/**\n * The framework imports this entry opens with, as `npm:` specifiers.\n *\n * Extracted from `renderDenoEntry` when adding the configured-directory literal pushed it past the\n * per-function line budget. A cohesive block — every line is one import of the same package family\n * — so lifting it keeps the budget a signal about the renderer rather than about its preamble.\n */\n/**\n * How this entry is deployed, and the one failure whose message names the wrong thing.\n *\n * Extracted for the same reason `FRAMEWORK_IMPORTS` above was: a cohesive block of emitted\n * comment lines that pushed the renderer past its line budget, where the budget is meant to\n * be a signal about the renderer rather than about its preamble.\n */\nconst DEPLOY_INSTRUCTIONS: readonly string[] = [\n `// Deploy from the project root, so the entry finds its own src/server tree:`,\n `// deno deploy --org <org> --app <name> --prod \\\\`,\n `// --ignore node_modules --ignore package.json`,\n `// Both exclusions are load-bearing, and both were isolated on the platform by`,\n `// changing one thing at a time. node_modules: pnpm's is a symlink farm the upload`,\n `// cannot carry, and this entry reaches the framework through npm: specifiers, so`,\n `// it needs none of it. package.json: it is what Deno resolves those specifiers`,\n `// against, so its version ranges bring the minimum-dependency-age policy with`,\n `// them — with the manifest in the upload the revision failed, without it the same`,\n `// directory deployed and served.`,\n `//`,\n `// If a deploy that keeps the manifest fails with \"Could not find npm package`,\n `// <name> matching <range>\",`,\n `// read the rest of that message before changing anything: Deno applies a`,\n `// minimum-dependency-age policy (24h by default) and refuses a version published`,\n `// inside that window, naming the PACKAGE rather than the policy. The range comes`,\n `// from this project's package.json, which the upload carries. It clears by itself;`,\n `// to deploy now, pass --min-dep-age=0 or set minimumDependencyAge in deno.json —`,\n `// both lower a supply-chain protection, which is why nothing here sets it for you.`,\n]\n\nconst FRAMEWORK_IMPORTS: readonly string[] = [\n `// Use npm: specifier so Deno resolves theokit from the user's package.json`,\n `// equivalent (works in both local 'deno run' and Deno Deploy).`,\n // Sub-paths, not the umbrella. `theokit/server` is DEPRECATED by the framework itself with a\n // REMOVAL scheduled, so this entry would stop loading on that release, before a request exists —\n // measured on Deno 2.9.5, where the warning printed on every start. This was the only adapter still\n // on the umbrella; the split below is the mapping four siblings already use and Bun proves by\n // running.\n `import { scanServerRoutes, matchRoute, createProductionLoader, scanWebSocketRoutes } from 'npm:theokit/server/scan'`,\n `import { executeRoute, extractTraceIdFromRequest, TRACE_HEADER, createCorsWebHandler } from 'npm:theokit/server/http'`,\n `import { createWebShim } from 'npm:theokit/adapters/web-shim'`,\n `import { buildSecurityHeaders, withSecurityHeaders } from 'npm:theokit/adapters/security-headers'`,\n `// T3.3 — WS bridge for Deno runtime`,\n `import { createDenoWsBridge } from 'npm:theokit/adapters/ws-shim'`,\n]\n\n/** The target's name, in the five places that spell it. Adding a sixth tripped the duplicate-literal gate. */\n/* The name in the places a gate does NOT read. `assertServicesUnsupported` keeps the literal:\n * `services-other-adapters-reject.test.ts:30` requires each adapter to name ITSELF there, so a\n * copy-paste carrying another adapter's name cannot hide behind a constant. */\nconst TARGET = 'deno-deploy'\n\nexport function renderDenoEntry(port: number, opts: DeployedEntryOptions = {}): string {\n const runtimeConfig = deployedRuntimeConfigFragment(opts)\n const agentsFragment = deployedAgentsFragment(scannedFromLoaderCache(agentsDirLiteral(opts)), {\n notFound: 'notFound()',\n importPrefix: 'npm:',\n // B-185 — bound only when the runtime-config fragment declared the const, which is\n // exactly when a plugins module was emitted. Referencing it otherwise would emit an\n // identifier the entry never declares.\n pluginRunnerExpr:\n opts.runtimeConfigModule === undefined ? undefined : 'await THEO_PLUGIN_RUNNER',\n })\n return [\n `// Generated by Theo — Deno Deploy Adapter`,\n ...DEPLOY_INSTRUCTIONS,\n `// Requires Deno >= 1.40 (Deno.serve + npm: specifier support)`,\n ``,\n `// Runtime guard`,\n `if (typeof Deno === 'undefined') {`,\n ` throw new Error('TheoDenoDeployAdapter must run inside Deno.')`,\n `}`,\n ``,\n ...FRAMEWORK_IMPORTS,\n ``,\n `const port = Number(Deno.env.get('PORT') ?? '${port}')`,\n `const cwd = Deno.cwd()`,\n `const serverDir = cwd + '/' + ${serverDirLiteral(opts)}`,\n `let routesCache = null`,\n `let wsRoutesCache = null`,\n `let loaderCache = null`,\n ``,\n `// #410 — the security baseline \\`theokit start\\` puts on every response,`,\n `// carried here as a literal because the deployed isolate has no`,\n `// theo.config.ts to read. Non-API paths 404 here and are served by Deno`,\n `// Deploy's static asset handler, so this covers the API and not the`,\n `// document (usetheokit/theokit#412).`,\n ...deployedEntryPreamble(runtimeConfig, agentsFragment, opts, TARGET),\n ``,\n `function notFound() {`,\n ` return new Response(JSON.stringify({ error: { code: 'NOT_FOUND' } }), {`,\n ` status: 404,`,\n ` headers: { 'Content-Type': 'application/json' },`,\n ` })`,\n `}`,\n ``,\n // B-027 — `npm:`, like every other specifier this target emits (`:37-43`). A bare one does\n // not resolve on Deno Deploy, and the harness asserts the prefix is here before rewriting it.\n ...(opts.rateLimit === undefined\n ? []\n : [\n `import { createRateLimiterWeb } from 'npm:theokit/server/rate-limit'`,\n `import { resolveClientIpFromRequest } from 'npm:theokit/server/rate-limit'`,\n ``,\n ]),\n ...deployedRateLimitFragment(\n opts.rateLimit,\n TARGET,\n // `info.remoteAddr` is the runtime's own answer. A `UnixAddr` has no `hostname`, so the\n // optional chain is what keeps the read from throwing there rather than a guess.\n `info?.remoteAddr?.hostname ?? resolveClientIpFromRequest(request, TRUST_PROXY)`,\n 'request, info',\n // B-257 — `npm:`, like every other specifier this target emits. A bare one does not resolve\n // on Deno Deploy, and the durable limiter's import is emitted by the fragment rather than\n // here, so the prefix has to travel with it.\n 'npm:',\n ),\n ``,\n // The serve handler's SECOND parameter is bound here for the first time: `Deno.serve` has\n // always passed it and the emitted entry discarded it.\n `Deno.serve({ port }, async (request, info) => {`,\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, info'),\n ``,\n ` // LCR0103 — the upgrade branch sits BELOW the limiter, and the order is the point.`,\n ` // It used to sit above, under the comment \"a 101 carries no document and no script,`,\n ` // so the security baseline does not apply to it\". That is true of the security`,\n ` // HEADERS — a document concern — and false of the limiter, which is a resource`,\n ` // concern: a long-lived socket is the most expensive thing this entry hands out, so`,\n ` // the upgrade is the path that most needs a budget, not the one that may skip it.`,\n ` // T3.3 — Detect WebSocket upgrade and delegate to the Deno bridge.`,\n ` // A 101 carries no document and no script, so the security baseline does`,\n ` // not apply to it.`,\n ` if (request.headers.get('upgrade')?.toLowerCase() === 'websocket') {`,\n ` if (!wsRoutesCache) wsRoutesCache = scanWebSocketRoutes(serverDir)`,\n ` if (wsRoutesCache.length === 0) return notFound()`,\n ` const denoWs = createDenoWsBridge({`,\n ` onOpen: () => {},`,\n ` onMessage: (ws, data) => { ws.send(data) },`,\n ` onClose: () => {},`,\n ` }, Deno)`,\n ` return denoWs.handle(request)`,\n ` }`,\n ` return withCors(request, withSecurityHeaders(await handleRequest(request), SECURITY_HEADERS))`,\n `})`,\n ``,\n `async function handleRequest(request) {`,\n ` const url = new URL(request.url)`,\n ``,\n ` if (!url.pathname.startsWith('/api/')${agentsFragment.hostBypass}) {`,\n ` // Static + SPA fallback are served by Deno Deploy's static asset handler.`,\n ` return notFound()`,\n ` }`,\n ``,\n ` if (!routesCache) routesCache = scanServerRoutes(serverDir)`,\n ` if (!loaderCache) loaderCache = createProductionLoader()`,\n ``,\n ...agentsFragment.branch,\n ``,\n ` const match = matchRoute(url.pathname, routesCache)`,\n ` if (!match) return notFound()`,\n ``,\n ` const { req, res, toResponse } = createWebShim(request)`,\n ...deployedTraceFragment('request', ' '),\n ` const method = request.method.toUpperCase()`,\n ` // #382 — not awaited: toResponse() settles at the headers and carries a`,\n ` // live body, so Deno.serve streams while the handler writes.`,\n ` return toResponse(executeRoute({ route: match.route, method, params: match.params, req, res, loadModule: loaderCache, serverDir, requestId, ...CSRF_CONFIG, ${runtimeConfig.executeRouteSpread} }))`,\n `}`,\n ``,\n `console.log('Theo (Deno Deploy) listening on :' + port)`,\n ].join('\\n')\n}\n\nexport async function buildDeno(\n config: TheoConfig,\n cwd: string,\n deps: DenoBuildDeps = {},\n ctx?: AdapterBuildContext,\n): Promise<void> {\n // Wave 2 (T2.2) — reject polyglot services on this adapter.\n assertServicesUnsupported('deno-deploy', readManifest(cwd))\n\n const runNodeBuild = deps.runNodeBuild ?? nodeAdapter.build.bind(nodeAdapter)\n await runNodeBuild(config, cwd, ctx)\n\n const outputDir = resolve(cwd, DENO_DEPLOY_ENTRY_PATH, '..')\n const ensureDir = deps.ensureDir ?? ((p: string) => mkdirSync(p, { recursive: true }))\n ensureDir(outputDir)\n\n const pluginsPlan = planDeployedPlugins(config.plugins, denoDeployAdapter.name)\n const entry = renderDenoEntry(config.port, {\n securityHeaders: config.security?.headers,\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 // #425 — the ONE concern that is not a literal. A closure cannot be baked, so a plugin\n // declared by module specifier is imported by the emitted module instead; a constructed one\n // is refused by name at build time rather than dropped in silence.\n runtimeConfigModule: pluginsPlan?.moduleSpecifier,\n // #95 — the configured directories, which `build.ts:210` already threads into the Vite\n // plugins. Without these two lines the literals above fall to their defaults and a project\n // with a custom dir deploys an entry that resolves a directory it does not have.\n serverDir: config.serverDir,\n agentsDir: config.agentsDir,\n })\n const write =\n deps.writeEntry ??\n ((p, c) => {\n writeFileSync(p, c)\n })\n if (pluginsPlan !== undefined) {\n // Beside the entry, so the emitted import is a sibling. Written through the same seam as\n // the entry so a test that captures one captures both (#425).\n write(resolve(outputDir, 'theo.plugins.mjs'), pluginsPlan.source)\n }\n write(resolve(cwd, DENO_DEPLOY_ENTRY_PATH), entry)\n\n // The import map and `sloppy-imports`, at the upload root. Measured on the platform: a\n // config in a subdirectory failed the revision, so this path is not a preference.\n const readSources = deps.readProjectSources ?? readProjectSourcesFromDisk\n const readConfig = deps.readDenoConfig ?? readDenoConfigFromDisk\n const denoConfig = renderDenoConfig({\n specifiers: bareSpecifiersOf(readSources(cwd, config)),\n existing: readConfig(cwd),\n })\n write(resolve(cwd, DENO_DEPLOY_CONFIG_PATH), `${JSON.stringify(denoConfig, undefined, 2)}\\n`)\n\n // eslint-disable-next-line no-console -- CLI build progress\n console.log(\n `\\n ✓ Deno Deploy output → ${DENO_DEPLOY_ENTRY_PATH} + ${DENO_DEPLOY_CONFIG_PATH} (${\n Object.keys(denoConfig.imports ?? {}).length\n } specifiers mapped)`,\n )\n // eslint-disable-next-line no-console -- CLI build progress\n console.log(\n `${describeDeployedSecurityHeaders({\n target: TARGET,\n securityHeaders: config.security?.headers,\n mintsNonce: false,\n documentHeaders: 'platform-unmanaged',\n })}\\n`,\n )\n}\n\n/**\n * Where the entry is written, relative to the project root.\n *\n * NOT under `.theokit/`, and that is the whole point: measured against the real platform on\n * 2026-09-30, a dot directory is never uploaded. `./.theokit/deno/probe.ts` failed the\n * revision while the byte-identical file at `./visible/probe.ts` served HTTP 200. An entry\n * the upload cannot see is an entry that cannot run, and the build reported success either\n * way — so nothing short of a deploy could find this.\n *\n * One directory deep, because the upload root has to stay the PROJECT root: the entry scans\n * `<cwd>/src/server` for the project's own route modules, so a deploy rooted anywhere else\n * finds no routes and answers 404 on every path.\n */\nexport const DENO_DEPLOY_ENTRY_PATH = 'theokit-deploy/server.ts'\n\n/** Where the Deno config is written. The upload root, and nowhere else — see below. */\nexport const DENO_DEPLOY_CONFIG_PATH = 'deno.json'\n\n/**\n * The bare specifiers a set of source texts import — the ones needing a registry, in the\n * order they will be emitted.\n *\n * Derived from the project's own sources rather than from `package.json`, because what has\n * to resolve is what is actually imported: a declared dependency nobody imports needs no\n * entry, and a subpath like `theokit/server/define` appears in no manifest at all.\n */\nexport function bareSpecifiersOf(sources: Iterable<string>): string[] {\n const found = new Set<string>()\n for (const source of sources) {\n for (const match of source.matchAll(/(?:from|import)\\s+['\"]([^'\"]+)['\"]/gu)) {\n // `match[1]` and not a guarded read: the capture group is not optional in this pattern,\n // so it participates in every match the loop yields.\n const specifier = match[1]\n // A relative or absolute path resolves on its own; a specifier that already names its\n // registry is not ours to map.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a regex group's type is wider than this pattern\n if (specifier === undefined) continue\n if (/^(?:[./]|npm:|jsr:|node:|data:|https?:)/u.test(specifier)) continue\n found.add(specifier)\n }\n }\n // An explicit comparator: the emitted map is read in diffs, so its order has to be the\n // same on every machine rather than whatever the default collation is.\n return [...found].sort((a, b) => a.localeCompare(b, 'en'))\n}\n\n/** The shape this adapter reads and writes. Anything else in the file is carried through. */\nexport interface DenoConfig {\n imports?: Record<string, string>\n unstable?: string[]\n [key: string]: unknown\n}\n\n/**\n * The Deno config the platform needs, merged onto whatever the project already wrote.\n *\n * Two measured facts decide its whole content:\n *\n * **Each specifier is mapped exactly, never as a prefix.** The emitted entry imports\n * `npm:theokit/...`; the project's own modules import the bare `theokit/server/define`. A\n * trailing-slash prefix cannot bridge them — Deno refuses `\"theokit/\": \"npm:theokit/\"` with\n * *\"its after-prefix portion could not be URL-parsed relative to the URL prefix\"*, because\n * the part after the prefix is not joinable onto an `npm:` URL. Exact entries resolve; the\n * prefix form fails at the first import, at runtime, with a 500.\n *\n * **`sloppy-imports` is declared.** A generated project's own agent modules import siblings\n * with a `.js` extension against files on disk ending `.ts` — six of them in the default\n * template. Deno refuses that pairing and says so: *\"Maybe change the extension to '.ts' or\n * run with --sloppy-imports\"*.\n */\nexport function renderDenoConfig(opts: {\n specifiers: readonly string[]\n existing?: DenoConfig\n}): DenoConfig {\n const config: DenoConfig = { ...(opts.existing ?? {}) }\n const imports: Record<string, string> = { ...(config.imports ?? {}) }\n for (const specifier of opts.specifiers) imports[specifier] = `npm:${specifier}`\n config.imports = imports\n const unstable = [...(config.unstable ?? [])]\n if (!unstable.includes('sloppy-imports')) unstable.push('sloppy-imports')\n config.unstable = unstable\n return config\n}\n\n/**\n * The project's own TypeScript sources, from the directories the entry scans at runtime.\n *\n * Scoped to those directories plus the config file rather than the whole tree: what the map\n * must resolve is what the DEPLOYED code imports, and a specifier reachable only from a test\n * or a build script never runs on the platform.\n */\nfunction readProjectSourcesFromDisk(cwd: string, config: TheoConfig): string[] {\n // No fallback: `config/schema.ts` gives both a zod `.default()`, so a parsed config always\n // carries them — and the defaults are `server`/`agents`, so the `src/`-prefixed guesses this\n // line used to hold would have read the wrong directories on any project that took them.\n const roots = [config.serverDir, config.agentsDir]\n const texts: string[] = []\n for (const root of roots) {\n const dir = resolve(cwd, root)\n if (!existsSync(dir)) continue\n for (const entry of readdirSync(dir, { recursive: true, withFileTypes: true })) {\n if (!entry.isFile()) continue\n if (!/\\.(?:ts|tsx|mts)$/u.test(entry.name)) continue\n if (/\\.(?:test|spec)\\./u.test(entry.name)) continue\n texts.push(readFileSync(resolve(entry.parentPath, entry.name), 'utf8'))\n }\n }\n const themeConfig = resolve(cwd, 'theo.config.ts')\n if (existsSync(themeConfig)) texts.push(readFileSync(themeConfig, 'utf8'))\n return texts\n}\n\nfunction readDenoConfigFromDisk(cwd: string): DenoConfig | undefined {\n const file = resolve(cwd, DENO_DEPLOY_CONFIG_PATH)\n if (!existsSync(file)) return undefined\n try {\n return JSON.parse(readFileSync(file, 'utf8')) as DenoConfig\n } catch {\n // A config we cannot parse is one we must not overwrite blind: returning undefined would\n // replace whatever the project wrote. Refusing here surfaces it at the write site instead.\n throw new Error(\n `${DENO_DEPLOY_CONFIG_PATH} exists and is not valid JSON. Fix or remove it before building for deno-deploy.`,\n )\n }\n}\n\nexport const denoDeployAdapter: DeployAdapter = {\n // Same as `bun`, plus the runtime compiles the TypeScript it finds — which is why a scan that\n // answered `SyntaxError` on netlify is legitimate here. The last runtime scanner in the fleet.\n readsSourceAtRunTime: true,\n specifiersResolvedBy: 'the-project-at-run-time',\n name: 'deno-deploy',\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 isolate returns. The\n // document comes from Deno Deploy's static asset handler and does not pass\n // through it (usetheokit/theokit#412).\n servesAgents: true,\n appliesConfig: ['securityHeaders', 'csrf', 'disallowed', 'cors', 'serialization', 'plugins'],\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 buildDeno(config, cwd, {}, ctx)\n },\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/netlify.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Netlify deploy adapter. All paths derived from `cwd` and a fixed\n * `.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 * 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(`${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(`${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(`${existing}${sep}\\n${THEO_REDIRECT_TARGET}\\n\\n${headersBlock}\\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":"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","names":["sep"]}
|
package/dist/node-4HQO6KKZ.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
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-4HQO6KKZ.js")).nodeAdapter,
|
|
10
|
-
vercel: async () => (await import("./vercel-VLR52RXT.js")).vercelAdapter,
|
|
11
|
-
cloudflare: async () => (await import("./cloudflare-Q5SUXRXY.js")).cloudflareAdapter,
|
|
12
|
-
static: async () => (await import("./static-7LP7LPGN.js")).staticAdapter,
|
|
13
|
-
bun: async () => (await import("./bun-I7YM3RDB.js")).bunAdapter,
|
|
14
|
-
"deno-deploy": async () => (await import("./deno-deploy-XW3Q6OMD.js")).denoDeployAdapter,
|
|
15
|
-
netlify: async () => (await import("./netlify-ALPCTQFO.js")).netlifyAdapter,
|
|
16
|
-
"aws-lambda": async () => (await import("./aws-lambda-ZYSPTD3O.js")).awsLambdaAdapter,
|
|
17
|
-
"theo-cloud": async () => (await import("./theo-cloud-GIA67L4Q.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-WVUO2WNR.js.map
|
/package/dist/{actions-virtual-module-JV7URROJ.js.map → actions-virtual-module-4J7Z37Y4.js.map}
RENAMED
|
File without changes
|
/package/dist/{actions-virtual-module-J2HYO7QZ.js.map → actions-virtual-module-MIQJEHKJ.js.map}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{services-typed-client-XGT5SUUN.js.map → services-typed-client-FOBFCRD6.js.map}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|