theokit 0.68.0 → 0.70.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.
Files changed (145) hide show
  1. package/README.md +21 -0
  2. package/dist/{actions-virtual-module-SE44BKR4.js → actions-virtual-module-ICWX5PZ2.js} +8 -8
  3. package/dist/{actions-virtual-module-3OPYLD76.js → actions-virtual-module-LY6VGJZ2.js} +5 -5
  4. package/dist/adapters/agent-mount.d.ts +191 -3
  5. package/dist/adapters/agent-mount.js +19 -4
  6. package/dist/adapters/security-headers.d.ts +17 -1
  7. package/dist/adapters/security-headers.js +7 -0
  8. package/dist/adapters/security-headers.js.map +1 -1
  9. package/dist/{agent-UBDDP2L5.js → agent-7DQ3TKJY.js} +4 -4
  10. package/dist/agent-scan-BLXaFL6R.d.ts +12 -0
  11. package/dist/{app-typed-client-BE3PV3JY.js → app-typed-client-2S76VTMB.js} +5 -5
  12. package/dist/{app-typed-client-RAFEBA7S.js → app-typed-client-6YQREFRS.js} +8 -8
  13. package/dist/{aws-lambda-R76PWR27.js → aws-lambda-OCJM5YGB.js} +35 -23
  14. package/dist/aws-lambda-OCJM5YGB.js.map +1 -0
  15. package/dist/{build-U4HVYY6F.js → build-NIHGHPYS.js} +12 -7
  16. package/dist/build-NIHGHPYS.js.map +1 -0
  17. package/dist/{bun-NPBIAWSU.js → bun-KRUAWYRW.js} +51 -39
  18. package/dist/bun-KRUAWYRW.js.map +1 -0
  19. package/dist/{chunk-GQNBZDYK.js → chunk-2FHNJ7LI.js} +1 -1
  20. package/dist/{chunk-GQNBZDYK.js.map → chunk-2FHNJ7LI.js.map} +1 -1
  21. package/dist/chunk-3NAKOWTX.js +573 -0
  22. package/dist/chunk-3NAKOWTX.js.map +1 -0
  23. package/dist/chunk-4D4YVXHR.js +816 -0
  24. package/dist/chunk-4D4YVXHR.js.map +1 -0
  25. package/dist/{chunk-G2NWAVGG.js → chunk-5XXXJ6DT.js} +65 -6
  26. package/dist/chunk-5XXXJ6DT.js.map +1 -0
  27. package/dist/{chunk-CO7Q75IS.js → chunk-6SK4MX2N.js} +10 -10
  28. package/dist/{chunk-UETVDZBE.js → chunk-BINRCILF.js} +4 -1
  29. package/dist/{chunk-UETVDZBE.js.map → chunk-BINRCILF.js.map} +1 -1
  30. package/dist/{chunk-AROOYXI5.js → chunk-BTDTHXUI.js} +2 -2
  31. package/dist/{chunk-GP6OJBXP.js → chunk-CPXIYCAY.js} +2 -2
  32. package/dist/chunk-FFGP2LGQ.js +465 -0
  33. package/dist/chunk-FFGP2LGQ.js.map +1 -0
  34. package/dist/{chunk-KDP2HURW.js → chunk-FHQP23Z5.js} +10 -2
  35. package/dist/{chunk-KDP2HURW.js.map → chunk-FHQP23Z5.js.map} +1 -1
  36. package/dist/{chunk-BCFA6LHL.js → chunk-GVJFVBCJ.js} +2 -2
  37. package/dist/{chunk-LADTWXOB.js → chunk-H5KSRGRS.js} +43 -554
  38. package/dist/chunk-H5KSRGRS.js.map +1 -0
  39. package/dist/{chunk-ENRT6DAU.js → chunk-IDWN2OSG.js} +15 -2
  40. package/dist/chunk-IDWN2OSG.js.map +1 -0
  41. package/dist/{chunk-GDF2XQOO.js → chunk-JMN4COMK.js} +5 -3
  42. package/dist/chunk-JMN4COMK.js.map +1 -0
  43. package/dist/{chunk-Q7T3UQ4L.js → chunk-KOG5K26V.js} +16 -738
  44. package/dist/chunk-KOG5K26V.js.map +1 -0
  45. package/dist/{chunk-FYYKMPST.js → chunk-MLF25NC4.js} +4 -4
  46. package/dist/{chunk-7THO4PRL.js → chunk-PGDBSK2L.js} +33 -11
  47. package/dist/chunk-PGDBSK2L.js.map +1 -0
  48. package/dist/{chunk-5NNFO7R7.js → chunk-R7G2B2WH.js} +10 -2
  49. package/dist/chunk-R7G2B2WH.js.map +1 -0
  50. package/dist/{chunk-GAJOZJWD.js → chunk-SX7ZAHNE.js} +15 -2
  51. package/dist/chunk-SX7ZAHNE.js.map +1 -0
  52. package/dist/chunk-V5SSTT3C.js +52 -0
  53. package/dist/chunk-V5SSTT3C.js.map +1 -0
  54. package/dist/chunk-XG6SQUEP.js +27 -0
  55. package/dist/chunk-XG6SQUEP.js.map +1 -0
  56. package/dist/{chunk-QGNSZ2ZK.js → chunk-YWWMYEAC.js} +3 -3
  57. package/dist/cli/index.js +7 -7
  58. package/dist/client/index.d.ts +20 -0
  59. package/dist/client/index.js.map +1 -1
  60. package/dist/{cloudflare-5HU56XIH.js → cloudflare-GK4VD3EU.js} +36 -13
  61. package/dist/cloudflare-GK4VD3EU.js.map +1 -0
  62. package/dist/{define-middleware-D2n71Svm.d.ts → define-middleware-BOHpPOBs.d.ts} +1 -1
  63. package/dist/{deno-deploy-BXOQ45LD.js → deno-deploy-WMNXRVGL.js} +37 -36
  64. package/dist/deno-deploy-WMNXRVGL.js.map +1 -0
  65. package/dist/{dev-E3USPAWQ.js → dev-KKO3JIN7.js} +7 -7
  66. package/dist/{dev-emit-ZLB2J5ME.js → dev-emit-23AA3V64.js} +3 -3
  67. package/dist/{dev-emit-7RT624PM.js → dev-emit-UJJXY3ET.js} +3 -3
  68. package/dist/{index-B9iVBHJI.d.ts → index-inRdhi59.d.ts} +39 -4
  69. package/dist/index.js +9 -8
  70. package/dist/index.js.map +1 -1
  71. package/dist/{internal-api-OOTVIOH2.js → internal-api-HUIBRF2X.js} +5 -5
  72. package/dist/{internal-api-VAKXXW6F.js → internal-api-S72T2XKD.js} +10 -9
  73. package/dist/match-DaKsL73w.d.ts +28 -0
  74. package/dist/{mcp-7UOQM4FW.js → mcp-I6MCW6KX.js} +4 -4
  75. package/dist/{match-Dw4CNXJH.d.ts → module-loader-DCip7NoL.d.ts} +1 -28
  76. package/dist/{netlify-LPJAPMQ2.js → netlify-VOL54SC7.js} +23 -20
  77. package/dist/netlify-VOL54SC7.js.map +1 -0
  78. package/dist/{openapi-SKKXWFX4.js → openapi-24PTE7P6.js} +3 -3
  79. package/dist/{preview-GPMF43QX.js → preview-EOL3LMK7.js} +3 -3
  80. package/dist/{registry-UOWTDUFL.js → registry-DDBXDHJ2.js} +7 -7
  81. package/dist/server/cost/index.d.ts +14 -1
  82. package/dist/server/cost/index.js +1 -1
  83. package/dist/server/define/index.d.ts +1 -1
  84. package/dist/server/define/index.js +2 -3
  85. package/dist/server/http/index.d.ts +4 -3
  86. package/dist/server/http/index.js +13 -8
  87. package/dist/server/index.d.ts +6 -5
  88. package/dist/server/index.js +17 -12
  89. package/dist/server/index.js.map +1 -1
  90. package/dist/server/scan/index.d.ts +4 -3
  91. package/dist/server/scan/index.js +2 -2
  92. package/dist/{server-boundary-A3HW27C7.js → server-boundary-ERBSHRHT.js} +5 -5
  93. package/dist/{server-boundary-V6PCM22J.js → server-boundary-I5XWYINJ.js} +8 -8
  94. package/dist/{start-6WEPXA3X.js → start-OD4DG4C6.js} +6 -6
  95. package/dist/{vercel-YUZADKGV.js → vercel-LZTDSDJF.js} +42 -28
  96. package/dist/vercel-LZTDSDJF.js.map +1 -0
  97. package/dist/vite-plugin/index.js +9 -8
  98. package/dist/{vite-plugin-WBF5NXGW.js → vite-plugin-SH3VGQEE.js} +7 -7
  99. package/package.json +4 -4
  100. package/dist/agent-scan-BZa-pagG.d.ts +0 -16
  101. package/dist/aws-lambda-R76PWR27.js.map +0 -1
  102. package/dist/build-U4HVYY6F.js.map +0 -1
  103. package/dist/bun-NPBIAWSU.js.map +0 -1
  104. package/dist/chunk-5NNFO7R7.js.map +0 -1
  105. package/dist/chunk-6B3CMPE4.js +0 -192
  106. package/dist/chunk-6B3CMPE4.js.map +0 -1
  107. package/dist/chunk-7L7LQ2GU.js +0 -16
  108. package/dist/chunk-7L7LQ2GU.js.map +0 -1
  109. package/dist/chunk-7THO4PRL.js.map +0 -1
  110. package/dist/chunk-ENRT6DAU.js.map +0 -1
  111. package/dist/chunk-G2NWAVGG.js.map +0 -1
  112. package/dist/chunk-GAJOZJWD.js.map +0 -1
  113. package/dist/chunk-GDF2XQOO.js.map +0 -1
  114. package/dist/chunk-LADTWXOB.js.map +0 -1
  115. package/dist/chunk-O55RLSGG.js +0 -127
  116. package/dist/chunk-O55RLSGG.js.map +0 -1
  117. package/dist/chunk-Q7T3UQ4L.js.map +0 -1
  118. package/dist/cloudflare-5HU56XIH.js.map +0 -1
  119. package/dist/deno-deploy-BXOQ45LD.js.map +0 -1
  120. package/dist/netlify-LPJAPMQ2.js.map +0 -1
  121. package/dist/vercel-YUZADKGV.js.map +0 -1
  122. /package/dist/{actions-virtual-module-SE44BKR4.js.map → actions-virtual-module-ICWX5PZ2.js.map} +0 -0
  123. /package/dist/{actions-virtual-module-3OPYLD76.js.map → actions-virtual-module-LY6VGJZ2.js.map} +0 -0
  124. /package/dist/{agent-UBDDP2L5.js.map → agent-7DQ3TKJY.js.map} +0 -0
  125. /package/dist/{app-typed-client-BE3PV3JY.js.map → app-typed-client-2S76VTMB.js.map} +0 -0
  126. /package/dist/{app-typed-client-RAFEBA7S.js.map → app-typed-client-6YQREFRS.js.map} +0 -0
  127. /package/dist/{chunk-CO7Q75IS.js.map → chunk-6SK4MX2N.js.map} +0 -0
  128. /package/dist/{chunk-AROOYXI5.js.map → chunk-BTDTHXUI.js.map} +0 -0
  129. /package/dist/{chunk-GP6OJBXP.js.map → chunk-CPXIYCAY.js.map} +0 -0
  130. /package/dist/{chunk-BCFA6LHL.js.map → chunk-GVJFVBCJ.js.map} +0 -0
  131. /package/dist/{chunk-FYYKMPST.js.map → chunk-MLF25NC4.js.map} +0 -0
  132. /package/dist/{chunk-QGNSZ2ZK.js.map → chunk-YWWMYEAC.js.map} +0 -0
  133. /package/dist/{dev-E3USPAWQ.js.map → dev-KKO3JIN7.js.map} +0 -0
  134. /package/dist/{dev-emit-ZLB2J5ME.js.map → dev-emit-23AA3V64.js.map} +0 -0
  135. /package/dist/{dev-emit-7RT624PM.js.map → dev-emit-UJJXY3ET.js.map} +0 -0
  136. /package/dist/{internal-api-OOTVIOH2.js.map → internal-api-HUIBRF2X.js.map} +0 -0
  137. /package/dist/{internal-api-VAKXXW6F.js.map → internal-api-S72T2XKD.js.map} +0 -0
  138. /package/dist/{mcp-7UOQM4FW.js.map → mcp-I6MCW6KX.js.map} +0 -0
  139. /package/dist/{openapi-SKKXWFX4.js.map → openapi-24PTE7P6.js.map} +0 -0
  140. /package/dist/{preview-GPMF43QX.js.map → preview-EOL3LMK7.js.map} +0 -0
  141. /package/dist/{registry-UOWTDUFL.js.map → registry-DDBXDHJ2.js.map} +0 -0
  142. /package/dist/{server-boundary-A3HW27C7.js.map → server-boundary-ERBSHRHT.js.map} +0 -0
  143. /package/dist/{server-boundary-V6PCM22J.js.map → server-boundary-I5XWYINJ.js.map} +0 -0
  144. /package/dist/{start-6WEPXA3X.js.map → start-OD4DG4C6.js.map} +0 -0
  145. /package/dist/{vite-plugin-WBF5NXGW.js.map → vite-plugin-SH3VGQEE.js.map} +0 -0
