theokit 0.54.1 → 0.56.0
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-M4MTKOAX.js → actions-virtual-module-3V7VG2YL.js} +3 -3
- package/dist/{actions-virtual-module-FGJR3I7V.js → actions-virtual-module-KJBCM7PP.js} +21 -21
- package/dist/adapters/agent-mount.d.ts +1 -1
- package/dist/adapters/agent-mount.js +9 -9
- package/dist/{agent-TKCC4WZ6.js → agent-NLG77PFN.js} +3 -3
- package/dist/{agents-typed-client-INR2E7B3.js → agents-typed-client-PVUZU65B.js} +3 -3
- package/dist/{app-typed-client-6MNNVMJU.js → app-typed-client-XSXAORG6.js} +21 -21
- package/dist/{app-typed-client-22BZ3KDX.js → app-typed-client-ZO3VKJ3O.js} +3 -3
- package/dist/boot/index.js +3 -3
- package/dist/{build-JH53TZJI.js → build-4GQLIFTD.js} +5 -4
- package/dist/build-4GQLIFTD.js.map +1 -0
- package/dist/{bun-L7PP6ID5.js → bun-POLTY2HK.js} +118 -3
- package/dist/bun-POLTY2HK.js.map +1 -0
- package/dist/{chunk-IHAQUUT2.js → chunk-22ZZSUKD.js} +2 -2
- package/dist/chunk-22ZZSUKD.js.map +1 -0
- package/dist/{chunk-5YPXXSYY.js → chunk-35QIWOHT.js} +9 -8
- package/dist/chunk-35QIWOHT.js.map +1 -0
- package/dist/{chunk-JDN5SAAD.js → chunk-44E7XIZC.js} +6 -6
- package/dist/{chunk-OQCRCXCP.js → chunk-4ERYQBL6.js} +2 -2
- package/dist/{chunk-52PDWL5S.js → chunk-5KRMDP46.js} +2 -2
- package/dist/{chunk-HLDXHDCB.js → chunk-5TPBOAAH.js} +8 -8
- package/dist/{chunk-6VYF5PMG.js → chunk-6PFF5HMY.js} +3 -3
- package/dist/{chunk-VQPHPQ5L.js → chunk-7NRFZBAL.js} +3 -3
- package/dist/{chunk-3PBAN2YE.js → chunk-CF2DNN5R.js} +9 -8
- package/dist/{chunk-3PBAN2YE.js.map → chunk-CF2DNN5R.js.map} +1 -1
- package/dist/{chunk-HK4AZBKX.js → chunk-D5KBBTVD.js} +7 -7
- package/dist/{chunk-BU6RJPPJ.js → chunk-GO7UWJ47.js} +2 -2
- package/dist/{chunk-BU6RJPPJ.js.map → chunk-GO7UWJ47.js.map} +1 -1
- package/dist/{chunk-VZTYCAO6.js → chunk-IDEZ7FU2.js} +3 -3
- package/dist/{chunk-FVFYACYK.js → chunk-JW5UFKQ3.js} +17 -17
- package/dist/chunk-JW5UFKQ3.js.map +1 -0
- package/dist/{chunk-IRASEXOG.js → chunk-KDP2HURW.js} +6 -6
- package/dist/{chunk-AI7GBBRB.js → chunk-KQ27YDLG.js} +8 -8
- package/dist/{chunk-WX6NHGKS.js → chunk-M357ILK5.js} +10 -10
- package/dist/{chunk-ZQO37YQJ.js → chunk-PELXWPDF.js} +5 -5
- package/dist/{chunk-2OEN3YTE.js → chunk-PVNMLZ5G.js} +2 -2
- package/dist/{chunk-5K4TDLRG.js → chunk-SOYOYGWY.js} +3 -3
- package/dist/{chunk-SIGUGCBS.js → chunk-TUO2FE3S.js} +3 -3
- package/dist/{chunk-4X6H2BXP.js → chunk-U3SPBLJF.js} +3 -3
- package/dist/{chunk-BX6EUYHU.js → chunk-V6Y2SMRG.js} +3 -3
- package/dist/{chunk-I2UN46ZX.js → chunk-XJOU425Y.js} +17 -17
- package/dist/{chunk-DAE7BJ7H.js → chunk-XYVZJCZU.js} +4 -4
- package/dist/{chunk-BND4YZTQ.js → chunk-ZDCCILMP.js} +2 -2
- package/dist/{chunk-S6RWUH3J.js → chunk-ZTIB4QSV.js} +63 -63
- package/dist/cli/index.js +6 -6
- package/dist/{config-support-WQHQIJTA.js → config-support-O4REYSK5.js} +32 -1
- package/dist/{config-support-WQHQIJTA.js.map → config-support-O4REYSK5.js.map} +1 -1
- package/dist/{controller-swc-transform-T7ZTD55V.js → controller-swc-transform-7EZKG2IS.js} +2 -2
- package/dist/cost-types-BALTuBpG.d.ts +79 -0
- package/dist/{dev-6KDYNF5E.js → dev-ZNTHPBBN.js} +5 -5
- package/dist/{dev-emit-W27J3DLU.js → dev-emit-FIQASO3D.js} +7 -7
- package/dist/index.js +23 -23
- package/dist/{internal-api-TA37BXH7.js → internal-api-D76JZGSC.js} +3 -3
- package/dist/{internal-api-VUDJUWYE.js → internal-api-JNX3MTIM.js} +26 -26
- package/dist/{mcp-2RQCKWQR.js → mcp-IMY3NUCL.js} +3 -3
- package/dist/{preview-J57QZNTO.js → preview-K4NIQLAK.js} +3 -3
- package/dist/{provider-resolver-Dx6QuWrw.d.ts → provider-resolver-VS61zqsw.d.ts} +0 -11
- package/dist/{registry-KBZDCFVQ.js → registry-3LUHO4IB.js} +2 -2
- package/dist/server/agent/index.d.ts +1 -1
- package/dist/server/agent/index.js +3 -3
- package/dist/server/cost/index.d.ts +3 -80
- package/dist/server/cost/sqlite/index.d.ts +21 -0
- package/dist/server/cost/sqlite/index.js +102 -0
- package/dist/server/cost/sqlite/index.js.map +1 -0
- package/dist/server/cron/index.js +4 -4
- package/dist/server/http/index.js +7 -7
- package/dist/server/index.d.ts +5 -4
- package/dist/server/index.js +79 -79
- package/dist/server/jobs/index.d.ts +2 -2
- package/dist/server/jobs/index.js +4 -4
- package/dist/server/observability/index.js +2 -2
- package/dist/server/scan/index.js +6 -6
- package/dist/server/storage/index.d.ts +2 -2
- package/dist/server/webhook/index.js +1 -1
- package/dist/{server-boundary-4UIGB3G5.js → server-boundary-654WC5SA.js} +23 -23
- package/dist/{server-boundary-A2PUD4JV.js → server-boundary-NW6LNNGK.js} +3 -3
- package/dist/{server-routes-hmr-BWN3WIGR.js → server-routes-hmr-TNI3FNGM.js} +2 -2
- package/dist/{services-typed-client-IXNOPVZA.js → services-typed-client-ACTJHAEP.js} +2 -2
- package/dist/{start-3F4LVHWS.js → start-ONZXIWEG.js} +4 -4
- package/dist/{storage-manager-C6hmsaer.d.ts → storage-manager-BtG38jYl.d.ts} +1 -1
- package/dist/{storage-types-DsDTCPbp.d.ts → storage-types-CFGPFIdB.d.ts} +1 -1
- package/dist/vite-plugin/index.js +21 -21
- package/dist/{vite-plugin-VYNUCEI2.js → vite-plugin-UET2BUFW.js} +5 -5
- package/package.json +7 -3
- package/dist/build-JH53TZJI.js.map +0 -1
- package/dist/bun-L7PP6ID5.js.map +0 -1
- package/dist/chunk-5YPXXSYY.js.map +0 -1
- package/dist/chunk-FVFYACYK.js.map +0 -1
- package/dist/chunk-IHAQUUT2.js.map +0 -1
- /package/dist/{actions-virtual-module-M4MTKOAX.js.map → actions-virtual-module-3V7VG2YL.js.map} +0 -0
- /package/dist/{actions-virtual-module-FGJR3I7V.js.map → actions-virtual-module-KJBCM7PP.js.map} +0 -0
- /package/dist/{agent-TKCC4WZ6.js.map → agent-NLG77PFN.js.map} +0 -0
- /package/dist/{agents-typed-client-INR2E7B3.js.map → agents-typed-client-PVUZU65B.js.map} +0 -0
- /package/dist/{app-typed-client-6MNNVMJU.js.map → app-typed-client-XSXAORG6.js.map} +0 -0
- /package/dist/{app-typed-client-22BZ3KDX.js.map → app-typed-client-ZO3VKJ3O.js.map} +0 -0
- /package/dist/{chunk-JDN5SAAD.js.map → chunk-44E7XIZC.js.map} +0 -0
- /package/dist/{chunk-OQCRCXCP.js.map → chunk-4ERYQBL6.js.map} +0 -0
- /package/dist/{chunk-52PDWL5S.js.map → chunk-5KRMDP46.js.map} +0 -0
- /package/dist/{chunk-HLDXHDCB.js.map → chunk-5TPBOAAH.js.map} +0 -0
- /package/dist/{chunk-6VYF5PMG.js.map → chunk-6PFF5HMY.js.map} +0 -0
- /package/dist/{chunk-VQPHPQ5L.js.map → chunk-7NRFZBAL.js.map} +0 -0
- /package/dist/{chunk-HK4AZBKX.js.map → chunk-D5KBBTVD.js.map} +0 -0
- /package/dist/{chunk-VZTYCAO6.js.map → chunk-IDEZ7FU2.js.map} +0 -0
- /package/dist/{chunk-IRASEXOG.js.map → chunk-KDP2HURW.js.map} +0 -0
- /package/dist/{chunk-AI7GBBRB.js.map → chunk-KQ27YDLG.js.map} +0 -0
- /package/dist/{chunk-WX6NHGKS.js.map → chunk-M357ILK5.js.map} +0 -0
- /package/dist/{chunk-ZQO37YQJ.js.map → chunk-PELXWPDF.js.map} +0 -0
- /package/dist/{chunk-2OEN3YTE.js.map → chunk-PVNMLZ5G.js.map} +0 -0
- /package/dist/{chunk-5K4TDLRG.js.map → chunk-SOYOYGWY.js.map} +0 -0
- /package/dist/{chunk-SIGUGCBS.js.map → chunk-TUO2FE3S.js.map} +0 -0
- /package/dist/{chunk-4X6H2BXP.js.map → chunk-U3SPBLJF.js.map} +0 -0
- /package/dist/{chunk-BX6EUYHU.js.map → chunk-V6Y2SMRG.js.map} +0 -0
- /package/dist/{chunk-I2UN46ZX.js.map → chunk-XJOU425Y.js.map} +0 -0
- /package/dist/{chunk-DAE7BJ7H.js.map → chunk-XYVZJCZU.js.map} +0 -0
- /package/dist/{chunk-BND4YZTQ.js.map → chunk-ZDCCILMP.js.map} +0 -0
- /package/dist/{chunk-S6RWUH3J.js.map → chunk-ZTIB4QSV.js.map} +0 -0
- /package/dist/{controller-swc-transform-T7ZTD55V.js.map → controller-swc-transform-7EZKG2IS.js.map} +0 -0
- /package/dist/{dev-6KDYNF5E.js.map → dev-ZNTHPBBN.js.map} +0 -0
- /package/dist/{dev-emit-W27J3DLU.js.map → dev-emit-FIQASO3D.js.map} +0 -0
- /package/dist/{internal-api-TA37BXH7.js.map → internal-api-D76JZGSC.js.map} +0 -0
- /package/dist/{internal-api-VUDJUWYE.js.map → internal-api-JNX3MTIM.js.map} +0 -0
- /package/dist/{mcp-2RQCKWQR.js.map → mcp-IMY3NUCL.js.map} +0 -0
- /package/dist/{preview-J57QZNTO.js.map → preview-K4NIQLAK.js.map} +0 -0
- /package/dist/{registry-KBZDCFVQ.js.map → registry-3LUHO4IB.js.map} +0 -0
- /package/dist/{server-boundary-4UIGB3G5.js.map → server-boundary-654WC5SA.js.map} +0 -0
- /package/dist/{server-boundary-A2PUD4JV.js.map → server-boundary-NW6LNNGK.js.map} +0 -0
- /package/dist/{server-routes-hmr-BWN3WIGR.js.map → server-routes-hmr-TNI3FNGM.js.map} +0 -0
- /package/dist/{services-typed-client-IXNOPVZA.js.map → services-typed-client-ACTJHAEP.js.map} +0 -0
- /package/dist/{start-3F4LVHWS.js.map → start-ONZXIWEG.js.map} +0 -0
- /package/dist/{vite-plugin-VYNUCEI2.js.map → vite-plugin-UET2BUFW.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/bun.ts","../src/adapters/deployed-rate-limit.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 { deployedCorsFragment, type DeployedCorsOptions } from './deployed-cors.js'\nimport { deployedCsrfFragment, type DeployedCsrfOptions } from './deployed-csrf.js'\nimport { planDeployedPlugins } from './deployed-plugins-module.js'\nimport {\n deployedRateLimitFragment,\n rateLimitCheckFragment,\n type DeployedRateLimitOptions,\n} from './deployed-rate-limit.js'\nimport {\n deployedRuntimeConfigFragment,\n type DeployedRuntimeConfigOptions,\n} from './deployed-runtime-config.js'\nimport { deployedTraceFragment } from './deployed-trace.js'\nimport { nodeAdapter } from './node.js'\nimport {\n describeDeployedSecurityHeaders,\n renderSecurityHeadersConfigLiteral,\n} 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\nexport function renderBunEntry(\n port: number,\n opts: {\n ssrStreaming?: boolean\n securityHeaders?: SecurityHeadersConfig\n } & DeployedCsrfOptions &\n DeployedRuntimeConfigOptions &\n DeployedCorsOptions &\n DeployedRateLimitOptions = {},\n): string {\n const streamingComment = opts.ssrStreaming\n ? `// T2.3 — ssrStreaming on; renderStreamingWeb may be consumed by app code`\n : `// (ssrStreaming off)`\n const runtimeConfig = deployedRuntimeConfigFragment(opts)\n const agentsFragment = deployedAgentsFragment(\n { kind: 'scan', projectRoot: 'cwd', loadModule: 'loadModule' },\n { pathname: 'pathname' },\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 `// 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 `import { resolve, join } from 'node:path'`,\n `import { existsSync } from 'node:fs'`,\n `import { scanServerRoutes, matchRoute, executeRoute, createProductionLoader, extractTraceIdFromRequest, TRACE_HEADER, createCorsWebHandler${opts.rateLimit === undefined ? '' : ', createRateLimiterWeb'} } from 'theokit/server'`,\n `import { createWebShim } from 'theokit/adapters/web-shim'`,\n `import { buildSecurityHeaders, withSecurityHeaders } from 'theokit/adapters/security-headers'`,\n `// T3.2 — WS bridge for Bun runtime`,\n `import { createBunWsBridge } from 'theokit/adapters/ws-shim'`,\n `import { scanWebSocketRoutes } from 'theokit/server'`,\n ``,\n `const cwd = process.cwd()`,\n `const clientDir = resolve(cwd, '.theokit/client')`,\n `const serverDir = resolve(cwd, 'server')`,\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 `const SECURITY_HEADERS_CONFIG = ${renderSecurityHeadersConfigLiteral(opts.securityHeaders)}`,\n `const SECURITY_HEADERS = buildSecurityHeaders(SECURITY_HEADERS_CONFIG, { production: true })`,\n ``,\n ...runtimeConfig.imports,\n ...agentsFragment.imports,\n ...runtimeConfig.declarations,\n ...agentsFragment.declarations,\n ...deployedCsrfFragment(opts),\n ``,\n ...deployedCorsFragment(opts.cors, '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),\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(runtimeSpread: string, agentBranch: readonly string[]): 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 ` 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 ` // 2) API routes through the full executeRoute pipeline via the shim`,\n ` if (pathname.startsWith('/api/')) {`,\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 ` // 3) SPA fallback`,\n ` const indexPath = join(clientDir, 'index.html')`,\n ` if (existsSync(indexPath)) return new Response(Bun.file(indexPath))`,\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 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 })\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 // No deploy target other than the streamed Cloudflare worker renders HTML\n // at request time, so none of the rest can mint a nonce.\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 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 build(config, cwd, ctx) {\n return buildBun(config, cwd, {}, ctx)\n },\n}\n","/**\n * The rate limit a deployed entry carries, baked at build time.\n *\n * ## What #508 asked for, and what this answers\n *\n * `theokit build` refuses the six Web-standards targets when `theo.config.ts` declares a\n * `rateLimit` (`UnenforceableRateLimitError`). That refusal is honest and it is not enforcement.\n * The issue names three things standing between the refusal and a working limit: per-runtime\n * caller-address resolution, a refusal that survives where the address cannot be resolved, and\n * storage that outlives one invocation.\n *\n * For `bun` all three already have answers, which is why it is the target that moves first:\n *\n * - **Address** — `Bun.serve`'s handler is `fetch(request, server)`, and `server.requestIP(request)`\n * returns the peer address without depending on a proxy header a client could set.\n * - **Storage** — `Bun.serve` is a long-lived process. `createRateLimiterWeb`'s default\n * `InMemoryStore` therefore behaves exactly as it does under `theokit start`, which is the\n * deployment `node` already ships.\n * - **Refusal** — see below: every shape whose key cannot be resolved in a deployed entry throws\n * at BUILD time rather than degrading.\n *\n * ## Why the other five are not here\n *\n * Cloudflare, AWS Lambda, Netlify and Vercel are per-invocation runtimes: an in-process counter\n * does not survive between requests, so a limiter built on one forgets. A limit that forgets is a\n * limit that does not limit — the same class of failure as the shared bucket, reached by a\n * different road. Deno Deploy evicts isolates for the same reason. Those need an external counter,\n * which is a storage design and not a wiring change, so they keep refusing by name.\n *\n * Being explicit about that boundary is the point. The failure this whole area exists to prevent is\n * a config that reads as protection while protecting nothing.\n */\nimport type { TheoConfig } from '../config/schema.js'\n\ntype RateLimitConfig = NonNullable<TheoConfig['rateLimit']>\n\n/** The rate-limit slice of an adapter's build options, named once like `DeployedCorsOptions`. */\nexport interface DeployedRateLimitOptions {\n rateLimit?: RateLimitConfig\n}\n\n/**\n * Thrown at BUILD time when a declared rate limit cannot be carried into a deployed entry.\n *\n * Distinct from {@link UnenforceableRateLimitError}, and the distinction is not cosmetic: that one\n * means *this target enforces no limit at all*, this one means *this target enforces limits, and\n * cannot carry THIS one*. An operator reading the first looks for another target; an operator\n * reading the second changes the key.\n */\nexport class UnserialisableRateLimitError extends Error {\n override readonly name = 'UnserialisableRateLimitError'\n constructor(\n readonly target: string,\n readonly reason: string,\n ways: readonly string[],\n ) {\n super(\n [\n `Refusing to build for \\`${target}\\`: theo.config.ts declares a rate limit this target cannot carry.`,\n ``,\n ` ${reason}`,\n ``,\n ` Ways forward:`,\n ...ways.map((w) => ` • ${w}`),\n ``,\n ` This refuses rather than dropping the key, because a rate limit that silently does not`,\n ` apply looks exactly like one that does (usetheokit/theokit#461, #508).`,\n ].join('\\n'),\n )\n }\n}\n\n/** The base shape every accepted config narrows to: a window, a ceiling, and an IP key. */\ninterface BakeableRateLimit {\n windowMs: number\n max: number\n}\n\n/**\n * Narrow a declared rate limit to what a deployed entry can actually enforce, or refuse by name.\n *\n * Accepts the base `{ windowMs, max }` and the explicit `keyBy: 'ip'`, which is what the address\n * resolution below can key. Everything else throws:\n *\n * - a **function** `keyBy` has no literal — the same wall `deployed-cors.ts` hits on a callback\n * origin, and refused for the same reason;\n * - `keyBy: 'session' | 'user'` needs a session the deployed entry does not resolve at the point\n * the limit runs, which is before routing;\n * - `routes` needs the matched route, decided after this check. Refusing it is honest today and is\n * the natural next slice.\n */\nfunction bakeableRateLimit(\n rateLimit: RateLimitConfig | undefined,\n target: string,\n): BakeableRateLimit | undefined {\n if (rateLimit === undefined) return undefined\n const cfg = rateLimit as Record<string, unknown>\n\n if (typeof cfg.keyBy === 'function') {\n throw new UnserialisableRateLimitError(\n target,\n '`security.rateLimit.keyBy` is a function, and a deployed entry has no literal for a closure.',\n [\n \"use `keyBy: 'ip'` (the default), which this target resolves from the connection\",\n 'build for `node` and run `theokit start`, which can call the function',\n ],\n )\n }\n if (cfg.keyBy === 'session' || cfg.keyBy === 'user') {\n throw new UnserialisableRateLimitError(\n target,\n `\\`security.rateLimit.keyBy: '${cfg.keyBy}'\\` needs a resolved session, and the limit runs before routing.`,\n [\n \"use `keyBy: 'ip'`, which is resolvable at that point\",\n 'build for `node` and run `theokit start`',\n ],\n )\n }\n if (cfg.routes !== undefined) {\n throw new UnserialisableRateLimitError(\n target,\n '`security.rateLimit.routes` needs the matched route, which is decided after the limit runs here.',\n [\n 'declare a single global limit (`windowMs` + `max`)',\n 'build for `node` and run `theokit start`, which applies per-route limits',\n ],\n )\n }\n\n const windowMs = cfg.windowMs\n const max = cfg.max\n if (typeof windowMs !== 'number' || typeof max !== 'number') return undefined\n return { windowMs, max }\n}\n\n/**\n * The generated declarations and helper for a target that keys on the connection's peer address.\n *\n * `addressExpression` is the per-runtime half the issue calls out — the one thing that genuinely\n * differs between targets. Bun passes `server`; a future Deno slice would pass its\n * `ServeHandlerInfo`. Everything else here is shared.\n *\n * Returns `[]` when nothing was declared, so an app without a limit emits no limiter at all rather\n * than an inert one.\n */\nexport function deployedRateLimitFragment(\n rateLimit: RateLimitConfig | undefined,\n target: string,\n addressExpression: string,\n): string[] {\n const baked = bakeableRateLimit(rateLimit, target)\n if (baked === undefined) return []\n return [\n `// #508 — the limit the app declared, carried as a literal because a deployed entry has no`,\n `// theo.config.ts to read. The counter lives in this process, which outlives a request here.`,\n `const RATE_LIMIT = createRateLimiterWeb({ windowMs: ${baked.windowMs}, max: ${baked.max} })`,\n ``,\n `/**`,\n ` * The caller's address, from the connection rather than from a header.`,\n ` *`,\n ` * A header a client can set is a key a client can choose, which makes the bucket theirs to`,\n ` * split. An unresolved address falls back to one shared bucket — rare here, since that only`,\n ` * happens for a connection already gone, and the same fallback \\`theokit start\\` uses.`,\n ` */`,\n `function callerAddress(request, server) {`,\n ` return ${addressExpression} ?? 'unknown'`,\n `}`,\n ``,\n `/** The 429 a limited caller gets, carrying the limiter's own headers. */`,\n `function rateLimited(result) {`,\n ` return new Response(JSON.stringify({ error: { code: 'RATE_LIMITED', message: 'Too many requests' } }), {`,\n ` status: 429,`,\n ` headers: { 'Content-Type': 'application/json', ...result.headers },`,\n ` })`,\n `}`,\n ]\n}\n\n/**\n * The check itself, as generated source, placed inside the runtime's request handler.\n *\n * Extracted for the reason `bun.ts` extracts its other fragments: the emitter is one array literal,\n * so every line the entry gains counts against `max-lines-per-function`, and this one pushed it\n * past the ceiling.\n *\n * Runs AFTER the CORS preflight and BEFORE routing: a limited caller should not reach a handler,\n * and a browser still needs its CORS answer to read the 429 as a 429 rather than as a network\n * failure.\n */\nexport function rateLimitCheckFragment(\n rateLimit: RateLimitConfig | undefined,\n indent: string,\n): string[] {\n if (rateLimit === undefined) return []\n return [\n `${indent}const limit = RATE_LIMIT(callerAddress(request, server))`,\n `${indent}if (limit.limited) {`,\n `${indent} return withCors(request, withSecurityHeaders(rateLimited(limit), SECURITY_HEADERS))`,\n `${indent}}`,\n ]\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import "tsx/esm";
|
|
3
3
|
import {
|
|
4
4
|
getApprovalRegistry
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-35QIWOHT.js";
|
|
6
6
|
import {
|
|
7
7
|
createWebRequestSource,
|
|
8
8
|
dispatchCsrfWarn,
|
|
@@ -2616,4 +2616,4 @@ export {
|
|
|
2616
2616
|
CsrfReadinessStore,
|
|
2617
2617
|
applySecurityHeaders
|
|
2618
2618
|
};
|
|
2619
|
-
//# sourceMappingURL=chunk-
|
|
2619
|
+
//# sourceMappingURL=chunk-22ZZSUKD.js.map
|