@@ -1,192 +0,0 @@
1
- #!/usr/bin/env node
2
- import "tsx/esm";
3
- import {
4
- buildSecurityHeaders
5
- } from "./chunk-WSMLSIS5.js";
6
-
7
- // src/adapters/deployed-cors.ts
8
- var UnserializableCorsOriginError = class extends Error {
9
- constructor(target) {
10
- super(
11
- `security.cors.origins is a function, and the \`${target}\` target cannot carry it: a deployed function has no theo.config.ts to read, and a callback cannot be written into the emitted entry. Replace it with the origin, a RegExp, or an array of either \u2014 all of which travel \u2014 or build for \`node\` and run \`theokit start\`, which evaluates the callback at runtime.`
12
- );
13
- this.name = "UnserializableCorsOriginError";
14
- }
15
- };
16
- function renderOrigin(origin, target) {
17
- if (typeof origin === "function") throw new UnserializableCorsOriginError(target);
18
- if (origin instanceof RegExp) return String(origin);
19
- if (Array.isArray(origin)) return `[${origin.map((o) => renderOrigin(o, target)).join(", ")}]`;
20
- return JSON.stringify(origin);
21
- }
22
- function renderDeployedCorsLiteral(cors, target) {
23
- if (cors === void 0) return "undefined";
24
- const parts = [`origins: ${renderOrigin(cors.origins, target)}`];
25
- if (cors.methods !== void 0) parts.push(`methods: ${JSON.stringify(cors.methods)}`);
26
- if (cors.allowedHeaders !== void 0)
27
- parts.push(`allowedHeaders: ${JSON.stringify(cors.allowedHeaders)}`);
28
- if (cors.exposedHeaders !== void 0)
29
- parts.push(`exposedHeaders: ${JSON.stringify(cors.exposedHeaders)}`);
30
- parts.push(
31
- `credentials: ${JSON.stringify(cors.credentials)}`,
32
- `maxAge: ${JSON.stringify(cors.maxAge)}`
33
- );
34
- return `{ ${parts.join(", ")} }`;
35
- }
36
- function deployedCorsFragment(cors, target) {
37
- return [
38
- `// #409 \u2014 the CORS the app declared, carried as a literal because a deployed function has no`,
39
- `// theo.config.ts to read. \`null\` when the app declared none: no headers, not permissive ones.`,
40
- `const CORS_CONFIG = ${renderDeployedCorsLiteral(cors, target)}`,
41
- `const CORS_HANDLER = CORS_CONFIG === undefined ? null : createCorsWebHandler(CORS_CONFIG)`,
42
- ``,
43
- `/** Answer a preflight before routing \u2014 an OPTIONS the router handles never gets a CORS answer. */`,
44
- `function corsPreflight(request) {`,
45
- ` return CORS_HANDLER === null ? null : CORS_HANDLER.handlePreflightRequest(request)`,
46
- `}`,
47
- ``,
48
- `/** Put the headers on whatever the app answered, including its 404s \u2014 a browser reads a 404`,
49
- ` * without them as a CORS failure rather than as the 404 it is. */`,
50
- `function withCors(request, response) {`,
51
- ` if (CORS_HANDLER !== null) CORS_HANDLER.applyCorsHeaders(request, response.headers)`,
52
- ` return response`,
53
- `}`
54
- ];
55
- }
56
-
57
- // src/adapters/deployed-csrf.ts
58
- function renderRoutePattern(pattern) {
59
- return pattern instanceof RegExp ? String(pattern) : JSON.stringify(pattern);
60
- }
61
- function renderDeployedCsrfLiteral(security) {
62
- if (security === void 0) return "{}";
63
- const parts = [];
64
- if (security.csrf !== void 0) parts.push(`csrfMode: ${JSON.stringify(security.csrf)}`);
65
- const { disallowed } = security;
66
- if (disallowed !== void 0) {
67
- const routes = disallowed.routes.map(renderRoutePattern).join(", ");
68
- parts.push(
69
- `disallowed: { routes: [${routes}], behavior: ${JSON.stringify(disallowed.behavior)} }`
70
- );
71
- }
72
- return parts.length === 0 ? "{}" : `{ ${parts.join(", ")} }`;
73
- }
74
- function deployedCsrfFragment(opts, home = "a deployed function") {
75
- return [
76
- `// #410 \u2014 the CSRF mode and per-route escalation the app declared. Carried as a`,
77
- `// literal for the same reason as the headers above: ${home} has no theo.config.ts`,
78
- `// to read. Absent keys stay absent so executeRoute's own default ('strict') applies,`,
79
- `// rather than this file becoming a second place it can drift.`,
80
- `const CSRF_CONFIG = ${renderDeployedCsrfLiteral(opts)}`
81
- ];
82
- }
83
-
84
- // src/adapters/deployed-runtime-config.ts
85
- function serverDirLiteral(opts) {
86
- return JSON.stringify(opts.serverDir ?? "server");
87
- }
88
- var EMPTY = {
89
- imports: [],
90
- declarations: [],
91
- executeRouteSpread: ""
92
- };
93
- function deployedRuntimeConfigFragment(options) {
94
- const pluginsModule = options?.runtimeConfigModule;
95
- const serialization = options?.serialization === "superjson" ? "superjson" : void 0;
96
- if (pluginsModule === void 0 && serialization === void 0) return EMPTY;
97
- const imports = [];
98
- const declarations = [];
99
- const spread = [];
100
- if (pluginsModule !== void 0) {
101
- imports.push(
102
- `import { createPluginRunnerFromConfig } from 'theokit/server'`,
103
- `// #425 \u2014 the app's own plugins, resolved on the build machine and written beside this entry.`,
104
- `// A closure has no literal, so this is an import rather than a baked value.`,
105
- `import theoRuntimeConfig from '${pluginsModule}'`
106
- );
107
- declarations.push(
108
- `// Built ONCE, at module load. A runner rebuilt per request would re-run every plugin's`,
109
- `// \`register\`, which is where a plugin allocates the state its hooks then read.`,
110
- `const THEO_PLUGIN_RUNNER = createPluginRunnerFromConfig(theoRuntimeConfig.plugins)`
111
- );
112
- spread.push(`pluginRunner: await THEO_PLUGIN_RUNNER`);
113
- }
114
- if (serialization !== void 0) {
115
- imports.push(`import { resolveTransformer } from 'theokit/server'`);
116
- declarations.push(
117
- `// #425 \u2014 a literal, because \`config.serialization\` is a SELECTOR and not a transformer.`,
118
- `// Same string, same function \`theokit start\` calls, so the deployed response and the local`,
119
- `// one cannot disagree about what the app asked for \u2014 including the \`x-theo-transformer\``,
120
- `// header, whose absence is what made this a data bug rather than a formatting one.`,
121
- `const THEO_TRANSFORMER = resolveTransformer('${serialization}')`
122
- );
123
- spread.push(`transformer: THEO_TRANSFORMER`);
124
- }
125
- return { imports, declarations, executeRouteSpread: `${spread.join(", ")},` };
126
- }
127
-
128
- // src/adapters/deployed-trace.ts
129
- function deployedTraceFragment(requestVar, indent) {
130
- return [
131
- `${indent}// #410 \u2014 honour the caller's trace id instead of minting a new one, and echo it.`,
132
- `${indent}// \`extractTraceIdFromRequest\` validates the caller-controlled \`x-request-id\``,
133
- `${indent}// before trusting it, and falls back to a fresh UUID when neither header is present.`,
134
- `${indent}const requestId = extractTraceIdFromRequest(${requestVar})`,
135
- `${indent}res.setHeader('x-request-id', requestId)`,
136
- `${indent}res.setHeader(TRACE_HEADER, requestId)`
137
- ];
138
- }
139
-
140
- // src/adapters/security-headers.ts
141
- function renderSecurityHeadersConfigLiteral(headers) {
142
- return JSON.stringify(headers ?? {});
143
- }
144
- function describeDeployedSecurityHeaders(limits) {
145
- const headers = buildSecurityHeaders(limits.securityHeaders ?? {}, { production: true });
146
- const names = Object.keys(headers);
147
- if (names.length === 0) {
148
- return ` ! \`${limits.target}\` sends no security headers: the configuration switched every one of them off.`;
149
- }
150
- const lines = [
151
- ` \u2713 security headers on every response \`${limits.target}\` returns: ${names.join(", ")}.`
152
- ];
153
- const sendsCsp = names.some((name) => name.startsWith("Content-Security-Policy"));
154
- if (sendsCsp && !limits.mintsNonce) {
155
- lines.push(
156
- ` - The CSP carries no nonce: this target serves HTML written at build time,`,
157
- ` so there is no per-request value to put on a script tag. An inline`,
158
- ` <script> is refused by \`script-src 'self'\` here, while the same page`,
159
- ` under \`theokit start\` gets a nonce and runs it. Move inline scripts to`,
160
- ` \`<script src="...">\`, or set \`security.headers.cspMode: 'report-only'\``,
161
- ` while you migrate.`
162
- );
163
- }
164
- if (limits.documentHeaders === "platform-configured") {
165
- lines.push(
166
- ` - The HTML document is served by the platform's static host, and reaches`,
167
- ` the browser with these headers through config this build emits. That`,
168
- ` path is not verified by a deploy from here \u2014 the values come from the`,
169
- ` same function the handler uses, but no response has been read back.`
170
- );
171
- }
172
- if (limits.documentHeaders === "platform-unmanaged") {
173
- lines.push(
174
- ` - The HTML document does NOT pass through this handler \u2014 the platform's`,
175
- ` static host serves it \u2014 so these headers reach \`/api/*\` responses and`,
176
- ` not the page. This build emits no artifact that could configure it, so`,
177
- ` set the document's headers on the platform (usetheokit/theokit#412).`
178
- );
179
- }
180
- return lines.join("\n");
181
- }
182
-
183
- export {
184
- deployedCorsFragment,
185
- deployedCsrfFragment,
186
- serverDirLiteral,
187
- deployedRuntimeConfigFragment,
188
- deployedTraceFragment,
189
- renderSecurityHeadersConfigLiteral,
190
- describeDeployedSecurityHeaders
191
- };
192
- //# sourceMappingURL=chunk-6B3CMPE4.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/deployed-cors.ts","../src/adapters/deployed-csrf.ts","../src/adapters/deployed-runtime-config.ts","../src/adapters/deployed-trace.ts","../src/adapters/security-headers.ts"],"sourcesContent":["/**\n * The CORS configuration a deployed entry carries, baked at build time.\n *\n * ## The defect this closes\n *\n * `security.cors` reached exactly one consumer: Vite's `configureServer` hook. So an app that\n * worked cross-origin under `theokit dev` stopped working the moment anything else served it —\n * `theokit start` (fixed separately) and all six Web deploy targets (usetheokit/theokit#409). Same\n * config, same code, no error and no warning; the failure surfaces in a browser as a blocked fetch\n * on the deployed URL, three layers from the key that had quietly stopped being read.\n *\n * The pure half was written twice and called once: `createCorsWebHandler` — the Web mirror — had no\n * caller anywhere in the repository. Nothing here reimplements it.\n *\n * ## A callback origin is REFUSED, not silently dropped\n *\n * `corsSchema.origins` accepts `z.function(...)` alongside the string / RegExp / array shapes. A\n * deployed function has no `theo.config.ts` to read, and there is no literal for a closure — so a\n * build that baked only the serialisable shapes would produce an app whose CORS silently allowed\n * nothing, which is the exact class of failure this issue reports.\n *\n * `rules/three-target-parity.md` § 3 is explicit about the alternative: \"a target that cannot serve\n * a capability refuses by name. Silent degradation is the failure mode this rule exists to\n * prevent.\" So the build throws, naming the target, the key and the two ways forward.\n */\nimport type { TheoConfig } from '../config/schema.js'\n\ntype CorsConfig = NonNullable<NonNullable<TheoConfig['security']>['cors']>\n\n/**\n * The CORS slice of an adapter's build options.\n *\n * Narrow and named once, matching how `securityHeaders` and `DeployedCsrfOptions` already reach the\n * emitters: each renderer receives what it uses, and six signatures name one type instead of six\n * inline shapes that can drift.\n */\nexport interface DeployedCorsOptions {\n cors?: CorsConfig\n}\n\n/**\n * Thrown at BUILD time when the declared CORS cannot be carried to a deployed target.\n *\n * A build error is the point: the alternative is a deploy that looks configured and refuses every\n * cross-origin request, discovered by a browser rather than by the build.\n */\nexport class UnserializableCorsOriginError extends Error {\n constructor(target: string) {\n super(\n `security.cors.origins is a function, and the \\`${target}\\` target cannot carry it: a deployed ` +\n `function has no theo.config.ts to read, and a callback cannot be written into the emitted ` +\n `entry. Replace it with the origin, a RegExp, or an array of either — all of which travel — ` +\n `or build for \\`node\\` and run \\`theokit start\\`, which evaluates the callback at runtime.`,\n )\n this.name = 'UnserializableCorsOriginError'\n }\n}\n\n/** Source text for one origin matcher: a RegExp as a literal, anything else as JSON. */\nfunction renderOrigin(origin: unknown, target: string): string {\n if (typeof origin === 'function') throw new UnserializableCorsOriginError(target)\n if (origin instanceof RegExp) return String(origin)\n if (Array.isArray(origin)) return `[${origin.map((o) => renderOrigin(o, target)).join(', ')}]`\n return JSON.stringify(origin)\n}\n\n/**\n * Source text for the CORS config, or `undefined` when the app declared none.\n *\n * RegExp entries are emitted as regex literals for the reason `deployed-csrf.ts` gives at length:\n * `JSON.stringify` renders a RegExp as `{}`, and `matchesOrigin` checks `instanceof RegExp`, so a\n * JSON-rendered origin would sit in the emitted file looking configured and matching nothing.\n *\n * @throws UnserializableCorsOriginError when `origins` is a callback\n */\nexport function renderDeployedCorsLiteral(cors: CorsConfig | undefined, target: string): string {\n if (cors === undefined) return 'undefined'\n\n const parts = [`origins: ${renderOrigin(cors.origins, target)}`]\n if (cors.methods !== undefined) parts.push(`methods: ${JSON.stringify(cors.methods)}`)\n if (cors.allowedHeaders !== undefined)\n parts.push(`allowedHeaders: ${JSON.stringify(cors.allowedHeaders)}`)\n if (cors.exposedHeaders !== undefined)\n parts.push(`exposedHeaders: ${JSON.stringify(cors.exposedHeaders)}`)\n // Both carry schema defaults, so they are always present and always emitted — unlike the\n // optional fields above, whose absence is a real answer the handler already has one for.\n parts.push(\n `credentials: ${JSON.stringify(cors.credentials)}`,\n `maxAge: ${JSON.stringify(cors.maxAge)}`,\n )\n\n return `{ ${parts.join(', ')} }`\n}\n\n/**\n * The lines that declare the CORS handler in a generated entry.\n *\n * `null` when nothing was declared, which is what \"no cors block\" meant before and still means: no\n * headers, not permissive ones.\n */\nexport function deployedCorsFragment(cors: CorsConfig | undefined, target: string): string[] {\n return [\n `// #409 — the CORS the app declared, carried as a literal because a deployed function has no`,\n `// theo.config.ts to read. \\`null\\` when the app declared none: no headers, not permissive ones.`,\n `const CORS_CONFIG = ${renderDeployedCorsLiteral(cors, target)}`,\n `const CORS_HANDLER = CORS_CONFIG === undefined ? null : createCorsWebHandler(CORS_CONFIG)`,\n ``,\n `/** Answer a preflight before routing — an OPTIONS the router handles never gets a CORS answer. */`,\n `function corsPreflight(request) {`,\n ` return CORS_HANDLER === null ? null : CORS_HANDLER.handlePreflightRequest(request)`,\n `}`,\n ``,\n `/** Put the headers on whatever the app answered, including its 404s — a browser reads a 404`,\n ` * without them as a CORS failure rather than as the 404 it is. */`,\n `function withCors(request, response) {`,\n ` if (CORS_HANDLER !== null) CORS_HANDLER.applyCorsHeaders(request, response.headers)`,\n ` return response`,\n `}`,\n ]\n}\n","/**\n * The CSRF configuration a deployed entry carries, baked at build time.\n *\n * ## The defect this closes\n *\n * The six Web-standards adapter entries built `executeRoute`'s context from an eight-field\n * literal, and neither `csrfMode` nor `disallowed` was among the eight (usetheokit/theokit#410).\n * `executeRoute` defaults an absent mode to `'strict'`, so an app declaring\n * `security: { csrf: 'off' }` — or `'warn'` — got `'strict'` on every deploy target: a `POST` that\n * works under `theokit dev` and `theokit start` answers `403 CSRF_INVALID` on Vercel, naming a\n * mechanism the operator had switched off. The config still validated and the build still\n * succeeded; the behaviour simply changed.\n *\n * The deployed function has no `theo.config.ts` to read, which is why the value is carried as a\n * literal — the same shape `security.headers` already uses (`renderSecurityHeadersConfigLiteral`).\n *\n * ## Why this is not `JSON.stringify`\n *\n * `disallowed.routes` accepts RegExp entries (`config/schemas/security.ts`), and `JSON.stringify`\n * renders a RegExp as `{}`. That is not a formatting problem: `matchDisallowed` checks\n * `p instanceof RegExp`, so a `{}` matches nothing while reading, in the emitted file, as a rule\n * that is present and configured. Reaching for JSON here would reproduce this issue's own defect —\n * configuration that survives validation and quietly stops applying — one layer further down.\n */\nimport type { TheoConfig } from '../config/schema.js'\n\ntype SecurityConfig = NonNullable<TheoConfig['security']>\n\n/**\n * The two slices of `security` that reach `executeRoute`'s context.\n *\n * Narrow rather than the whole block, matching how `securityHeaders` is already passed: each\n * renderer receives what it uses and nothing else, so a headers change cannot reach the CSRF\n * literal and vice versa.\n */\nexport interface DeployedCsrfOptions {\n csrf?: SecurityConfig['csrf']\n disallowed?: SecurityConfig['disallowed']\n}\n\n/**\n * Source text for one route pattern.\n *\n * A RegExp is emitted as a regex literal so it arrives as a RegExp; a string goes through\n * `JSON.stringify`, which is the correct escaper for a JS string literal (quotes, backslashes,\n * control characters, line separators).\n */\nfunction renderRoutePattern(pattern: string | RegExp): string {\n return pattern instanceof RegExp ? String(pattern) : JSON.stringify(pattern)\n}\n\n/**\n * Source text for the CSRF slice of `executeRoute`'s context.\n *\n * Absent values are OMITTED rather than defaulted. `executeRoute` already defaults an absent\n * `csrfMode` to `'strict'`, and writing `'strict'` here would put that default in a second place\n * where the two can disagree — which is the class of drift the whole issue is about.\n *\n * @param security - the declared csrf slices, or `undefined` when the app declared no security block\n */\nexport function renderDeployedCsrfLiteral(security: DeployedCsrfOptions | undefined): string {\n if (security === undefined) return '{}'\n\n const parts: string[] = []\n if (security.csrf !== undefined) parts.push(`csrfMode: ${JSON.stringify(security.csrf)}`)\n\n const { disallowed } = security\n if (disallowed !== undefined) {\n const routes = disallowed.routes.map(renderRoutePattern).join(', ')\n parts.push(\n `disallowed: { routes: [${routes}], behavior: ${JSON.stringify(disallowed.behavior)} }`,\n )\n }\n\n // `{}` and not `{ }` when nothing was declared: the emitted file is read by people, and the\n // two-space version reads as though something was meant to be there.\n return parts.length === 0 ? '{}' : `{ ${parts.join(', ')} }`\n}\n\n/**\n * The lines that declare `CSRF_CONFIG` in a generated entry.\n *\n * One function rather than the same six lines pasted into each of the six adapters: that\n * duplication is how the eight-field context literal came to be wrong in six places at once, and\n * repeating the fix in the same shape would leave the next field with the same six places to be\n * forgotten in. It also keeps the two largest emitters under the `max-lines-per-function` ceiling,\n * which `vercel.ts` already extracts fragments to respect.\n *\n * @param opts - the declared csrf slices, passed straight through from the adapter's build options\n * @param home - what the target has instead of a config file, for the comment's second sentence\n */\nexport function deployedCsrfFragment(\n opts: DeployedCsrfOptions,\n home = 'a deployed function',\n): string[] {\n return [\n `// #410 — the CSRF mode and per-route escalation the app declared. Carried as a`,\n `// literal for the same reason as the headers above: ${home} has no theo.config.ts`,\n `// to read. Absent keys stay absent so executeRoute's own default ('strict') applies,`,\n `// rather than this file becoming a second place it can drift.`,\n `const CSRF_CONFIG = ${renderDeployedCsrfLiteral(opts)}`,\n ]\n}\n","/**\n * The configuration a deployed entry could not apply (usetheokit/theokit#425).\n *\n * ## Why this is not another literal renderer\n *\n * `deployed-csrf.ts` and `deployed-cors.ts` bake their values into the emitted source, which works\n * because `csrf` is an enum and `disallowed` is a `{ routes, behavior }` object — plain data, and a\n * deployed function has no `theo.config.ts` to read.\n *\n * The two concerns left over from #410 turn out to be different from each other, and the difference\n * is the whole design:\n *\n * - **`serialization` is plain data too.** The config field is `z.enum(['json', 'superjson'])`\n * (`config/schema.ts:147`) — a selector, not a transformer. `resolveTransformer` turns it into the\n * functions, and it already ships from `theokit/server`. So this half is a literal like the rest,\n * and the deployed entry resolves it exactly the way `theokit start` does\n * (`cli/commands/start/index.ts:108`), from the same string, through the same function.\n * - **`plugins` genuinely carries functions.** A plugin is constructed in `theo.config.ts` and there\n * is no literal for a closure, so this half needs the entry to import a module instead.\n *\n * ## Static import, not `import()` in the request path\n *\n * The tempting shortcut is `await import('../../theo.config.js')` inside the handler. It trades a\n * silent failure for a louder one on targets with no filesystem, and it moves configuration\n * resolution into every request on the targets that do have one.\n *\n * What this emits instead is a TOP-LEVEL import of a module the build already resolved and wrote\n * beside the entry — the same shape `renderBakedRoutes` uses for route modules (#369): decide on\n * the build machine, emit a static specifier. It is evaluated once at module load, the target's\n * bundler can see through it, and a plugin that needs an API the target lacks fails the build\n * rather than the first request.\n *\n * ## Why each half is optional\n *\n * An app that declares neither concern must produce the entry it produced before this existed.\n * Importing a module the build did not emit fails at load, and spreading an empty object costs an\n * allocation per request for nothing. So an empty request renders to nothing at all, and the\n * caller's `executeRoute` literal is unchanged.\n *\n * The halves are independent on purpose: an app that only picks `superjson` must not be made to\n * carry a plugins module, and an app with plugins and default JSON must not gain a transformer\n * lookup. Coupling them would have made the common case pay for the rare one.\n */\n\n/**\n * The option every Web-standards adapter grows to carry non-serialisable configuration.\n *\n * Composed into each adapter's option type the way `DeployedCsrfOptions` already is, so the six\n * targets cannot drift into six spellings of the same field.\n */\n/**\n * The project's `serverDir`, carried into every generated entrypoint (#RFC server-layout).\n *\n * Separate from the other option groups because it is not a runtime feature toggle: it is the\n * project's own layout, and an adapter that hardcodes `'server'` agrees with the default by\n * COINCIDENCE. The moment a project sets the option — the entire point of it existing — the\n * generated entrypoint resolves a directory that is not there, and only after deploy: the build\n * succeeds, the bundle is written, and routes 404 in production with nothing naming the cause.\n */\nexport interface DeployedServerDirOptions {\n /** Project-relative server directory. Absent ⇒ the schema default, `server`. */\n serverDir?: string\n}\n\n/**\n * The server directory as a quoted TypeScript literal, ready to interpolate into generated source.\n *\n * `JSON.stringify` rather than wrapping in quotes by hand: the value reaches this from user config,\n * so a directory containing a quote or a backslash would otherwise emit a syntax error into\n * somebody else's build — a worse failure than the one this fixes.\n */\nexport function serverDirLiteral(opts: DeployedServerDirOptions): string {\n return JSON.stringify(opts.serverDir ?? 'server')\n}\n\nexport interface DeployedRuntimeConfigOptions {\n /**\n * Specifier of the plugins module the build wrote beside the entry, or `undefined` when the app\n * declares no plugins and the build wrote none.\n */\n runtimeConfigModule?: string\n /**\n * The app's `serialization` selector, carried as a literal.\n *\n * `'json'` and `undefined` both mean the default, and neither emits anything: `executeRoute`\n * already falls back to `JSON.stringify`, and the `x-theo-transformer` header is deliberately\n * absent for the default so a client is told only when there is something to be told.\n */\n serialization?: 'json' | 'superjson'\n}\n\n/** The three places an entry has to grow to carry non-serialisable configuration. */\nexport interface DeployedRuntimeConfigFragment {\n /** Top-level imports. Empty when the build emitted no config module. */\n readonly imports: string[]\n /** Module-scope declarations — evaluated once, at load. Empty when there is nothing to carry. */\n readonly declarations: string[]\n /**\n * Spread into the entry's `executeRoute({ … })` literal, inside an async function.\n *\n * Empty string when there is nothing to carry, so the call site keeps the exact shape it had.\n */\n readonly executeRouteSpread: string\n}\n\nconst EMPTY: DeployedRuntimeConfigFragment = {\n imports: [],\n declarations: [],\n executeRouteSpread: '',\n}\n\n/**\n * What a deployed entry needs in order to apply `config.plugins` and `config.serialization`.\n *\n * @param moduleSpecifier - specifier of the runtime-config module the build emitted beside the\n * entry, or `undefined` when the app declared neither concern and the build emitted none.\n */\nexport function deployedRuntimeConfigFragment(\n options: DeployedRuntimeConfigOptions | undefined,\n): DeployedRuntimeConfigFragment {\n const pluginsModule = options?.runtimeConfigModule\n // 'json' is the default and emits nothing — see `serialization` above.\n const serialization = options?.serialization === 'superjson' ? 'superjson' : undefined\n if (pluginsModule === undefined && serialization === undefined) return EMPTY\n\n const imports: string[] = []\n const declarations: string[] = []\n const spread: string[] = []\n\n if (pluginsModule !== undefined) {\n imports.push(\n `import { createPluginRunnerFromConfig } from 'theokit/server'`,\n `// #425 — the app's own plugins, resolved on the build machine and written beside this entry.`,\n `// A closure has no literal, so this is an import rather than a baked value.`,\n `import theoRuntimeConfig from '${pluginsModule}'`,\n )\n declarations.push(\n `// Built ONCE, at module load. A runner rebuilt per request would re-run every plugin's`,\n `// \\`register\\`, which is where a plugin allocates the state its hooks then read.`,\n `const THEO_PLUGIN_RUNNER = createPluginRunnerFromConfig(theoRuntimeConfig.plugins)`,\n )\n // Awaited, not passed along: `createPluginRunnerFromConfig` is async because `register` is, and\n // a pending promise handed to `executeRoute` is a truthy object with none of the runner's\n // methods — every hook would silently not fire, which is this issue's own defect one layer in.\n spread.push(`pluginRunner: await THEO_PLUGIN_RUNNER`)\n }\n\n if (serialization !== undefined) {\n imports.push(`import { resolveTransformer } from 'theokit/server'`)\n declarations.push(\n `// #425 — a literal, because \\`config.serialization\\` is a SELECTOR and not a transformer.`,\n `// Same string, same function \\`theokit start\\` calls, so the deployed response and the local`,\n `// one cannot disagree about what the app asked for — including the \\`x-theo-transformer\\``,\n `// header, whose absence is what made this a data bug rather than a formatting one.`,\n `const THEO_TRANSFORMER = resolveTransformer('${serialization}')`,\n )\n spread.push(`transformer: THEO_TRANSFORMER`)\n }\n\n return { imports, declarations, executeRouteSpread: `${spread.join(', ')},` }\n}\n","/**\n * The request id a deployed entry uses, and the header it echoes back.\n *\n * ## The defect this closes\n *\n * Every generated entry minted a fresh `randomUUID()` per request and set no correlation header\n * at all on a success path (usetheokit/theokit#410). Both Node paths do the opposite: they resolve\n * an incoming `traceparent` / `x-request-id` through `extractTraceId` and echo the result under\n * both `x-request-id` and `x-trace-id` (`cli/commands/start/request-handler.ts`,\n * `vite-plugin/api-middleware.ts`).\n *\n * The consequence is that a trace crossing into a deployed function starts over. The caller's id\n * is discarded, and the response carries nothing to correlate against — so a request that fails in\n * production cannot be tied to the client that made it, which is the one situation the id exists\n * for.\n *\n * ## Why `setHeader` before the handler, rather than wrapping the response\n *\n * It is what the Node path does, and the shim reproduces Node's semantics exactly: `writeHead`\n * MERGES into the header map rather than replacing it (`web-shim.ts`), so a header set here\n * survives the handler's own `writeHead` and a handler that sets its own id still wins. Wrapping\n * the finished `Response` instead would have to mutate a response whose body is already streaming\n * (#382), and would miss the branches that return before the shim is built.\n */\n\n/**\n * Lines that resolve the request id and echo it, as generated source.\n *\n * @param requestVar - the name the entry gave the Web `Request` in scope\n * @param indent - leading whitespace, so the emitted file stays readable\n */\nexport function deployedTraceFragment(requestVar: string, indent: string): string[] {\n return [\n `${indent}// #410 — honour the caller's trace id instead of minting a new one, and echo it.`,\n `${indent}// \\`extractTraceIdFromRequest\\` validates the caller-controlled \\`x-request-id\\``,\n `${indent}// before trusting it, and falls back to a fresh UUID when neither header is present.`,\n `${indent}const requestId = extractTraceIdFromRequest(${requestVar})`,\n `${indent}res.setHeader('x-request-id', requestId)`,\n `${indent}res.setHeader(TRACE_HEADER, requestId)`,\n ]\n}\n","/**\n * The security headers a deployed target puts on its responses.\n *\n * `theokit start` applies the configured baseline to every response it writes\n * (`cli/commands/start/request-handler.ts`). None of the six Web-standards\n * deploy adapters applied any, so the same page carried a CSP,\n * `X-Frame-Options`, HSTS and `nosniff` under `theokit start` and none of them\n * once deployed (usetheokit/theokit#410, GHSA-87qq-fgcr-384x).\n *\n * This module is the seam that closes that half of the gap. It has two halves\n * and they live together on purpose: the code that writes the literal into a\n * generated entry and the code that reads it at request time have to agree on\n * one shape, and a shape stated in two files drifts.\n *\n * - **Build time** — {@link renderSecurityHeadersConfigLiteral} turns\n * `security.headers` into a JSON literal the adapter inlines. A deployed\n * runtime has no `theo.config.ts` to read, so the configuration travels as\n * data.\n * - **Request time** — the generated entry calls {@link buildSecurityHeaders}\n * on that literal and hands every response to {@link withSecurityHeaders}.\n * The same function `theokit start` calls, on the same input, so the two\n * cannot disagree about what the configuration means.\n *\n * ## The per-request nonce, and where it stops\n *\n * `buildSecurityHeaders` accepts a per-request `nonce` and substitutes it into\n * `script-src`. A nonce cannot survive a build-time literal — it is minted per\n * response — so a target reaches one only if it renders the HTML at request\n * time and can put the same value on the script tags it emits.\n *\n * Exactly one deploy path does: **Cloudflare with `ssrStreaming: true`**, whose\n * worker calls `renderStreamingWeb(request, { nonce })`, and that renderer\n * threads the value into `renderToReadableStream` and into the hydration script\n * (`router/entry-server.ts`). That branch mints a nonce per request and builds\n * its CSP from it. Everything else serves HTML written at build time, or no\n * HTML at all, and carries a **nonce-less CSP** — the same answer\n * `buildSecurityHeaders` already gives a prerendered route (EC-4), for the same\n * reason: a nonce in the header with no nonce on the tag blocks every inline\n * script.\n *\n * That asymmetry is real and is not smoothed over. It is stated in the emitted\n * entry, printed by the build through\n * {@link describeDeployedSecurityHeaders}, and written down in\n * `docs/surfaces/build-adapters.md`.\n */\nimport { generateNonce } from '../core/contracts/nonce.js'\nimport type { SecurityHeadersConfig } from '../core/contracts/security-headers.js'\nimport { buildSecurityHeaders } from '../core/contracts/security-headers.js'\n\n/**\n * Re-exported so a generated entry has ONE import for the whole concern.\n *\n * Reaching it through `theokit/server/security` would work and would also drag\n * that barrel's CSRF surface into a Worker bundle, for a function that is forty\n * lines of string concatenation. It is defined in `core/contracts/`, which is\n * the module every target may import from — `adapters → server` is not an edge\n * in the DAG, and the header policy was never server code.\n */\nexport { buildSecurityHeaders }\n\n/**\n * Re-exported for the same reason, and so the streamed Cloudflare worker mints\n * its nonce with the identical primitive `theokit start` uses\n * (`cli/commands/start/request-handler.ts`) rather than a second, hand-rolled\n * one. It is already runtime-portable: Web Crypto first, with a named error\n * when the runtime has none.\n */\nexport { generateNonce }\n\n/**\n * The `security.headers` block, as a literal a generated entry can carry.\n *\n * `{}` when the app declares none — which is not the same as \"no headers\".\n * `buildSecurityHeaders({})` returns the full default baseline, and `{}` is\n * exactly what `theokit start` passes when `security.headers` is absent\n * (`cli/commands/start/index.ts`). An app with no security block gets the same\n * baseline deployed as it gets locally.\n */\nexport function renderSecurityHeadersConfigLiteral(\n headers: SecurityHeadersConfig | undefined,\n): string {\n return JSON.stringify(headers ?? {})\n}\n\n/**\n * Put the headers on a response, without overruling the handler.\n *\n * `theokit start` sets the baseline BEFORE the route handler runs, so a handler\n * can override it with `res.setHeader` (last write wins, Node convention). On a\n * Web target the response arrives already built, so the equivalent of \"the\n * handler wins\" is to skip a header the response already carries: a route that\n * set its own `Content-Security-Policy` keeps it.\n *\n * Mutates and returns the same `Response` rather than constructing a\n * replacement, because these responses are handed to the runtime while their\n * body is still being written (#382) and re-wrapping the stream is exactly the\n * second buffering point that change removed.\n *\n * Mutation is safe for every response these entries produce: the Fetch spec\n * gives a locally constructed `Response` the `response` header guard, which\n * permits `set` for every name used here. The `immutable` guard belongs to\n * responses that came back from `fetch()`, and none of the six emitted handlers\n * returns one — each builds its response from `createWebShim`, from a `new\n * Response(...)`, or from the SSR renderer. The WebSocket upgrade, which is the\n * one response an adapter gets from its runtime rather than building, is\n * deliberately not routed through here.\n */\nexport function withSecurityHeaders(response: Response, headers: Record<string, string>): Response {\n for (const [key, value] of Object.entries(headers)) {\n if (!response.headers.has(key)) response.headers.set(key, value)\n }\n return response\n}\n\nexport interface DeployedSecurityHeaderLimits {\n target: string\n /** The app's `security.headers` block, or undefined when it declares none. */\n securityHeaders: SecurityHeadersConfig | undefined\n /**\n * Does the emitted handler render HTML at request time and mint a CSP nonce\n * for it? True only for Cloudflare with `ssrStreaming: true`.\n */\n mintsNonce: boolean\n /**\n * Is the HTML document served by a platform static host rather than by the\n * handler this build emits? True wherever the emitted handler answers\n * `/api/*` and returns 404 for everything else.\n */\n /**\n * Who puts the security headers on the HTML DOCUMENT — a different question from who serves it,\n * and the two used to be collapsed into one boolean (usetheokit/theokit#412).\n *\n * - `handler` — this target's own handler returns the document, so it carries the same baseline\n * every API response carries. No caveat.\n * - `platform-configured` — the platform's static host serves the document, AND this build emits\n * the configuration that puts the headers on it (`.vercel/output/config.json`, `netlify.toml`).\n * Still worth stating, because nothing here has seen a deployed response.\n * - `platform-unmanaged` — the platform serves it and this build owns no artifact that could\n * configure it. This is the real remaining gap, and it stays named.\n *\n * The two-value version reported `platform-configured` targets with the same message as\n * `platform-unmanaged` ones, telling an operator to go and do work the build had already done —\n * and a stale limitation reads exactly like a current one.\n */\n documentHeaders: 'handler' | 'platform-configured' | 'platform-unmanaged'\n}\n\n/**\n * What the build tells the operator, once, per target.\n *\n * Silent degradation is the failure mode `rules/three-target-parity.md` exists\n * to prevent. Two things degrade quietly here and both are named rather than\n * discovered in production: a CSP that refuses inline scripts on a deploy while\n * allowing them locally, and an HTML document that never passes through the\n * handler these headers are attached to.\n *\n * The header names are read from the map the entry will actually carry, not\n * from a list written next to it. A configuration that switches HSTS or the CSP\n * off would otherwise be announced as sending them.\n */\nexport function describeDeployedSecurityHeaders(limits: DeployedSecurityHeaderLimits): string {\n const headers = buildSecurityHeaders(limits.securityHeaders ?? {}, { production: true })\n const names = Object.keys(headers)\n if (names.length === 0) {\n return ` ! \\`${limits.target}\\` sends no security headers: the configuration switched every one of them off.`\n }\n\n const lines = [\n ` ✓ security headers on every response \\`${limits.target}\\` returns: ${names.join(', ')}.`,\n ]\n const sendsCsp = names.some((name) => name.startsWith('Content-Security-Policy'))\n if (sendsCsp && !limits.mintsNonce) {\n lines.push(\n ` - The CSP carries no nonce: this target serves HTML written at build time,`,\n ` so there is no per-request value to put on a script tag. An inline`,\n ` <script> is refused by \\`script-src 'self'\\` here, while the same page`,\n ` under \\`theokit start\\` gets a nonce and runs it. Move inline scripts to`,\n ` \\`<script src=\"...\">\\`, or set \\`security.headers.cspMode: 'report-only'\\``,\n ` while you migrate.`,\n )\n }\n if (limits.documentHeaders === 'platform-configured') {\n lines.push(\n ` - The HTML document is served by the platform's static host, and reaches`,\n ` the browser with these headers through config this build emits. That`,\n ` path is not verified by a deploy from here — the values come from the`,\n ` same function the handler uses, but no response has been read back.`,\n )\n }\n if (limits.documentHeaders === 'platform-unmanaged') {\n lines.push(\n ` - The HTML document does NOT pass through this handler — the platform's`,\n ` static host serves it — so these headers reach \\`/api/*\\` responses and`,\n ` not the page. This build emits no artifact that could configure it, so`,\n ` set the document's headers on the platform (usetheokit/theokit#412).`,\n )\n }\n return lines.join('\\n')\n}\n"],"mappings":"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","names":[]}
@@ -1,16 +0,0 @@
1
- // src/server/define/define-middleware.ts
2
- var WEB_SHAPED_MIDDLEWARE = /* @__PURE__ */ Symbol.for("theokit.middleware.web-shaped");
3
- function defineMiddleware(handler) {
4
- Object.defineProperty(handler, WEB_SHAPED_MIDDLEWARE, {
5
- value: true,
6
- enumerable: false,
7
- configurable: true
8
- });
9
- return handler;
10
- }
11
-
12
- export {
13
- WEB_SHAPED_MIDDLEWARE,
14
- defineMiddleware
15
- };
16
- //# sourceMappingURL=chunk-7L7LQ2GU.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/define/define-middleware.ts"],"mappings":";AAkEO,IAAM,wBAAwB,uBAAO,IAAI,+BAA+B;AAUxE,SAAS,iBAAiB,SAA+C;AAC9E,SAAO,eAAe,SAAS,uBAAuB;AAAA,IACpD,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB,CAAC;AACD,SAAO;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/resolve-plugin-specifiers.ts","../src/server/transformer.ts","../src/vite-plugin/hoist-head-tags.ts","../src/vite-plugin/ssr-dev-middleware.ts","../src/server/agent/agent-card-handler.ts","../src/server/agent/approve-agent.ts","../src/server/agent/handle-agent-run-reconnect.ts","../src/server/agent/thread-dispatcher.ts","../src/server/agent/thread-run-registry.ts","../src/server/agent/handle-thread-routes.ts","../src/server/agent/list-approvals-handler.ts","../src/server/agent/serve-aux-routes.ts","../src/server/http/plugin-lifecycle.ts","../src/server/http/resolve-agent-subject.ts"],"sourcesContent":["/**\n * Turn `config.plugins` entries that are module SPECIFIERS into plugins (usetheokit/theokit#425).\n *\n * ## Why the field grew a second shape\n *\n * `config.plugins` holds constructed objects, and a generated deploy entry cannot carry a closure:\n * there is no literal for one. So on all six Web-standards targets the entry built its request\n * context with no runner and every lifecycle hook was dead on a deployed app while firing locally.\n *\n * Two ways out were weighed:\n *\n * - **Bundle `theo.config.ts` into the entry.** Rejected on measurement. It silently drops\n * `theo.config.<NODE_ENV>.ts`, which `loadConfig` merges (`config/load-config.ts:92`) — a new\n * silent drop, which is the exact class of defect this work exists to remove. And it pulls every\n * module the config imports (database drivers, build-only helpers) into a Worker bundle that\n * builds today, so the common case would pay for the rare one.\n * - **Name the module.** A string entry says which module the plugin comes from, so the build emits\n * a static import for that module and nothing else. One declaration serves the local server and\n * the deployed entry, which is what keeps them from disagreeing.\n *\n * The second is what this implements. It is ADDITIVE: an app passing constructed objects is\n * untouched, and gets the same treatment it always got.\n *\n * ## Why this lives in `config/` and not beside `createPluginRunnerFromConfig`\n *\n * Resolving a specifier means importing a path, and that means `node:url`/`node:path`. `server/`\n * holds a no-`node:*` invariant so the same code serves the Web, Tauri and TUI targets\n * (`rules/three-target-parity.md`). `config/` already reads the filesystem — `load-config.ts` is\n * the module that finds `theo.config.ts` at all — and it is the one place BOTH local entry points\n * (`theokit start` and the Vite dev server) already import from. So the specifier is resolved\n * where the config is read, and `createPluginRunnerFromConfig` keeps taking what it always took:\n * objects.\n */\nimport { isAbsolute, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\n\n/**\n * A declared plugin module that could not be turned into a plugin.\n *\n * Its own error type because the alternative — skipping the entry — leaves an app running with one\n * fewer plugin than it declared and nothing saying so. That is the failure this issue is about,\n * reproduced at the door.\n */\nexport class UnresolvablePluginSpecifierError extends Error {\n constructor(index: number, specifier: string, reason: string) {\n super(`plugins[${index}] (${specifier}) could not be loaded: ${reason}`)\n this.name = 'UnresolvablePluginSpecifierError'\n }\n}\n\n/**\n * Resolve every string entry in `plugins` to the module's default export, in order.\n *\n * @param plugins - the raw `config.plugins` array: constructed plugins, module specifiers, or both.\n * @param cwd - the project root a relative specifier is resolved against.\n */\nexport async function resolvePluginSpecifiers(\n plugins: readonly unknown[],\n cwd: string,\n): Promise<unknown[]> {\n const resolved: unknown[] = []\n // Sequential on purpose. Plugin order is hook order, and resolving concurrently then collecting\n // as each settles would reorder an app's lifecycle by module size.\n for (const [index, entry] of plugins.entries()) {\n resolved.push(typeof entry === 'string' ? await importPlugin(entry, index, cwd) : entry)\n }\n return resolved\n}\n\nasync function importPlugin(specifier: string, index: number, cwd: string): Promise<unknown> {\n const target = isAbsolute(specifier) ? specifier : resolve(cwd, specifier)\n let mod: { default?: unknown }\n try {\n mod = (await import(/* @vite-ignore */ pathToFileURL(target).href)) as { default?: unknown }\n } catch (err) {\n throw new UnresolvablePluginSpecifierError(index, specifier, messageOf(err))\n }\n if (mod.default === undefined) {\n // Registering `undefined` would fail later inside `createPluginRunnerFromConfig` with an error\n // naming a shape rather than a file, which is the harder half of the diagnosis.\n throw new UnresolvablePluginSpecifierError(\n index,\n specifier,\n 'the module has no default export; a plugin module must `export default` its plugin',\n )\n }\n return mod.default\n}\n\nfunction messageOf(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n","import superjson from 'superjson'\n\n/**\n * T5.2 — pluggable response/request transformer.\n *\n * `superjson` is the default, preserving Date/Map/Set/BigInt/etc.\n * `json` is the lightweight option (plain JSON.stringify/parse).\n * Users can supply a custom object implementing this contract.\n */\nexport interface TheoTransformer {\n name: string\n serialize: (value: unknown) => string\n deserialize: (raw: string) => unknown\n}\n\nexport const superjsonTransformer: TheoTransformer = {\n name: 'superjson',\n serialize: (v) => JSON.stringify(superjson.serialize(v)),\n deserialize: (raw) => {\n const parsed = JSON.parse(raw) as Parameters<typeof superjson.deserialize>[0]\n return superjson.deserialize(parsed)\n },\n}\n\nexport const jsonTransformer: TheoTransformer = {\n name: 'json',\n serialize: (v) => JSON.stringify(v),\n deserialize: (raw) => JSON.parse(raw) as unknown,\n}\n\nconst BUILT_INS: Record<string, TheoTransformer> = {\n superjson: superjsonTransformer,\n json: jsonTransformer,\n}\n\nexport function resolveTransformer(\n selector: 'json' | 'superjson' | TheoTransformer,\n): TheoTransformer {\n if (typeof selector === 'string') {\n // selector is 'json' | 'superjson' literal — both keys exist in\n // BUILT_INS by construction. Type system guarantees a hit; we keep\n // a defensive fallback that the compiler cannot see is unreachable\n // at runtime, just in case someone adds a new literal to the union\n // but forgets to register the built-in.\n const built = BUILT_INS[selector]\n // Defensive: the public union ensures `built` is defined, but if a\n // future contributor extends the union without registering the impl,\n // the cast keeps the failure mode loud.\n if ((built as TheoTransformer | undefined) === undefined) {\n throw new Error(\n `Unknown transformer \"${selector}\". Built-in options: ${Object.keys(BUILT_INS).join(', ')}.`,\n )\n }\n return built\n }\n if (\n typeof selector !== 'object' ||\n typeof selector.serialize !== 'function' ||\n typeof selector.deserialize !== 'function'\n ) {\n throw new Error(\n `Custom transformer must have serialize and deserialize functions. Got: ${JSON.stringify(selector)}`,\n )\n }\n return selector\n}\n","/**\n * Moves the document metadata a route rendered into the `<head>` where it belongs.\n *\n * ## Why this exists\n *\n * React 19 hoists `<title>`, `<meta>` and `<link>` into the head — **in the browser**, by moving\n * DOM nodes after hydration. On the server it emits them inline, wherever the component sat, and\n * the SSR output is injected inside `<div id=\"root\">`. So a route's own metadata ships in the\n * BODY.\n *\n * For a reader that changes nothing: hydration moves the tags a moment later. For a crawler it\n * changes everything, because the ones that matter never run JavaScript. Every social unfurler —\n * X, LinkedIn, Slack, Discord, WhatsApp — reads the served `<head>` and stops. Without this, every\n * page of a site unfurls with whatever static fallback `index.html` happens to carry: share ten\n * different documentation pages, get ten identical cards.\n *\n * Turning SSR on to fix social previews and finding they still do not work is a bad afternoon, so\n * the framework does the hoist itself (usetheokit/theokit#319).\n *\n * ## Precedence\n *\n * The route wins over the template. `index.html` holds site-wide defaults; a page that states its\n * own title, description or canonical is being specific on purpose, and shipping both would leave\n * the crawler to pick — in practice the first one, which is the generic one.\n */\n\n/**\n * Tags React hoists, and therefore the ones worth moving.\n *\n * Two separate patterns rather than one with an alternation: a single expression covering both the\n * self-closing tags and the `<title>…</title>` pair needs a lazy `[\\s\\S]*?` next to a lazy\n * `[^>]*?`, and that nests two unbounded quantifiers — catastrophic backtracking on hostile input,\n * which here is a served HTML document. Each pattern below is linear: `[^>]` and `[^<]` cannot\n * cross the delimiter that ends the match.\n */\nconst VOID_METADATA = /<(?:meta|link)\\b[^>]*>/gi\n/** `<title>` content is text, so it cannot contain `<` — the class is what keeps this linear. */\nconst TITLE_TAG = /<title\\b[^>]*>[^<]*<\\/title>/gi\n\n/** Runs `replacer` over every hoistable tag, in document order. */\nfunction replaceHoistable(html: string, replacer: (tag: string) => string): string {\n return html.replace(TITLE_TAG, replacer).replace(VOID_METADATA, replacer)\n}\n\n/**\n * The identity of a metadata tag, used to decide what the route replaces.\n *\n * `<meta name=\"description\">` and `<meta property=\"og:title\">` are distinct slots; two `<meta>`\n * tags with different names are not duplicates. A `<link>` is keyed by `rel`, so a route's\n * canonical replaces the template's while a stylesheet link is left alone.\n *\n * Anything unkeyed (a `<link rel=\"preconnect\">`, say) returns `undefined` and is simply appended —\n * additive tags must not evict each other.\n */\nexport function metadataKey(tag: string): string | undefined {\n if (/^<title\\b/i.test(tag)) return 'title'\n\n const name = /\\bname=[\"']([^\"']+)[\"']/i.exec(tag)?.[1]\n const property = /\\bproperty=[\"']([^\"']+)[\"']/i.exec(tag)?.[1]\n const rel = /\\brel=[\"']([^\"']+)[\"']/i.exec(tag)?.[1]\n\n if (/^<meta\\b/i.test(tag)) {\n if (property !== undefined) return `property:${property.toLowerCase()}`\n if (name !== undefined) return `name:${name.toLowerCase()}`\n return undefined\n }\n\n if (/^<link\\b/i.test(tag) && rel !== undefined) {\n const slug = rel.toLowerCase()\n // Only single-valued rels are slots. `stylesheet`, `preload` and friends are additive: keying\n // them would let one page's stylesheet evict another's.\n return slug === 'canonical' || slug === 'manifest' ? `link:${slug}` : undefined\n }\n\n return undefined\n}\n\nexport interface HoistedHead {\n /** The rendered HTML with its metadata tags removed. */\n html: string\n /** Those tags, ready to be placed in the head. */\n headTags: string[]\n}\n\n/** Pulls hoistable metadata out of rendered SSR markup. */\nexport function extractHeadTags(ssrHtml: string): HoistedHead {\n const headTags: string[] = []\n const html = replaceHoistable(ssrHtml, (tag) => {\n headTags.push(tag)\n return ''\n })\n return { html, headTags }\n}\n\n/**\n * Inserts `headTags` into the template's head, dropping any template tag the route supersedes.\n *\n * Returns the template untouched when there is nothing to hoist or no `</head>` to hoist into —\n * a missing head is a malformed template, and rewriting it further would not help anyone.\n */\nexport function injectIntoHead(template: string, headTags: string[]): string {\n if (headTags.length === 0) return template\n\n const closingHead = template.toLowerCase().lastIndexOf('</head>')\n if (closingHead === -1) return template\n\n const supersededKeys = new Set(\n headTags.map((tag) => metadataKey(tag)).filter((key): key is string => key !== undefined),\n )\n\n let head = template.slice(0, closingHead)\n if (supersededKeys.size > 0) {\n head = replaceHoistable(head, (tag) => {\n const key = metadataKey(tag)\n return key !== undefined && supersededKeys.has(key) ? '' : tag\n })\n }\n\n return `${head} ${headTags.join('\\n ')}\\n ${template.slice(closingHead)}`\n}\n\n/**\n * The whole operation: strip metadata from the rendered markup and place it in the template's head.\n */\nexport function hoistHeadTags(\n template: string,\n ssrHtml: string,\n): { template: string; html: string } {\n const { html, headTags } = extractHeadTags(ssrHtml)\n const hoisted = injectIntoHead(template, headTags)\n\n // Fail SAFE, not silent. `injectIntoHead` returns the template untouched when it finds no\n // `</head>` — and if we returned the stripped body alongside it, the metadata would be removed\n // from one place and added to neither. It would vanish, with nothing to show for it.\n //\n // That is not hypothetical: a template whose COMMENT mentioned `<div id=\"root\">` split at the\n // comment, leaving a \"head\" half with no `</head>` in it, and every route silently lost its\n // title and canonical. Metadata in the wrong place still works after hydration; metadata that is\n // gone never comes back.\n if (hoisted === template) return { template, html: ssrHtml }\n\n return { template: hoisted, html }\n}\n","/**\n * T2.2 (architecture-medium-deferrals plan, ADR D2) — SSR dev middleware\n * extracted from `vite-plugin/index.ts` for SRP.\n *\n * `setupSsrDevMiddleware(server, opts)` registers a Connect-style middleware\n * on the Vite dev server that:\n * 1. Skips API, static, and HMR requests (let other middlewares handle).\n * 2. Reads `index.html`, runs `transformIndexHtml`.\n * 3. Generates per-request nonce, applies security headers (CSP + Cache-Control).\n * 4. Calls `ssrLoadModule(VIRTUAL_ENTRY_SERVER_ID).render(url, { nonce })`.\n * 5. Injects rendered HTML (with hydration script) into root div.\n * 6. On error: ssrFixStacktrace + fallback to CSR via `next()`.\n *\n * No-op when `ssrEnabled === false`. Caller's responsibility to gate.\n */\n\nimport { readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport type { ViteDevServer } from 'vite'\n\nimport { findRootDiv } from '../core/contracts/find-root-div.js'\nimport {\n applySecurityHeaders,\n generateNonce,\n type SecurityHeadersConfig,\n} from '../server/internal-api.js'\n\nimport { hoistHeadTags } from './hoist-head-tags.js'\n\ninterface SsrRenderResult {\n html: string\n hydrationData: {\n loaderData?: unknown\n actionData?: unknown\n errors?: unknown\n }\n}\n\ninterface SsrEntryServer {\n render: (\n url: string,\n opts: { nonce: string },\n ) => Promise<SsrRenderResult | { redirect: Response } | string>\n}\n\n/**\n * Stamps the request nonce onto every inline `<script>` the HTML already carries.\n *\n * `transformIndexHtml` lets Vite plugins inject their own scripts, and they know nothing about our\n * CSP. `@vitejs/plugin-react` injects its refresh preamble as an INLINE module script with no\n * nonce, so a nonce-based `script-src` blocks it, `window.$RefreshReg$` is never defined, and the\n * first component module throws \"@vitejs/plugin-react can't detect preamble\". SSR still produced\n * the HTML, so the page looks fine and simply never hydrates — nothing interactive works, and the\n * one console error points at Vite rather than at us (usetheokit/theokit#319).\n *\n * Only scripts WITHOUT `src` are stamped: a same-origin `src` is already covered by `'self'`, and\n * an inline script is the only kind a nonce is needed for. Scripts that already carry a nonce are\n * left alone, so the render's own output is never rewritten.\n *\n * Deliberately not a general HTML parser: this runs per request in dev, on markup we produced or a\n * Vite plugin injected, and the pattern only ever matches an opening `<script>` tag.\n */\nexport function applyNonceToInlineScripts(html: string, nonce: string): string {\n return html.replace(\n /<script(?![^>]*\\ssrc=)(?![^>]*\\snonce=)([^>]*)>/gi,\n `<script nonce=\"${nonce}\"$1>`,\n )\n}\n\nfunction isSsrRenderResult(value: unknown): value is SsrRenderResult {\n if (typeof value !== 'object' || value === null) return false\n if (!('html' in value)) return false\n return typeof (value as Record<string, unknown>).html === 'string'\n}\n\ninterface SsrDevMiddlewareOptions {\n projectRoot: string\n virtualEntryServerId: string\n securityHeaders: SecurityHeadersConfig | undefined\n}\n\n/**\n * Attach the SSR dev middleware to a Vite dev server. Caller decides whether\n * to invoke this based on `ssrEnabled` — this function does not gate.\n */\nexport function setupSsrDevMiddleware(server: ViteDevServer, opts: SsrDevMiddlewareOptions): void {\n server.middlewares.use((req, res, next) => {\n void (async () => {\n const url = req.url ?? '/'\n // Skip API, static, and HMR requests\n if (\n url.startsWith('/api/') ||\n url.startsWith('/@') ||\n url.startsWith('/node_modules/') ||\n url.includes('.')\n ) {\n next()\n return\n }\n\n try {\n const indexPath = resolve(opts.projectRoot, 'index.html')\n // eslint-disable-next-line security/detect-non-literal-fs-filename -- projectRoot is from `theokit dev`'s caller-controlled cwd\n let template = readFileSync(indexPath, 'utf-8')\n\n // T4.1 — Generate a per-request nonce and apply security headers BEFORE render.\n // The same nonce flows into React's renderToPipeableStream({ nonce }) so every\n // emitted <script> carries it AND into the CSP script-src directive.\n // EC-3: applySecurityHeaders also forces Cache-Control: private, no-store.\n //\n // The nonce is minted BEFORE `transformIndexHtml` so the scripts Vite plugins inject can be\n // stamped with it. Minting it afterwards left the React refresh preamble unnonced, the CSP\n // blocked it, and the app never hydrated (usetheokit/theokit#319).\n const nonce = generateNonce()\n\n template = await server.transformIndexHtml(url, template)\n template = applyNonceToInlineScripts(template, nonce)\n applySecurityHeaders(\n res,\n opts.securityHeaders ?? {},\n { production: process.env.NODE_ENV === 'production' },\n { nonce },\n )\n\n const mod = (await server.ssrLoadModule(opts.virtualEntryServerId)) as SsrEntryServer\n const result = await mod.render(url, { nonce })\n\n if (result && typeof result === 'object' && 'redirect' in result) {\n res.writeHead(302, {\n Location: result.redirect.headers.get('location') ?? '/',\n })\n res.end()\n return\n }\n\n // Backward-compat: old render returned string. New shape returns\n // { html, hydrationData } so the framework can emit the hydration\n // data script OUTSIDE the React root (fixes hydration mismatch).\n let ssrHtml: string\n let hydrationScript = ''\n if (typeof result === 'string') {\n ssrHtml = result\n } else if (isSsrRenderResult(result)) {\n ssrHtml = result.html\n const dataJson = JSON.stringify(result.hydrationData).replace(/</g, '\\\\u003c')\n hydrationScript = `<script nonce=\"${nonce}\">window.__staticRouterHydrationData=${dataJson}</script>`\n } else {\n ssrHtml = ''\n }\n // Move the route's <title>/<meta>/<link> out of the rendered body and into the head.\n // React only hoists those in the browser, after hydration — a crawler that does not run JS\n // would otherwise never see a page's own title or social card (usetheokit/theokit#319).\n const hoisted = hoistHeadTags(template, ssrHtml)\n template = hoisted.template\n ssrHtml = hoisted.html\n\n const rootDiv = findRootDiv(template)\n if (!rootDiv) {\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(template)\n return\n }\n\n const splitIdx = rootDiv.insertAt\n const html =\n template.slice(0, splitIdx) + ssrHtml + hydrationScript + template.slice(splitIdx)\n\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(html)\n } catch (err) {\n server.ssrFixStacktrace(err as Error)\n console.error('[SSR Dev Error]', err)\n // Fallback to CSR\n next()\n return\n }\n })()\n })\n}\n","/**\n * M15 (theokit-ai-first) — serve the A2A agent card at `/.well-known/<name>/agent-card.json`.\n *\n * `buildAgentCard` (@theokit/agents) is the pure generator; this handler compiles a loaded agent\n * module to its tools + streaming capability, builds the card, and returns it as a Web-Standard\n * JSON `Response` (G8). The dev middleware + prod handler branch to this before the agent POST route.\n */\nimport { type AgentManifestEntry, buildAgentCard, compileLoadedAgentModule } from '@theokit/agents'\n\nconst WELL_KNOWN = /^\\/\\.well-known\\/([^/]+)\\/agent-card\\.json$/\n\n/** Return the agent name when `urlPath` is a well-known card path, else `null`. */\nexport function isAgentCardPath(urlPath: string): string | null {\n const match = WELL_KNOWN.exec(urlPath)\n return match ? decodeURIComponent(match[1]) : null\n}\n\n/** Build a minimal manifest entry (the subset `buildAgentCard` reads) from a compiled agent. */\nfunction toManifestEntry(name: string, route: string, mod: unknown): AgentManifestEntry {\n const compiled = compileLoadedAgentModule(mod, `agent card for \"${name}\"`)\n return {\n name,\n route,\n stream: compiled.stream,\n mainLoop: { method: '', strategy: '' },\n guards: [],\n interceptors: [],\n tools: compiled.tools.map((t) => ({\n name: t.name,\n description: t.description,\n approval: false,\n trace: false,\n audit: false,\n })),\n subAgents: [],\n }\n}\n\n/**\n * Serve the A2A card for a loaded agent module. Returns 200 with the card JSON, or 500 with an\n * error body if the module is not a valid agent (fail-clear, not a silent empty card).\n */\nexport function handleAgentCard(\n mod: unknown,\n name: string,\n route: string,\n baseUrl: string,\n): Response {\n try {\n const card = buildAgentCard(toManifestEntry(name, route, mod), { baseUrl })\n return new Response(JSON.stringify(card), {\n status: 200,\n headers: { 'content-type': 'application/json; charset=utf-8' },\n })\n } catch (err) {\n return new Response(\n JSON.stringify({\n error: {\n code: 'AGENT_CARD_FAILED',\n message: err instanceof Error ? err.message : 'card build failed',\n },\n }),\n { status: 500, headers: { 'content-type': 'application/json; charset=utf-8' } },\n )\n }\n}\n","/**\n * M4 (theokit-ai-first) — the HITL approve endpoint: `POST /api/agents/<name>/approve/<approvalId>`.\n *\n * The counterpart to `mountAgent`'s HITL pause. While a gated tool holds the SDK run paused (the\n * awaited `pre_tool_call` hook), the client POSTs here with `{ approved }`; this resolves the\n * pending approval in the shared registry, which un-pauses the run (allow) or vetoes the tool (deny).\n *\n * Web-Standard `Request` → `Response`, one wiring point shared by dev (vite middleware) and prod\n * (built server) so the two never drift (EC-4 parity with `mountAgent`). The registry is INJECTED —\n * dev/prod pass the process singleton (`getApprovalRegistry`), tests pass a fresh instance.\n */\nimport type { RoutePolicy } from '../../core/contracts/route-policy.js'\nimport { validateCsrfRequest, type CsrfMode } from '../security/csrf.js'\n\nimport { admitAgentRequest, agentAccessDenied, type AgentSubjectResolver } from './agent-access.js'\nimport type { ApprovalDecision, ApprovalRegistry } from './approval-registry.js'\nimport { closePauseSpan } from './hitl-pause-spans.js'\n\n/** The path segment separating the agent name from the approval id. */\nconst APPROVE_SEGMENT = '/approve/'\n\nconst APPROVE_PATH = /^\\/api\\/agents\\/([^/]+)\\/approve\\/([^/]+)$/\n\n/**\n * The agent named by a `/api/agents/<name>/approve/<id>` path, or `null`.\n *\n * The route's own gate is the agent's declared policy, and reading the policy needs the agent —\n * which this path carries and nothing previously read (usetheokit/theokit#365).\n */\nexport function parseApprovalAgentName(urlPath: string): string | null {\n const match = APPROVE_PATH.exec(urlPath)\n return match ? decodeURIComponent(match[1]) : null\n}\n\n/**\n * Extract the `<approvalId>` from a `/api/agents/<name>/approve/<approvalId>` path.\n * Returns `null` when the path has no `/approve/` segment or an empty / nested id.\n */\nexport function parseApprovalId(urlPath: string): string | null {\n const at = urlPath.indexOf(APPROVE_SEGMENT)\n if (at === -1) return null\n const id = urlPath.slice(at + APPROVE_SEGMENT.length)\n return id.length > 0 && !id.includes('/') ? id : null\n}\n\n/** True when `urlPath` targets a HITL approve endpoint (used by dev/prod routing to branch early). */\nexport function isApprovalPath(urlPath: string): boolean {\n return urlPath.includes(APPROVE_SEGMENT)\n}\n\nfunction jsonError(status: number, code: string, message: string): Response {\n return new Response(JSON.stringify({ error: { code, message } }), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n}\n\n/**\n * M20 — cap on the serialized custom payload (16 KiB). A payload is a small structured note\n * (edited args, a reviewer comment), not a data channel — an oversized one is rejected fail-fast\n * rather than silently truncated (Rule 8).\n */\nconst MAX_PAYLOAD_BYTES = 16 * 1024\n\n/**\n * Extract an {@link ApprovalDecision} from an untrusted body; `null` when the shape is wrong.\n *\n * M20 — accepts an optional `reason` (string) and `payload` (object, capped at\n * {@link MAX_PAYLOAD_BYTES}). Backward-compatible: `{ approved }` and `{ approved, reason }` parse\n * unchanged. A non-object or oversized `payload` is rejected (returns `null` → the route 400s).\n *\n * @public\n */\nexport function parseApprovalBody(body: unknown): ApprovalDecision | null {\n if (typeof body !== 'object' || body === null) return null\n const b = body as Record<string, unknown>\n if (typeof b.approved !== 'boolean') return null\n const decision: ApprovalDecision = { approved: b.approved }\n if (b.reason !== undefined) {\n if (typeof b.reason !== 'string') return null\n decision.reason = b.reason\n }\n if (b.payload !== undefined) {\n if (typeof b.payload !== 'object' || b.payload === null || Array.isArray(b.payload)) return null\n if (JSON.stringify(b.payload).length > MAX_PAYLOAD_BYTES) return null\n decision.payload = b.payload\n }\n return decision\n}\n\n/**\n * The gates it applies (usetheokit/theokit#365):\n *\n * CSRF, which refuses a cross-origin POST and identifies nobody — and then the agent's declared\n * `policy`, which is what makes \"who is asking\" a question this endpoint can answer at all.\n * Reproduced before the policy existed: a process holding no cookie and no credential read a\n * pending id off the listing, POSTed here, and the gated tool ran.\n *\n * Ownership, which this endpoint could NOT decide until B-016 and now can, within a stated scope.\n * `mountAgent` records the run's subject on each approval it registers, for agents that DECLARE a\n * policy, and this route refuses a caller whose identity does not match. Before it, an\n * authenticated tenant could settle another tenant's approval on an agent both were admitted to —\n * the policy was the only thing between them, and the policy cannot see whose approval it is.\n *\n * Two limits, stated rather than implied. An agent that declares `'public'` records no owner, since\n * attributing approvals there would start refusing callers the declaration admits. And a thread\n * continuation runs headless, with no request whose identity could be resolved, so its approvals\n * record nobody. In both cases the endpoint behaves exactly as it did — `params.approvalId` is\n * still passed so an application holding its own owner map can answer more than the framework does.\n *\n * Returns:\n * 403 CSRF_FAILED — strict CSRF check failed\n * 403 FORBIDDEN — the agent's policy refused this caller\n * 400 BAD_REQUEST — no `/approve/<id>` in the path, or body lacks a boolean `approved`\n * 404 NOT_PENDING — the id is unknown or already settled (idempotent double-submit)\n * 200 { resolved:true } — the approval was settled by this call\n */\n/**\n * Refuse a caller who does not own this approval, where the ledger knows the owner (B-016).\n *\n * The agent's policy answers \"may this subject touch this agent's approvals\". It cannot answer \"is\n * this approval theirs\", because it is never told — which is why an authenticated tenant could\n * settle another tenant's approval on an agent both were admitted to. `mountAgent` now records the\n * run's subject on each approval it registers, for agents that DECLARE a policy, and this reads it.\n *\n * `undefined` from `ownerOf` covers three cases the endpoint treats identically — never registered,\n * already settled, and registered with no owner — and in all three there is nothing to compare a\n * caller against, so the endpoint behaves exactly as it did. The check only ever narrows.\n */\nasync function refuseIfNotOwner(\n registry: ApprovalRegistry,\n approvalId: string,\n resolveSubject: AgentSubjectResolver | undefined,\n params: Parameters<typeof agentAccessDenied>[1],\n): Promise<Response | undefined> {\n const owner = registry.ownerOf(approvalId)\n if (owner === undefined) return undefined\n\n const subject = resolveSubject === undefined ? null : await resolveSubject()\n if (subject?.id === owner) return undefined\n\n // An unidentifiable caller is refused, deliberately. An approval that HAS an owner must not be\n // settleable by whoever reaches the endpoint without an identity — admitting there would make the\n // guarantee depend on how the host wired its resolver rather than on who is asking.\n return agentAccessDenied(\n { allowed: false, reason: 'the approval belongs to another subject' },\n params,\n )\n}\n\nexport async function handleAgentApproval(\n request: Request,\n urlPath: string,\n registry: ApprovalRegistry,\n csrfMode: CsrfMode = 'strict',\n access: { policy?: RoutePolicy; resolveSubject?: AgentSubjectResolver } = {},\n): Promise<Response> {\n if (csrfMode !== 'off') {\n const csrf = validateCsrfRequest(request)\n if (!csrf.valid && csrfMode === 'strict') {\n return jsonError(403, 'CSRF_FAILED', `CSRF check failed: ${csrf.reason}`)\n }\n }\n\n const approvalId = parseApprovalId(urlPath)\n if (approvalId === null) {\n return jsonError(400, 'BAD_REQUEST', 'Approval path must be /api/agents/<name>/approve/<id>.')\n }\n\n const params = {\n agent: parseApprovalAgentName(urlPath) ?? 'unknown',\n endpoint: 'approve' as const,\n approvalId,\n }\n const decision = await admitAgentRequest(access.policy, access.resolveSubject, params)\n if (!decision.allowed) return agentAccessDenied(decision, params)\n\n const notOwner = await refuseIfNotOwner(registry, approvalId, access.resolveSubject, params)\n if (notOwner !== undefined) return notOwner\n\n let body: unknown = null\n try {\n body = await request.json()\n } catch {\n /* invalid/empty JSON → handled below as a 400 */\n }\n const parsed = parseApprovalBody(body)\n if (parsed === null) {\n return jsonError(400, 'BAD_REQUEST', 'Request body must contain a boolean `approved`.')\n }\n\n const resolved = registry.resolve(approvalId, parsed)\n if (!resolved) {\n return jsonError(404, 'NOT_PENDING', `No pending approval for id '${approvalId}'.`)\n }\n\n // THIS is the resume instant, and it is why the span could not be closed correctly before\n // (B-028). The run's observer never sees this request; it saw the tool's output arriving later\n // and closed the pause there, so the recorded wait was the human's plus the model's — measured at\n // +1523 ms on a run whose human answered at 3306 ms. Closing here, on the request that carries\n // the answer, makes the duration the human's by construction rather than by subtraction.\n closePauseSpan(approvalId, { resumeObserved: true })\n return new Response(JSON.stringify({ resolved: true }), {\n status: 200,\n headers: { 'content-type': 'application/json' },\n })\n}\n","import {\n encodeSse,\n formatSseFrame,\n RUN_ID_HEADER,\n SSE_BASE_HEADERS,\n SSE_DONE_FRAME,\n} from './durable-ui-message-stream-response.js'\nimport type { RunEventCache } from './run-event-cache.js'\n\n/**\n * M37 (ADR-0046 D5) — the reconnect / observe endpoint handler for\n * `GET /api/agents/<name>/runs/<runId>/stream`.\n *\n * Replays the frames the client missed (`seq > Last-Event-ID`, SSE-native), then\n * — if the run is still live — follows the live tail; a SECOND client can\n * observe a run a first started. Run already ended ⇒ replay + `[DONE]`. Unknown\n * `runId` ⇒ 404. The request `AbortSignal` unsubscribes on disconnect.\n */\n\nconst RUN_STREAM_PATH = /^\\/api\\/agents\\/([^/]+)\\/runs\\/([^/]+)\\/stream$/\n\n/**\n * Match `GET /api/agents/<name>/runs/<runId>/stream`; returns the decoded\n * `{ name, runId }` or `null` to fall through (mirrors `isMcpPath` etc.).\n */\nexport function isAgentRunStreamPath(urlPath: string): { name: string; runId: string } | null {\n const m = RUN_STREAM_PATH.exec(urlPath)\n return m ? { name: decodeURIComponent(m[1]), runId: decodeURIComponent(m[2]) } : null\n}\n\n/** Parse `Last-Event-ID` (a frame `seq`) to a number; absent/invalid ⇒ -1 (replay from the start). */\nfunction parseLastEventId(raw: string | null): number {\n if (raw === null) return -1\n const n = Number.parseInt(raw, 10)\n return Number.isInteger(n) && n >= 0 ? n : -1\n}\n\nexport function handleAgentRunReconnect(\n runId: string,\n request: Request,\n cache: RunEventCache,\n): Response {\n // Unknown run ⇒ 404 (a run never started here, or already evicted).\n if (!cache.has(runId)) {\n return new Response(\n JSON.stringify({ error: { code: 'RUN_NOT_FOUND', message: `Unknown run '${runId}'.` } }),\n {\n status: 404,\n headers: { 'content-type': 'application/json' },\n },\n )\n }\n\n const afterSeq = parseLastEventId(request.headers.get('last-event-id'))\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n let closed = false\n const safeEnqueue = (text: string): void => {\n if (closed) return\n try {\n controller.enqueue(encodeSse(text))\n } catch {\n /* controller already closed by an abort race — ignore */\n }\n }\n const close = (): void => {\n if (closed) return\n safeEnqueue(SSE_DONE_FRAME)\n closed = true\n try {\n controller.close()\n } catch {\n /* already closed */\n }\n }\n\n // Atomic: snapshot replay frames AND subscribe to the live tail in one tick.\n const res = cache.attach(\n runId,\n afterSeq,\n (frame) => {\n safeEnqueue(formatSseFrame(frame.seq, frame.data))\n },\n () => {\n close()\n },\n )\n // Evicted between has() and attach() (rare TOCTOU) ⇒ just end the stream.\n if (!res.known) {\n close()\n return\n }\n for (const frame of res.replay) {\n safeEnqueue(formatSseFrame(frame.seq, frame.data))\n }\n if (res.ended) {\n close()\n return\n }\n // Client disconnects ⇒ detach the live listener + close.\n request.signal.addEventListener('abort', () => {\n res.unsubscribe()\n close()\n })\n },\n })\n\n return new Response(stream, { headers: { ...SSE_BASE_HEADERS, [RUN_ID_HEADER]: runId } })\n}\n","/**\n * M39 (ADR-0048) — the thread follow-up dispatcher.\n *\n * Drives a run over the M37 durable cache HEADLESS — it iterates the SDK chunk\n * generator and `cache.append`s directly, NOT via a `Response` `ReadableStream`\n * (whose backpressure would stall a run with no HTTP reader). Subscribers read\n * from the cache via the thread / reconnect stream.\n *\n * - Post to an IDLE thread ⇒ start a run + pump.\n * - Post to an ACTIVE thread ⇒ FIFO-queue the follow-up.\n * - On terminal ⇒ `registry.endRun` hands back the next queued follow-up, which\n * is dispatched as a continuation on the SAME sessionId (⇒ the SDK continues\n * the conversation via its `ConversationStorageAdapter`).\n *\n * This adds NO agent loop — it reuses the SDK run (`startRun`) + the M37 cache.\n * Single-process (ADR-0048 D2).\n */\n\nimport type { WireChunk as UIMessageChunk } from '@theokit/presenter/wire'\n\nimport { type RunEventCache, mintRunId } from './run-event-cache.js'\nimport type { ThreadRunRegistry } from './thread-run-registry.js'\n\ninterface ThreadDispatchDeps {\n readonly registry: ThreadRunRegistry\n readonly cache: RunEventCache\n /** Start a run for a follow-up on `sessionId`; returns the SDK chunk stream. */\n readonly startRun: (sessionId: string, message: string) => AsyncIterable<UIMessageChunk>\n}\n\n/** Result of posting a follow-up: the started `runId` (idle thread) or `queued` (active thread). */\ntype PostFollowUpResult = { runId: string } | { queued: true }\n\n/**\n * Post a follow-up on a thread. IDLE ⇒ start a run (returns its `runId`); ACTIVE\n * ⇒ FIFO-queue it (returns `{ queued: true }`) — dispatched when the active run ends.\n */\nexport function postThreadFollowUp(\n deps: ThreadDispatchDeps,\n sessionId: string,\n message: string,\n): PostFollowUpResult {\n if (deps.registry.getActive(sessionId) !== null) {\n deps.registry.queue(sessionId, { message })\n return { queued: true }\n }\n return { runId: startAndPump(deps, sessionId, message) }\n}\n\n/** Mint a runId, mark the thread active, and pump the run into the cache headless. */\nfunction startAndPump(deps: ThreadDispatchDeps, sessionId: string, message: string): string {\n const runId = mintRunId()\n // Register the run in the cache SYNCHRONOUSLY (before the async pump appends its\n // first frame) so a subscriber resolving the active runId can attach immediately.\n deps.cache.begin(runId)\n deps.registry.startRun(sessionId, runId)\n pumpIntoCache(deps, sessionId, runId, deps.startRun(sessionId, message))\n return runId\n}\n\n/**\n * Drive `chunks` into the cache under `runId`, then end the run and dispatch the\n * next queued follow-up (if any) as a continuation. Fire-and-forget — the caller\n * does not await the run; subscribers observe it via the cache.\n */\nfunction pumpIntoCache(\n deps: ThreadDispatchDeps,\n sessionId: string,\n runId: string,\n chunks: AsyncIterable<UIMessageChunk>,\n): void {\n void (async () => {\n try {\n for await (const chunk of chunks) {\n deps.cache.append(runId, JSON.stringify(chunk))\n }\n } catch {\n // The SDK translator owns error semantics (surfaces failures as chunks);\n // the transport guarantees only a terminated, cache-ended run.\n } finally {\n deps.cache.end(runId)\n const next = deps.registry.endRun(sessionId, runId)\n if (next !== undefined) startAndPump(deps, sessionId, next.message)\n }\n })()\n}\n","/**\n * M39 (ADR-0048) — the in-process thread→run registry.\n *\n * A thread is the existing `sessionId` (the SDK conversation key). This registry\n * tracks, per thread, the single ACTIVE run, a FIFO queue of follow-ups to\n * dispatch as continuations, and one-shot \"next run\" waiters (so a client can\n * subscribe to a thread before posting a message and attach when the run starts).\n *\n * Pure state only — it never starts a run or touches the transport. The route\n * layer owns dispatch: on `endRun` it receives the next queued follow-up (if any)\n * and starts the continuation over the M37 durable transport.\n *\n * Single-process contract (ADR-0048 D2): a multi-instance deploy needs a shared\n * registry + leasing — that is infra (TheoCloud), explicitly out of M39. The\n * interface is injectable so a durable impl slots in later without touching the\n * routes. We do NOT build a distributed store now (YAGNI).\n */\n\n/** A follow-up message queued on an active thread, dispatched as a continuation. */\nexport interface FollowUp {\n readonly message: string\n}\n\nexport interface ThreadRunRegistry {\n /** The active runId for a thread, or `null` when the thread is idle. */\n getActive(sessionId: string): string | null\n /** Mark a run started for a thread (sets it active; fires + clears one-shot waiters). */\n startRun(sessionId: string, runId: string): void\n /**\n * Mark `runId` ended for a thread. A no-op unless `runId` is the current active\n * run (a stale terminal never clears a newer run). Clears the active run and\n * returns the next FIFO follow-up to dispatch as a continuation, or `undefined`.\n */\n endRun(sessionId: string, runId: string): FollowUp | undefined\n /** FIFO-enqueue a follow-up on a thread (dispatched when the active run ends). */\n queue(sessionId: string, followUp: FollowUp): void\n /**\n * Register a ONE-SHOT waiter fired with the runId of the NEXT run started on\n * this thread. Returns an unsubscribe fn. Used by subscribe-by-thread on an\n * idle thread (attach when the next run starts).\n */\n onNextRun(sessionId: string, cb: (runId: string) => void): () => void\n}\n\ninterface ThreadState {\n activeRunId: string | null\n readonly queue: FollowUp[]\n readonly waiters: Set<(runId: string) => void>\n}\n\nexport function createInProcessThreadRunRegistry(): ThreadRunRegistry {\n const threads = new Map<string, ThreadState>()\n const ensure = (sessionId: string): ThreadState => {\n let s = threads.get(sessionId)\n if (s === undefined) {\n s = { activeRunId: null, queue: [], waiters: new Set() }\n threads.set(sessionId, s)\n }\n return s\n }\n\n return {\n getActive(sessionId) {\n return threads.get(sessionId)?.activeRunId ?? null\n },\n startRun(sessionId, runId) {\n const s = ensure(sessionId)\n s.activeRunId = runId\n // Fire one-shot waiters, then clear them (single-threaded → no re-entrancy race).\n const waiters = [...s.waiters]\n s.waiters.clear()\n for (const cb of waiters) cb(runId)\n },\n endRun(sessionId, runId) {\n const s = threads.get(sessionId)\n if (s?.activeRunId !== runId) return undefined\n s.activeRunId = null\n return s.queue.shift()\n },\n queue(sessionId, followUp) {\n ensure(sessionId).queue.push(followUp)\n },\n onNextRun(sessionId, cb) {\n const s = ensure(sessionId)\n s.waiters.add(cb)\n return () => {\n s.waiters.delete(cb)\n }\n },\n }\n}\n\nlet serverRegistry: ThreadRunRegistry | undefined\n\n/** Process-wide singleton (mirrors `getRunEventCache` / `getApprovalRegistry`). */\nexport function getThreadRunRegistry(): ThreadRunRegistry {\n serverRegistry ??= createInProcessThreadRunRegistry()\n return serverRegistry\n}\n","/**\n * M39 (ADR-0048) — the thread signal routes over the M37 durable transport:\n *\n * - `POST /api/agents/<name>/threads/<sessionId>/message` — a follow-up. ACTIVE\n * run ⇒ FIFO-queue (dispatched as a continuation when it ends); IDLE ⇒ start a\n * run. Returns `202` (the run streams headless into the cache; observe it via\n * the thread stream). Spends LLM tokens ⇒ CSRF-gated (parity with mount-agent).\n * - `GET /api/agents/<name>/threads/<sessionId>/stream` — subscribe. ACTIVE ⇒\n * attach to the durable stream (reuse the M37 reconnect handler); IDLE ⇒ wait\n * (bounded) for the next run on the thread, then attach (subscribe-then-post).\n *\n * These DRIVE the SDK run (via `makeThreadStartRun`) + the M37 cache — no new loop.\n */\n\nimport { validateCsrfRequest, type CsrfMode } from '../security/csrf.js'\n\nimport type { ApiKeyResolver } from './api-key-resolver.js'\nimport { makeThreadStartRun } from './build-agent-streamer.js'\nimport {\n encodeSse,\n formatSseFrame,\n RUN_ID_HEADER,\n SSE_BASE_HEADERS,\n SSE_DONE_FRAME,\n} from './durable-ui-message-stream-response.js'\nimport { handleAgentRunReconnect } from './handle-agent-run-reconnect.js'\nimport { parseAgentRequestBody } from './mount-agent.js'\nimport { getRunEventCache, type RunEventCache } from './run-event-cache.js'\nimport { postThreadFollowUp } from './thread-dispatcher.js'\nimport { getThreadRunRegistry, type ThreadRunRegistry } from './thread-run-registry.js'\n\nconst THREAD_MESSAGE_PATH = /^\\/api\\/agents\\/([^/]+)\\/threads\\/([^/]+)\\/message$/\nconst THREAD_STREAM_PATH = /^\\/api\\/agents\\/([^/]+)\\/threads\\/([^/]+)\\/stream$/\n\n/** How long a subscribe-to-idle-thread waits for the next run before closing. */\nconst DEFAULT_IDLE_WAIT_MS = 30_000\n\nfunction matchThread(re: RegExp, urlPath: string): { name: string; sessionId: string } | null {\n const m = re.exec(urlPath)\n return m ? { name: decodeURIComponent(m[1]), sessionId: decodeURIComponent(m[2]) } : null\n}\n\nexport const isThreadMessagePath = (urlPath: string) => matchThread(THREAD_MESSAGE_PATH, urlPath)\nexport const isThreadStreamPath = (urlPath: string) => matchThread(THREAD_STREAM_PATH, urlPath)\n\nfunction jsonError(status: number, code: string, message: string): Response {\n return new Response(JSON.stringify({ error: { code, message } }), {\n status,\n headers: { 'content-type': 'application/json; charset=utf-8' },\n })\n}\n\n/** Inputs for {@link handleThreadMessage} (bundled to stay within the arity budget). */\ninterface ThreadMessageArgs {\n readonly mod: unknown\n /** theokit#328 — a resolver is passed through unresolved so the model can pick the provider. */\n readonly apiKey: string | ApiKeyResolver\n readonly sessionId: string\n readonly request: Request\n /** Labels a fail-fast `AgentDefinitionError`. Human-readable; never a telemetry key. */\n readonly source: string\n /**\n * The agent's name, as the scanner discovered it — the attribute an operator groups runs by.\n * Separate from {@link ThreadMessageArgs.source} since usetheokit/theokit#406: one field was\n * carrying both, and this route's `source` is the label `agent \"chat\"`.\n */\n readonly agentName: string\n readonly csrfMode?: CsrfMode\n}\n\n/** POST a follow-up on a thread. Returns `202` with `{ runId }` (started) or `{ queued: true }`. */\nexport async function handleThreadMessage(args: ThreadMessageArgs): Promise<Response> {\n const { mod, apiKey, sessionId, request, source, agentName, csrfMode = 'strict' } = args\n // A follow-up drives the agent (spends LLM tokens) — reject a cross-origin POST.\n if (csrfMode === 'strict') {\n const csrf = validateCsrfRequest(request)\n if (!csrf.valid) return jsonError(403, 'CSRF_FAILED', `CSRF check failed: ${csrf.reason}`)\n }\n let body: unknown = null\n try {\n body = await request.json()\n } catch {\n /* invalid/empty JSON → 400 below */\n }\n const input = parseAgentRequestBody(body)\n if (input === null) {\n return jsonError(400, 'BAD_REQUEST', 'Request must contain a non-empty message.')\n }\n const result = postThreadFollowUp(\n {\n registry: getThreadRunRegistry(),\n cache: getRunEventCache(),\n // usetheokit/theokit#381 — the request goes with it, so the run's spans join the trace of\n // the caller that queued it instead of opening one of their own.\n startRun: makeThreadStartRun(mod, apiKey, source, agentName, request),\n },\n sessionId,\n input.message,\n )\n const headers: Record<string, string> = { 'content-type': 'application/json; charset=utf-8' }\n if ('runId' in result) headers[RUN_ID_HEADER] = result.runId\n return new Response(JSON.stringify(result), { status: 202, headers })\n}\n\n/** GET the thread's durable stream. Active ⇒ attach now; idle ⇒ wait (bounded) for the next run. */\nexport function handleThreadStream(\n sessionId: string,\n request: Request,\n registry: ThreadRunRegistry = getThreadRunRegistry(),\n cache: RunEventCache = getRunEventCache(),\n idleWaitMs = DEFAULT_IDLE_WAIT_MS,\n): Response {\n const active = registry.getActive(sessionId)\n if (active !== null && cache.has(active)) {\n // Reuse the M37 reconnect handler — replay + live tail on the active run.\n return handleAgentRunReconnect(active, request, cache)\n }\n return waitThenAttachStream(sessionId, request, registry, cache, idleWaitMs)\n}\n\n/** Subscribe to an idle thread: wait (bounded) for the NEXT run to start, then attach + tail. */\nfunction waitThenAttachStream(\n sessionId: string,\n request: Request,\n registry: ThreadRunRegistry,\n cache: RunEventCache,\n idleWaitMs: number,\n): Response {\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n let closed = false\n const send = (text: string): void => {\n if (closed) return\n try {\n controller.enqueue(encodeSse(text))\n } catch {\n /* closed by an abort race */\n }\n }\n let detachAttach: (() => void) | undefined\n const close = (): void => {\n if (closed) return\n send(SSE_DONE_FRAME)\n closed = true\n try {\n controller.close()\n } catch {\n /* already closed */\n }\n }\n const offNext = registry.onNextRun(sessionId, (runId) => {\n const res = cache.attach(\n runId,\n -1,\n (frame) => {\n send(formatSseFrame(frame.seq, frame.data))\n },\n () => {\n close()\n },\n )\n if (!res.known) {\n close()\n return\n }\n for (const frame of res.replay) send(formatSseFrame(frame.seq, frame.data))\n if (res.ended) {\n close()\n return\n }\n detachAttach = res.unsubscribe\n })\n // HIGH-1 — the waiter teardown MUST run on BOTH the idle-wait timeout AND the\n // client abort, else the (one-shot) `onNextRun` waiter leaks in the registry\n // when a timed-out subscriber's session never receives another run.\n const teardownWaiter = (): void => {\n offNext()\n detachAttach?.()\n }\n const timer = setTimeout(() => {\n teardownWaiter()\n close()\n }, idleWaitMs)\n timer.unref()\n request.signal.addEventListener('abort', () => {\n teardownWaiter()\n clearTimeout(timer)\n close()\n })\n },\n })\n return new Response(stream, { headers: { ...SSE_BASE_HEADERS } })\n}\n","/**\n * M14 (theokit-ai-first) — GET /api/agents/<name>/approvals: list pending HITL approvals.\n *\n * Serves the approvals the CALLER owns, plus the ownerless ones, as JSON. Web Standards Response (G8).\n *\n * ## Why this is scoped, and what it closes\n *\n * The registry is process-wide by contract (ADR 0038): `list()` returns every pending approval, and\n * the `<name>` segment is accepted for a future per-agent store. That was the whole answer here, so\n * one admitted tenant of one agent received every pending approval in the process — other tenants',\n * other agents' — each with the `approvalId` the settle route needs.\n *\n * The draft advisory `GHSA-g94h-459g-rjhj` describes two steps: list without authentication, then\n * settle with an id from the listing. Both halves were closed around this file and neither in it —\n * `admitAux` refuses a caller the agent's policy does not admit (usetheokit/theokit#365), and\n * `approve-agent.ts` refuses a settle by a caller who is not the owner (B-016). The door was gated\n * and the window left open: an ADMITTED caller still read everyone's ids.\n *\n * ## An ownerless approval stays visible, deliberately\n *\n * The registry records an owner only for agents that DECLARE a policy — `admitAgentRequest` resolves\n * no subject for `'public'` or for an undeclared agent, so there is nothing to attribute. The settle\n * route already treats an absent owner as \"nothing to compare a caller against\" and refuses nobody\n * on it. Listing follows the same rule rather than inventing a second one, because hiding those\n * would blank a public agent's own approvals UI while protecting nobody.\n *\n * The filter asks `ownerOf` per approval rather than reading an owner off the listing, because\n * `owner` is held BESIDE `info` precisely so `list()` cannot leak it (B-016). Scoping the response\n * must not put the identity back into it.\n */\nimport type { ApprovalRegistry } from './approval-registry.js'\n\nconst LIST_PATH = /^\\/api\\/agents\\/([^/]+)\\/approvals$/\n\n/** Return the agent name when `urlPath` is the approvals-listing path, else `null`. */\nexport function isListApprovalsPath(urlPath: string): string | null {\n const match = LIST_PATH.exec(urlPath)\n return match ? decodeURIComponent(match[1]) : null\n}\n\n/**\n * Serve the pending approvals this caller may see as `{ approvals: [...] }` JSON.\n *\n * `subject` is the admitted caller's id, or `undefined` when the agent declares no policy and none\n * was resolved. An approval is included when it has no owner, or when its owner is this subject.\n */\nexport function handleListApprovals(\n registry: ApprovalRegistry,\n subject: string | undefined,\n): Response {\n const visible = registry.list().filter((approval) => {\n const owner = registry.ownerOf(approval.approvalId)\n return owner === undefined || owner === subject\n })\n return new Response(JSON.stringify({ approvals: visible }), {\n status: 200,\n headers: { 'content-type': 'application/json; charset=utf-8' },\n })\n}\n","/**\n * M15/M16 follow-up — shared dispatcher for the agent AUXILIARY routes that BOTH dev (vite\n * middleware) and prod (`theokit start` handler) must serve identically. Before this, these routes\n * were wired only into the dev middleware, so a built/deployed app served none of them (agent cards,\n * MCP, pending-approvals listing all 404'd in production).\n *\n * Single source of truth (DRY): one Web-Request→Response dispatcher, two callers. It handles the\n * routes that derive purely from the agent module + shared registry:\n * - **M15** `GET /.well-known/<name>/agent-card.json` → {@link handleAgentCard}\n * - **M14** `GET /api/agents/<name>/approvals` → {@link handleListApprovals}\n * - **M16** `POST /api/agents/<name>/mcp` → {@link handleMcpJsonRpc}\n * - **M37** `GET /api/agents/<name>/runs/<id>/stream` → {@link handleAgentRunReconnect}\n * - **M39** the two thread routes → {@link handleThreadMessage} / {@link handleThreadStream}\n *\n * Channels (M27) are NOT here: a channel webhook needs app-supplied `validators` + `onMessage`, so\n * the app wires `handleChannelWebhook` in its own route (it cannot be auto-derived from the module).\n * The HITL approve route stays in each caller (it carries caller-specific rate-limiting/CSRF plumbing).\n *\n * ## Deciding and answering are two functions, and that is the fix\n *\n * This used to be one call that took a not-yet-converted request, decided whether it owned the path\n * and answered in the same breath. A caller could therefore learn \"this is an agent aux route\" only\n * by receiving the finished `Response` — too late to run anything around the handler. So the plugin\n * lifecycle, which every other branch of `theokit start` runs, was never run here: `onRequest`,\n * `onResponse` and `onError` fired for a file route and for the plain agent route and for none of\n * these six, and the observability plugin therefore emitted no `http.request` span for the endpoints\n * that spend tokens and settle human decisions (usetheokit/theokit#405).\n *\n * {@link matchAgentAuxRoute} decides; {@link serveMatchedAuxRoute} answers. A caller brackets the\n * gap with whatever the request lifecycle owes — and a seventh route added to the match table\n * inherits that bracket instead of having to remember it.\n */\nimport type { RouteSubject } from '../../core/contracts/route-policy.js'\nimport type { AgentNode } from '../scan/agent-scan.js'\nimport { validateCsrfRequest, type CsrfMode } from '../security/csrf.js'\n\nimport {\n admitAgentRequest,\n agentAccessDenied,\n readAgentPolicy,\n type AgentAccessParams,\n type AgentSubjectResolver,\n} from './agent-access.js'\nimport { isAgentCardPath, handleAgentCard } from './agent-card-handler.js'\nimport type { ApiKeyResolver } from './api-key-resolver.js'\nimport { getApprovalRegistry } from './approval-registry.js'\nimport { handleAgentRunReconnect, isAgentRunStreamPath } from './handle-agent-run-reconnect.js'\nimport {\n handleThreadMessage,\n handleThreadStream,\n isThreadMessagePath,\n isThreadStreamPath,\n} from './handle-thread-routes.js'\nimport { isListApprovalsPath, handleListApprovals } from './list-approvals-handler.js'\nimport { extractAppResources } from './mcp-app-resources.js'\nimport { isMcpPath, handleMcpJsonRpc } from './mcp-handler.js'\nimport { getRunEventCache } from './run-event-cache.js'\n\n/** JSON error envelope (mirrors mount-agent.ts:37 — the parity source for the MCP CSRF gate). */\nfunction jsonError(status: number, code: string, message: string): Response {\n return new Response(JSON.stringify({ error: { code, message } }), {\n status,\n headers: { 'content-type': 'application/json; charset=utf-8' },\n })\n}\n\n/** Dependencies the aux dispatcher needs from its caller (dev or prod). */\ninterface AuxRouteDeps {\n /** Discovered agents (from `scanAgents`). */\n agents: readonly AgentNode[]\n /** Load an agent module from its file path (dev: vite loader; prod: dynamic import). */\n loadModule: (filePath: string) => Promise<unknown>\n /** Absolute base URL (`http(s)://host`) for the agent-card endpoint URLs. */\n baseUrl: string\n /**\n * M34 (#97) — CSRF enforcement mode for the MCP route. `POST /api/agents/<name>/mcp` drives the\n * agent (spends LLM tokens), so a cross-origin POST MUST be rejected in `'strict'` — parity with\n * the agent-run route (`mount-agent.ts:83-91`). Defaults to `'strict'` (safe-by-default); a caller\n * that already gated upstream may pass `'off'`.\n */\n csrfMode?: CsrfMode\n /**\n * M39 — lazily resolve the provider apiKey. Required only for the thread\n * follow-up route (which drives the agent); resolved on demand so non-agent\n * aux routes (card, approvals, stream) never need a provider key.\n *\n * theokit#328 — it receives the model the agent declares, so the credential matches the provider\n * the agent asked for. It was called with no argument, before the module was even compiled, so\n * an agent declaring `anthropic/…` was handed whichever key env priority found first.\n */\n resolveApiKey?: ApiKeyResolver\n /**\n * Who is asking (usetheokit/theokit#365). Invoked ONLY from {@link serveMatchedAuxRoute}, and only\n * when the matched path's agent declares a policy — so the application's `createContext` never\n * runs for a url this dispatcher merely declines. {@link matchAgentAuxRoute} is not given it, for\n * the same reason it is not given the request body: deciding must cost nothing.\n */\n resolveSubject?: AgentSubjectResolver\n}\n\n/**\n * One aux route, already decided. Carries what the match resolved so the serve half re-derives\n * nothing: the agent node it looked up, and for MCP the module it had to open in order to answer\n * the opt-in question at all.\n */\nexport type AgentAuxRoute =\n | { readonly kind: 'card'; readonly agent: AgentNode }\n | { readonly kind: 'approvals'; readonly agent: AgentNode }\n | { readonly kind: 'run-stream'; readonly agent: AgentNode; readonly runId: string }\n | { readonly kind: 'thread-stream'; readonly agent: AgentNode; readonly sessionId: string }\n | { readonly kind: 'thread-message'; readonly agent: AgentNode; readonly sessionId: string }\n | { readonly kind: 'mcp'; readonly agent: AgentNode; readonly mod: unknown }\n\n/**\n * Resolve `name` to a discovered agent and build a route from it, or `null` when there is no name\n * (the path did not match) or no such agent (fall through to the caller's 404).\n *\n * Both misses collapse to `null` deliberately: every one of them means \"this dispatcher does not\n * answer this url\", and the path families below are mutually exclusive, so a family that declines\n * can safely let the next matcher look.\n */\nfunction routeFor<R>(\n deps: AuxRouteDeps,\n name: string | null,\n build: (agent: AgentNode) => R,\n): R | null {\n if (name === null) return null\n const agent = deps.agents.find((a) => a.name === name)\n return agent === undefined ? null : build(agent)\n}\n\n/** The GET-only aux routes: agent card, approvals listing, run stream, thread stream. */\nfunction matchGetAuxRoute(verb: string, urlPath: string, deps: AuxRouteDeps): AgentAuxRoute | null {\n if (verb !== 'GET') return null\n\n // M15 — A2A agent card at `/.well-known/<name>/agent-card.json`.\n const card = routeFor(\n deps,\n isAgentCardPath(urlPath),\n (agent) => ({ kind: 'card', agent }) as const,\n )\n if (card !== null) return card\n\n // M14 — the pending HITL approvals of one agent.\n const approvals = routeFor(\n deps,\n isListApprovalsPath(urlPath),\n (agent) => ({ kind: 'approvals', agent }) as const,\n )\n if (approvals !== null) return approvals\n\n // M37 — the durable run stream (`/runs/<runId>/stream`), reconnect or observe.\n const run = isAgentRunStreamPath(urlPath)\n if (run !== null) {\n return routeFor(\n deps,\n run.name,\n (agent) => ({ kind: 'run-stream', agent, runId: run.runId }) as const,\n )\n }\n\n // M39 — subscribe to a thread (`/threads/<sessionId>/stream`).\n const stream = isThreadStreamPath(urlPath)\n if (stream === null) return null\n return routeFor(\n deps,\n stream.name,\n (agent) => ({ kind: 'thread-stream', agent, sessionId: stream.sessionId }) as const,\n )\n}\n\n/** The POST-only aux routes: thread follow-up and MCP. */\nasync function matchPostAuxRoute(\n verb: string,\n urlPath: string,\n deps: AuxRouteDeps,\n): Promise<AgentAuxRoute | null> {\n if (verb !== 'POST') return null\n\n // M39 — a follow-up message on a thread.\n const msg = isThreadMessagePath(urlPath)\n if (msg !== null) {\n return routeFor(\n deps,\n msg.name,\n (agent) => ({ kind: 'thread-message', agent, sessionId: msg.sessionId }) as const,\n )\n }\n\n // M16 — the JSON-RPC MCP server, behind the M34 opt-in.\n const agent = routeFor(deps, isMcpPath(urlPath), (found) => found)\n if (agent === null) return null\n // M34 — DEFAULT-DENY: an agent is NOT exposed on MCP unless it explicitly opts in with a named\n // `export const mcp = true` (blueprint D5 — default-EXPOSE is the footgun magnified by the\n // multi-surface thesis). Absent the opt-in, fall through to 404 (the agent is web-only). This is a\n // breaking change from the M16 auto-mount (documented in the CHANGELOG § Security).\n const mod = await deps.loadModule(agent.filePath)\n return isMcpExposed(mod) ? { kind: 'mcp', agent, mod } : null\n}\n\n/**\n * Does this dispatcher own `urlPath`? Returns the matched route, or `null` to fall through (not an\n * aux path, wrong method, unknown agent, or an agent that did not opt into MCP).\n *\n * theokit#400 — this function is where the \"convert only on a path you are about to answer\" rule\n * now lives, and it is enforced by the signature rather than by discipline: it is handed a method\n * and a url and has no request to convert. Converting in order to decide is what drained the Node\n * body stream on every path this dispatcher declined, so an ordinary `POST /api/…` file route then\n * waited forever for an `'end'` that had already fired — no status, no timeout, no response.\n *\n * The one branch that does real work here is MCP, which must open the module to read its\n * `export const mcp` opt-in. That is deliberate: a match that could still fall through would hand\n * the caller a request it had already started a lifecycle for, and the span opened for it would\n * either double-count or never close.\n */\nexport async function matchAgentAuxRoute(\n method: string,\n urlPath: string,\n deps: AuxRouteDeps,\n): Promise<AgentAuxRoute | null> {\n const verb = method.toUpperCase()\n return matchGetAuxRoute(verb, urlPath, deps) ?? (await matchPostAuxRoute(verb, urlPath, deps))\n}\n\n/** What {@link admitAux} decided, and — when a policy declared one — who was admitted. */\ninterface Admission {\n readonly refusal: Response | null\n /** The admitted caller's id, or `undefined` when no policy asked for one. */\n readonly subject: string | undefined\n}\n\n/**\n * Evaluate the agent's declared policy for one aux endpoint.\n *\n * Returns the refusal `Response`, or `null` when the caller is admitted. Loading the module here is\n * what makes the gate reachable at all: the policy is an export of the agent file, and three of\n * these branches previously answered without ever opening it.\n */\nasync function admitAux(\n deps: AuxRouteDeps,\n agent: AgentNode,\n params: AgentAccessParams,\n body?: unknown,\n): Promise<Admission> {\n const mod = await deps.loadModule(agent.filePath)\n // The subject is RECORDED rather than resolved twice. `admitAgentRequest` returns before touching\n // the resolver when the policy is absent or `'public'`, which is the guarantee `resolveSubject`'s\n // own docblock makes: the application's `createContext` must not run for a url this dispatcher\n // merely declines. Wrapping preserves that exactly — `seen` stays `undefined` in those cases —\n // while the approvals branch gets the id it needs to scope its answer.\n const resolve = deps.resolveSubject\n // A box rather than a `let`: the assignment happens inside a closure the compiler cannot see as\n // reachable before the read, so a plain binding narrows to `never` and `seen?.id` stops compiling.\n const admitted: { subject: RouteSubject | null } = { subject: null }\n const recording: AgentSubjectResolver | undefined =\n resolve === undefined\n ? undefined\n : async () => {\n admitted.subject = await resolve()\n return admitted.subject\n }\n const decision = await admitAgentRequest(\n readAgentPolicy(mod, agent.filePath),\n recording,\n params,\n body,\n )\n const refusal = decision.allowed ? null : agentAccessDenied(decision, params)\n return { refusal, subject: admitted.subject?.id }\n}\n\n/**\n * Answer a route {@link matchAgentAuxRoute} already claimed. Always returns a `Response` — every\n * fall-through was decided upstream, which is what lets a caller open a request span before this\n * runs and be sure something will close it.\n */\nexport async function serveMatchedAuxRoute(\n route: AgentAuxRoute,\n request: Request,\n deps: AuxRouteDeps,\n): Promise<Response> {\n if (route.kind === 'card') {\n const mod = await deps.loadModule(route.agent.filePath)\n return handleAgentCard(mod, route.agent.name, route.agent.agentPath, deps.baseUrl)\n }\n\n // usetheokit/theokit#365 — the approvals listing used to answer 200 with every pending approval\n // id to anyone who asked, and the id is all the approve route needs to settle a paused tool.\n if (route.kind === 'approvals') {\n const admission = await admitAux(deps, route.agent, {\n agent: route.agent.name,\n endpoint: 'approvals',\n })\n if (admission.refusal !== null) return admission.refusal\n // SCOPED to this caller. `admitAux` answered \"may you touch this agent's approvals\"; it cannot\n // answer \"which of them are yours\", and the registry is process-wide by contract (ADR 0038).\n return handleListApprovals(getApprovalRegistry(), admission.subject)\n }\n\n // M37 — INTENTIONALLY open (no CSRF, no auth gate): a GET is not CSRF-vulnerable, the run-start\n // POST is already gated, and the `runId` is a 122-bit UUID minted BY THE SERVER (`mintRunId`) and\n // handed only to the caller that started the run — a capability the framework issued rather than\n // a name the caller chose. That is the property the thread and conversation keys lack, and it is\n // the whole of the difference. Observe-by-runId is a FEATURE (ADR-0046 D5). Do NOT add a\n // custom-header CSRF check here: browsers send NO custom headers with `EventSource`, so it would\n // break native SSE reconnect.\n if (route.kind === 'run-stream') {\n return handleAgentRunReconnect(route.runId, request, getRunEventCache())\n }\n\n if (route.kind === 'mcp') return serveMcpRoute(route, request, deps)\n\n return serveThreadRoute(route, request, deps)\n}\n\n/**\n * M39 — serve the thread routes:\n * - `POST .../threads/<sessionId>/message` (follow-up) — loads the module, drives\n * the run headless via the thread dispatcher. Needs `resolveApiKey` (drives the\n * agent) → 501 when absent (rather than a silent 404).\n * - `GET .../threads/<sessionId>/stream` (subscribe) — attach to the active/next\n * run's durable stream. INTENTIONALLY open (GET, no custom headers — like the\n * M37 reconnect route).\n *\n * SECURITY (thread stream): unlike the M37 reconnect route — keyed on an\n * `mintRunId()` UUID (122-bit unguessable) — the thread stream is keyed on the\n * caller-supplied `sessionId`, so an app using a PREDICTABLE sessionId (a user id,\n * an email, a tenant-derived key) is one guess away from another party reading the\n * thread's live conversation.\n *\n * usetheokit/theokit#365 — this paragraph used to end by telling the application it\n * \"MUST add its own auth gate before this endpoint\", and no such gate was constructible:\n * the URL is dispatched before route matching, so no `route()` and no middleware ever\n * saw it. The gate is the agent's own `export const policy`, evaluated here, and the\n * instruction is now one an application can follow.\n */\nasync function serveThreadRoute(\n route: Extract<AgentAuxRoute, { kind: 'thread-stream' | 'thread-message' }>,\n request: Request,\n deps: AuxRouteDeps,\n): Promise<Response> {\n const { agent, sessionId } = route\n\n if (route.kind === 'thread-stream') {\n const { refusal } = await admitAux(deps, agent, {\n agent: agent.name,\n endpoint: 'thread-stream',\n sessionId,\n })\n return refusal ?? handleThreadStream(sessionId, request)\n }\n\n const { refusal } = await admitAux(deps, agent, {\n agent: agent.name,\n endpoint: 'thread-message',\n sessionId,\n })\n if (refusal !== null) return refusal\n if (deps.resolveApiKey === undefined) {\n // MEDIUM-1 — the path matched but the caller wired no provider-key resolver.\n // Fail loudly (501) instead of a silent 404 that reads as \"route not found\".\n return jsonError(\n 501,\n 'NOT_CONFIGURED',\n 'Thread follow-up requires a provider API key (resolveApiKey was not provided to serveMatchedAuxRoute).',\n )\n }\n const mod = await deps.loadModule(agent.filePath)\n return handleThreadMessage({\n mod,\n // Passed unresolved: `makeThreadStartRun` calls it once the module is compiled and the\n // model is known (theokit#328).\n apiKey: deps.resolveApiKey,\n sessionId,\n request,\n source: `agent \"${agent.name}\"`,\n // usetheokit/theokit#406 — the label above reads well in an `AgentDefinitionError` and is not\n // a name; the spans get the name, so the same agent is one series whichever route started it.\n agentName: agent.name,\n csrfMode: deps.csrfMode ?? 'strict',\n })\n}\n\n/**\n * Serve the MCP route with the M34 gates. The opt-in check already ran in the match (it is what\n * decides ownership), so what is left here is: default-DENY policy → CSRF → dispatch.\n */\nasync function serveMcpRoute(\n route: Extract<AgentAuxRoute, { kind: 'mcp' }>,\n request: Request,\n deps: AuxRouteDeps,\n): Promise<Response> {\n const { agent, mod } = route\n\n // usetheokit/theokit#365 — the MCP route drives the agent and reaches its tools, so it answers to\n // the same declared policy as the run route.\n const mcpParams = { agent: agent.name, endpoint: 'mcp' as const }\n const mcpDecision = await admitAgentRequest(\n readAgentPolicy(mod, agent.filePath),\n deps.resolveSubject,\n mcpParams,\n )\n if (!mcpDecision.allowed) return agentAccessDenied(mcpDecision, mcpParams)\n\n // M34 (#97) — enforce CSRF BEFORE any work. The MCP route drives the agent (real LLM tokens), so a\n // cross-origin POST must be rejected — parity with the agent-run route (`mount-agent.ts:83-91`).\n const csrfMode = deps.csrfMode ?? 'strict'\n if (csrfMode === 'strict') {\n const csrf = validateCsrfRequest(request)\n if (!csrf.valid) return jsonError(403, 'CSRF_FAILED', `CSRF check failed: ${csrf.reason}`)\n }\n\n let body: unknown = null\n try {\n body = await request.json()\n } catch {\n /* malformed/empty JSON → handleMcpJsonRpc returns a -32600 envelope */\n }\n // M30 — pass the agent's declared `ui://` App resources (named `appResources` export) so the MCP\n // server advertises + serves them via resources/list + resources/read.\n return handleMcpJsonRpc(mod, agent.name, body, extractAppResources(mod))\n}\n\n/**\n * M34 — DEFAULT-DENY opt-in check: is this agent module exposed on the MCP surface? An agent opts in\n * with a named `export const mcp = true` (mirroring the `appResources` named-export convention).\n * Anything else (absent / falsy) → NOT exposed. Read at the emit layer (blueprint D5).\n */\nfunction isMcpExposed(mod: unknown): boolean {\n return (mod as { mcp?: unknown } | null | undefined)?.mcp === true\n}\n","/**\n * One bracket around a Node-dispatched request, so every agent branch has the same lifecycle\n * (theokit#324, usetheokit/theokit#405).\n *\n * ## Why this is a function and not a paragraph in a review checklist\n *\n * `executeRoute` and `executeAction` have run the plugin lifecycle since the beginning. The agent\n * branches did not, and they were fixed one at a time: theokit#324 taught the plain\n * `POST /api/agents/<name>` to call `applyDecorations` → `runOnRequest` → handler →\n * `runOnResponse`, with `runOnError` on the failure path, and copied that shape into the dev\n * middleware. The aux routes (thread message and stream, MCP, agent card, approvals listing) and the\n * HITL approve route kept answering without it, in BOTH surfaces, so an application embedding\n * TheoKit had no supported place to observe six endpoints — two of which spend tokens and one of\n * which settles a human decision. The observability plugin is the case that made it legible: no\n * `onRequest` means no `http.request` span, and an operator reading HTTP latency or error rate sees\n * no traffic for endpoints that are serving traffic (usetheokit/theokit#405).\n *\n * A copied bracket is what let five branches drift from one. This is the bracket, once.\n *\n * ## The conversion is here, and only here\n *\n * The lifecycle needs a Web `Request` (that is what `PluginContext` carries), and converting an\n * `IncomingMessage` drains its body exactly once — a second conversion yields a Request whose body\n * is an empty closed stream, which is a silent truncation (theokit#400). So callers hand over a\n * {@link WebRequestSource}, whose `toRequest()` memoizes, and hand the SAME source to the handler\n * they wrap. Converting is therefore idempotent across the bracket, by construction rather than by\n * anyone noticing.\n *\n * The caller must still only enter this bracket on a path it is about to answer: `toRequest()` runs\n * here, and running it to decide ownership is the theokit#400 hang.\n */\nimport type { ServerResponse } from 'node:http'\n\nimport type { PluginContext } from '../plugin-types.js'\nimport type { PluginRunner } from '../plugins/plugin-runner.js'\n\nimport type { WebRequestSource } from './node-request.js'\nimport { sendError } from './send-response.js'\n\n/** What the bracket needs from the branch it wraps. */\nexport interface PluginLifecycleTarget {\n /** The unconverted request. Converted once, here — see the module docstring. */\n source: WebRequestSource\n res: ServerResponse\n requestId: string\n /** Absent ⇒ no plugins are registered, and the bracket costs one object allocation. */\n pluginRunner: PluginRunner | undefined\n /** The 500 message when the handler (or the conversion) throws, e.g. `'Agent handler failed'`. */\n failureMessage: string\n}\n\nfunction messageOf(err: unknown, fallback: string): string {\n return err instanceof Error ? err.message : fallback\n}\n\n/**\n * Run `serve` inside the plugin lifecycle: decorations, `onRequest` (which may short-circuit),\n * the handler, `onError` on a throw, and `onResponse` after the response is written.\n *\n * Mirrors `executeRoute`'s shape deliberately — same `PluginContext`, same short-circuit contract,\n * same `onError` placement. An agent route should not have a lifecycle of its own.\n *\n * Never throws: a handler failure becomes a 500 through the same `sendError` envelope the branches\n * used before, so the caller's `logRequest` still reads a settled `res.statusCode`.\n */\nexport async function serveThroughPluginLifecycle(\n target: PluginLifecycleTarget,\n serve: (request: Request, pluginCtx: PluginContext) => Promise<void>,\n): Promise<void> {\n const { res, requestId, pluginRunner, failureMessage } = target\n\n let request: Request\n try {\n request = target.source.toRequest()\n } catch (err) {\n // A request the adapter cannot represent is a 500, exactly as it was before these branches grew\n // a lifecycle — the conversion used to sit inside the handler's own try.\n sendError(res, 'INTERNAL', messageOf(err, failureMessage), 500, undefined, requestId)\n return\n }\n\n const pluginCtx: PluginContext = { request, response: res, ctx: {}, requestId }\n\n if (pluginRunner) {\n pluginRunner.applyDecorations(pluginCtx.ctx)\n const onRequest = await pluginRunner.runOnRequest(pluginCtx)\n // A hook that answered the request stops the pipeline — the same guarantee `executeRoute` gives.\n if (onRequest.shortCircuited) return\n }\n\n try {\n await serve(request, pluginCtx)\n } catch (err) {\n if (pluginRunner) await pluginRunner.runOnError(pluginCtx, err)\n sendError(res, 'INTERNAL', messageOf(err, failureMessage), 500, undefined, requestId)\n }\n\n // After the response is written, as `executeRoute` does — a hook here observes a completed turn.\n if (pluginRunner) await pluginRunner.runOnResponse(pluginCtx)\n}\n","/**\n * Who is asking, on the Node dispatch path that serves the agent endpoints\n * (usetheokit/theokit#365).\n *\n * `executeRoute` answers this with `subjectFromContext(ctx)`, where `ctx` is the run context built\n * from the application's `server/context.ts` plus plugin decorations. The agent branches build no\n * such context — which is why `mountAgent`'s `subject` option had nowhere to come from and every\n * caller left it out. This builds the same context from the same two sources, so the agent surface\n * reads identity from the seam the routes already read it from rather than from a second one.\n *\n * ## Why it returns a resolver instead of a subject\n *\n * `tryServeAgentAux` runs for EVERY url, including the ones it does not own. Resolving eagerly\n * there would execute the application's `createContext` twice on every route request — once in the\n * aux branch that falls through, once in the route executor. So callers get a memoized thunk and\n * invoke it only on a path they are about to answer, which is the same discipline theokit#400\n * imposed on `source.toRequest()` for the same dispatcher.\n *\n * ## What `createContext` can read here, and what it cannot (usetheokit/theokit#415)\n *\n * **Headers and cookies: yes. The request body: no.**\n *\n * This used to state the opposite as a MUST — \"invoke it before converting the request to a Web\n * `Request`\" — and no caller could honour it. The laziness argued for directly above is what makes\n * it unsatisfiable: the invocation necessarily happens INSIDE the handler, and the handler is\n * entered after `serveThroughPluginLifecycle` has already called `source.toRequest()` at the top of\n * its bracket. `incomingMessageToWebRequest` attaches the Node readable as the request body\n * (`body: webStream, duplex: 'half'`), so by the time an application's `createContext` receives\n * that `IncomingMessage`, the stream is consumed.\n *\n * The contract was written for an EAGER resolver and kept when the resolver became lazy. Both\n * decisions were right on their own; the sentence joining them was not, and it pointed callers at\n * something impossible while implying a capability that does not exist.\n *\n * Practically this costs little — identity is overwhelmingly a header or a cookie, and both survive\n * the conversion untouched. What it costs an application that resolves identity from the BODY is an\n * empty read or a wait for an `'end'` that already fired, which is why saying so plainly matters\n * more than the frequency suggests.\n *\n * Restoring body access would mean resolving eagerly — running the application's `createContext`\n * twice on every route request, which is exactly what the laziness exists to prevent — or buffering\n * every agent request body to replay it, which is a cost paid by every caller for a case almost\n * none has.\n */\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport { subjectFromContext, type RouteSubject } from '../../core/contracts/route-policy.js'\nimport type { PluginRunner } from '../plugins/plugin-runner.js'\nimport type { LoadModule } from '../scan/module-loader.js'\n\nimport { createServerContext } from './middleware-runner.js'\n\n/** What {@link createAgentSubjectResolver} needs in order to build the run context. */\nexport interface AgentSubjectSources {\n req: IncomingMessage\n res: ServerResponse\n loadModule: LoadModule\n /** The app's `server/` directory. Absent ⇒ there is no `context.ts` to consult. */\n serverDir: string | undefined\n pluginRunner: PluginRunner | undefined\n}\n\n/**\n * Build a memoized resolver for the caller's identity.\n *\n * Decorations are applied ON TOP of the factory's result, matching `executeRoute`: a plugin\n * decoration wins only where `context.ts` did not set the same key.\n *\n * A `createContext` that throws is not swallowed — an application whose identity resolution is\n * broken must not be treated as an anonymous caller, because that reads as a clean refusal and\n * hides the fault. The throw reaches the branch's own error handler and becomes a 500.\n */\nexport function createAgentSubjectResolver(\n sources: AgentSubjectSources,\n): () => Promise<RouteSubject | null> {\n let pending: Promise<RouteSubject | null> | undefined\n return () => {\n pending ??= resolve(sources)\n return pending\n }\n}\n\nasync function resolve(sources: AgentSubjectSources): Promise<RouteSubject | null> {\n const { req, res, loadModule, serverDir, pluginRunner } = sources\n const produced =\n serverDir === undefined ? {} : await createServerContext(req, res, loadModule, serverDir)\n const ctx = (produced ?? {}) as Record<string, unknown>\n pluginRunner?.applyDecorations(ctx)\n return subjectFromContext(ctx)\n}\n"],"mappings":"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","names":["resolve","resolve","jsonError","jsonError","agent","resolve","refusal","messageOf","resolve"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/contracts/route-policy.ts"],"mappings":";AAyDO,SAAS,mBAAmB,SAAuC;AACxE,MAAI,YAAY,QAAQ,OAAO,YAAY,SAAU,QAAO;AAI5D,MACE,OAAQ,QAAqC,eAAe,cAC5D,EAAE,aAAa,UACf;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IAIF;AAAA,EACF;AACA,QAAM,YAAa,QAAkC;AACrD,MAAI,cAAc,QAAQ,cAAc,UAAa,OAAO,cAAc,SAAU,QAAO;AAC3F,QAAM,KAAM,UAA+B;AAC3C,SAAO,OAAO,OAAO,YAAY,GAAG,SAAS,IAAK,YAA6B;AACjF;AAoBA,eAAsB,oBACpB,QACA,OACyB;AACzB,MAAI,WAAW,OAAW,QAAO,EAAE,SAAS,KAAK;AACjD,MAAI,WAAW,SAAU,QAAO,EAAE,SAAS,KAAK;AAEhD,QAAM,UAAU,MAAM,OAAO,KAAK;AAClC,MAAI,OAAO,YAAY,WAAW;AAChC,WAAO,UAAU,EAAE,SAAS,KAAK,IAAI,EAAE,SAAS,OAAO,QAAQ,gCAAgC;AAAA,EACjG;AACA,SAAO;AACT;AASO,SAAS,aACd,SACA,SACgB;AAChB,MAAI,YAAY,KAAM,QAAO,EAAE,SAAS,OAAO,QAAQ,oBAAoB;AAC3E,MAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG;AAIvD,WAAO,EAAE,SAAS,OAAO,QAAQ,iCAAiC;AAAA,EACpE;AACA,SAAO,QAAQ,OAAO,UAClB,EAAE,SAAS,KAAK,IAChB,EAAE,SAAS,OAAO,QAAQ,qCAAqC;AACrE;","names":[]}