theokit 0.74.2 → 0.74.3

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 (95) hide show
  1. package/dist/{actions-virtual-module-JV7URROJ.js → actions-virtual-module-4J7Z37Y4.js} +2 -2
  2. package/dist/{actions-virtual-module-J2HYO7QZ.js → actions-virtual-module-MIQJEHKJ.js} +2 -2
  3. package/dist/adapters/agent-mount.js +2 -2
  4. package/dist/{agent-5J7CQAYR.js → agent-QJINXU6U.js} +2 -2
  5. package/dist/{app-typed-client-XD4DZBV7.js → app-typed-client-AZMUYIYV.js} +2 -2
  6. package/dist/{app-typed-client-EOA3A2AR.js → app-typed-client-DSS23KDC.js} +2 -2
  7. package/dist/{aws-lambda-ZYSPTD3O.js → aws-lambda-K5Y6XS5V.js} +4 -4
  8. package/dist/{build-7YZSJGP2.js → build-4NRHCMFB.js} +23 -19
  9. package/dist/build-4NRHCMFB.js.map +1 -0
  10. package/dist/{bun-I7YM3RDB.js → bun-VPXMWFBA.js} +6 -4
  11. package/dist/bun-VPXMWFBA.js.map +1 -0
  12. package/dist/{chunk-SG62LZOJ.js → chunk-25OXNMVO.js} +4 -4
  13. package/dist/{chunk-QX5Q3FBJ.js → chunk-7FIK5NKN.js} +10 -10
  14. package/dist/{chunk-SHIXTMQE.js → chunk-DA3GGICE.js} +16 -2
  15. package/dist/{chunk-SHIXTMQE.js.map → chunk-DA3GGICE.js.map} +1 -1
  16. package/dist/{chunk-ZNZISJDZ.js → chunk-L4V5V2TI.js} +1 -1
  17. package/dist/{chunk-ZNZISJDZ.js.map → chunk-L4V5V2TI.js.map} +1 -1
  18. package/dist/{chunk-UFBBFP75.js → chunk-NLHAYGQQ.js} +2 -2
  19. package/dist/{chunk-X2LFNDJQ.js → chunk-NX3P5MLH.js} +2 -2
  20. package/dist/{chunk-2NG5T77O.js → chunk-R4AMIBZL.js} +16 -2
  21. package/dist/{chunk-2NG5T77O.js.map → chunk-R4AMIBZL.js.map} +1 -1
  22. package/dist/{chunk-NQZIQJFH.js → chunk-SHFZKJCU.js} +7 -7
  23. package/dist/{chunk-QAS5SKZP.js → chunk-VD3BCME6.js} +2 -2
  24. package/dist/{chunk-SZWGXHY3.js → chunk-VOXLI66L.js} +2 -2
  25. package/dist/{chunk-HK57MPSZ.js → chunk-VPK7ABMB.js} +2 -2
  26. package/dist/cli/index.js +9 -9
  27. package/dist/{cloudflare-Q5SUXRXY.js → cloudflare-PRTTYWRD.js} +3 -3
  28. package/dist/{config-support-MOZYHRWG.js → config-support-HUZ4DXR7.js} +3 -3
  29. package/dist/{deno-deploy-XW3Q6OMD.js → deno-deploy-ALX36LID.js} +3 -3
  30. package/dist/{dev-FZ4OTCPT.js → dev-LMZGOV4M.js} +7 -7
  31. package/dist/index.js +3 -3
  32. package/dist/{info-SUX7QVA3.js → info-XURFOBRF.js} +4 -4
  33. package/dist/{internal-api-GKPJYL3G.js → internal-api-ATSPOXI2.js} +2 -2
  34. package/dist/{internal-api-ZUBUYGCQ.js → internal-api-XPT4GLYX.js} +2 -2
  35. package/dist/{load-config-52H3EKAA.js → load-config-2DXLI7NW.js} +4 -4
  36. package/dist/{mcp-VUHRRX36.js → mcp-4CXNOZA4.js} +3 -3
  37. package/dist/{netlify-ALPCTQFO.js → netlify-2D2TM2UW.js} +3 -3
  38. package/dist/node-LORYECWI.js +10 -0
  39. package/dist/{openapi-C4UX2SFV.js → openapi-UJSUQPNT.js} +4 -4
  40. package/dist/{preview-II33QNAC.js → preview-LHNJSLS6.js} +3 -3
  41. package/dist/registry-QSJ7X5NO.js +34 -0
  42. package/dist/{routes-3PTNISSO.js → routes-ENMU4GAN.js} +4 -4
  43. package/dist/{schema-LHNWUR4V.js → schema-DJH3IOVR.js} +3 -3
  44. package/dist/{server-boundary-QCJNECJP.js → server-boundary-JM72DQLA.js} +2 -2
  45. package/dist/{server-boundary-RTRPHX5I.js → server-boundary-K4YQXDQT.js} +2 -2
  46. package/dist/{services-typed-client-XGT5SUUN.js → services-typed-client-FOBFCRD6.js} +2 -2
  47. package/dist/{start-EREUCSN6.js → start-GAULIE5E.js} +7 -7
  48. package/dist/{static-7LP7LPGN.js → static-O2RZ5NLR.js} +3 -3
  49. package/dist/{theo-cloud-GIA67L4Q.js → theo-cloud-B4R7GCWK.js} +3 -3
  50. package/dist/{vercel-VLR52RXT.js → vercel-INHLOCSZ.js} +3 -3
  51. package/dist/vite-plugin/index.js +3 -3
  52. package/dist/{vite-plugin-3LTZJTUM.js → vite-plugin-NXWE2AVM.js} +7 -7
  53. package/package.json +1 -1
  54. package/dist/build-7YZSJGP2.js.map +0 -1
  55. package/dist/bun-I7YM3RDB.js.map +0 -1
  56. package/dist/node-4HQO6KKZ.js +0 -10
  57. package/dist/registry-WVUO2WNR.js +0 -34
  58. /package/dist/{actions-virtual-module-JV7URROJ.js.map → actions-virtual-module-4J7Z37Y4.js.map} +0 -0
  59. /package/dist/{actions-virtual-module-J2HYO7QZ.js.map → actions-virtual-module-MIQJEHKJ.js.map} +0 -0
  60. /package/dist/{agent-5J7CQAYR.js.map → agent-QJINXU6U.js.map} +0 -0
  61. /package/dist/{app-typed-client-XD4DZBV7.js.map → app-typed-client-AZMUYIYV.js.map} +0 -0
  62. /package/dist/{app-typed-client-EOA3A2AR.js.map → app-typed-client-DSS23KDC.js.map} +0 -0
  63. /package/dist/{aws-lambda-ZYSPTD3O.js.map → aws-lambda-K5Y6XS5V.js.map} +0 -0
  64. /package/dist/{chunk-SG62LZOJ.js.map → chunk-25OXNMVO.js.map} +0 -0
  65. /package/dist/{chunk-QX5Q3FBJ.js.map → chunk-7FIK5NKN.js.map} +0 -0
  66. /package/dist/{chunk-UFBBFP75.js.map → chunk-NLHAYGQQ.js.map} +0 -0
  67. /package/dist/{chunk-X2LFNDJQ.js.map → chunk-NX3P5MLH.js.map} +0 -0
  68. /package/dist/{chunk-NQZIQJFH.js.map → chunk-SHFZKJCU.js.map} +0 -0
  69. /package/dist/{chunk-QAS5SKZP.js.map → chunk-VD3BCME6.js.map} +0 -0
  70. /package/dist/{chunk-SZWGXHY3.js.map → chunk-VOXLI66L.js.map} +0 -0
  71. /package/dist/{chunk-HK57MPSZ.js.map → chunk-VPK7ABMB.js.map} +0 -0
  72. /package/dist/{cloudflare-Q5SUXRXY.js.map → cloudflare-PRTTYWRD.js.map} +0 -0
  73. /package/dist/{config-support-MOZYHRWG.js.map → config-support-HUZ4DXR7.js.map} +0 -0
  74. /package/dist/{deno-deploy-XW3Q6OMD.js.map → deno-deploy-ALX36LID.js.map} +0 -0
  75. /package/dist/{dev-FZ4OTCPT.js.map → dev-LMZGOV4M.js.map} +0 -0
  76. /package/dist/{info-SUX7QVA3.js.map → info-XURFOBRF.js.map} +0 -0
  77. /package/dist/{internal-api-GKPJYL3G.js.map → internal-api-ATSPOXI2.js.map} +0 -0
  78. /package/dist/{internal-api-ZUBUYGCQ.js.map → internal-api-XPT4GLYX.js.map} +0 -0
  79. /package/dist/{load-config-52H3EKAA.js.map → load-config-2DXLI7NW.js.map} +0 -0
  80. /package/dist/{mcp-VUHRRX36.js.map → mcp-4CXNOZA4.js.map} +0 -0
  81. /package/dist/{netlify-ALPCTQFO.js.map → netlify-2D2TM2UW.js.map} +0 -0
  82. /package/dist/{node-4HQO6KKZ.js.map → node-LORYECWI.js.map} +0 -0
  83. /package/dist/{openapi-C4UX2SFV.js.map → openapi-UJSUQPNT.js.map} +0 -0
  84. /package/dist/{preview-II33QNAC.js.map → preview-LHNJSLS6.js.map} +0 -0
  85. /package/dist/{registry-WVUO2WNR.js.map → registry-QSJ7X5NO.js.map} +0 -0
  86. /package/dist/{routes-3PTNISSO.js.map → routes-ENMU4GAN.js.map} +0 -0
  87. /package/dist/{schema-LHNWUR4V.js.map → schema-DJH3IOVR.js.map} +0 -0
  88. /package/dist/{server-boundary-QCJNECJP.js.map → server-boundary-JM72DQLA.js.map} +0 -0
  89. /package/dist/{server-boundary-RTRPHX5I.js.map → server-boundary-K4YQXDQT.js.map} +0 -0
  90. /package/dist/{services-typed-client-XGT5SUUN.js.map → services-typed-client-FOBFCRD6.js.map} +0 -0
  91. /package/dist/{start-EREUCSN6.js.map → start-GAULIE5E.js.map} +0 -0
  92. /package/dist/{static-7LP7LPGN.js.map → static-O2RZ5NLR.js.map} +0 -0
  93. /package/dist/{theo-cloud-GIA67L4Q.js.map → theo-cloud-B4R7GCWK.js.map} +0 -0
  94. /package/dist/{vercel-VLR52RXT.js.map → vercel-INHLOCSZ.js.map} +0 -0
  95. /package/dist/{vite-plugin-3LTZJTUM.js.map → vite-plugin-NXWE2AVM.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import "tsx/esm";
3
- import "./chunk-SHIXTMQE.js";
3
+ import "./chunk-DA3GGICE.js";
4
4
  import "./chunk-BINRCILF.js";
5
5
  import "./chunk-FNJVSFEC.js";
6
6
  import "./chunk-WSMLSIS5.js";
@@ -218,4 +218,4 @@ export const actions = manifest
218
218
  export {
219
219
  actionsVirtualModule
220
220
  };
221
- //# sourceMappingURL=actions-virtual-module-JV7URROJ.js.map
221
+ //# sourceMappingURL=actions-virtual-module-4J7Z37Y4.js.map
@@ -1,5 +1,5 @@
1
1
  import "./chunk-D7STTNQN.js";
2
- import "./chunk-2NG5T77O.js";
2
+ import "./chunk-R4AMIBZL.js";
3
3
  import "./chunk-WSOAN4KN.js";
4
4
  import "./chunk-ENSFCKP6.js";
5
5
  import "./chunk-2Z7TANA4.js";
@@ -234,4 +234,4 @@ export const actions = manifest
234
234
  export {
235
235
  actionsVirtualModule
236
236
  };
237
- //# sourceMappingURL=actions-virtual-module-J2HYO7QZ.js.map
237
+ //# sourceMappingURL=actions-virtual-module-MIQJEHKJ.js.map
@@ -3,10 +3,10 @@ import {
3
3
  createSubjectResolverFromFactory,
4
4
  matchAgentAuxRoute,
5
5
  serveMatchedAuxRoute
6
- } from "../chunk-HK57MPSZ.js";
6
+ } from "../chunk-VPK7ABMB.js";
7
7
  import {
8
8
  mountAgent
9
- } from "../chunk-2NG5T77O.js";
9
+ } from "../chunk-R4AMIBZL.js";
10
10
  import "../chunk-SYIQV4UH.js";
11
11
  import "../chunk-P6OS7652.js";
12
12
  import "../chunk-IDWN2OSG.js";
@@ -3,7 +3,7 @@ import "tsx/esm";
3
3
  import {
4
4
  agentCommand,
5
5
  createAgentSsrLoader
6
- } from "./chunk-SG62LZOJ.js";
6
+ } from "./chunk-25OXNMVO.js";
7
7
  import "./chunk-BINRCILF.js";
8
8
  import "./chunk-HKF6YNY4.js";
9
9
  import "./chunk-Z7CJHDLS.js";
@@ -12,4 +12,4 @@ export {
12
12
  agentCommand,
13
13
  createAgentSsrLoader
14
14
  };
15
- //# sourceMappingURL=agent-5J7CQAYR.js.map
15
+ //# sourceMappingURL=agent-QJINXU6U.js.map
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import "tsx/esm";
3
- import "./chunk-SHIXTMQE.js";
3
+ import "./chunk-DA3GGICE.js";
4
4
  import "./chunk-BINRCILF.js";
5
5
  import {
6
6
  scanControllerModules
@@ -411,4 +411,4 @@ export {
411
411
  generateClientDts,
412
412
  shouldReemitForFile
413
413
  };
414
- //# sourceMappingURL=app-typed-client-XD4DZBV7.js.map
414
+ //# sourceMappingURL=app-typed-client-AZMUYIYV.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  scanControllerModules
3
3
  } from "./chunk-D7STTNQN.js";
4
- import "./chunk-2NG5T77O.js";
4
+ import "./chunk-R4AMIBZL.js";
5
5
  import "./chunk-WSOAN4KN.js";
6
6
  import "./chunk-ENSFCKP6.js";
7
7
  import "./chunk-2Z7TANA4.js";
@@ -427,4 +427,4 @@ export {
427
427
  generateClientDts,
428
428
  shouldReemitForFile
429
429
  };
430
- //# sourceMappingURL=app-typed-client-EOA3A2AR.js.map
430
+ //# sourceMappingURL=app-typed-client-DSS23KDC.js.map
@@ -22,12 +22,12 @@ import {
22
22
  } from "./chunk-EQJF2EH5.js";
23
23
  import {
24
24
  nodeAdapter
25
- } from "./chunk-UFBBFP75.js";
25
+ } from "./chunk-NLHAYGQQ.js";
26
26
  import "./chunk-WSMLSIS5.js";
27
27
  import {
28
28
  assertServicesUnsupported,
29
29
  readManifest
30
- } from "./chunk-ZNZISJDZ.js";
30
+ } from "./chunk-L4V5V2TI.js";
31
31
 
32
32
  // src/adapters/aws-lambda.ts
33
33
  import { mkdirSync } from "fs";
@@ -260,7 +260,7 @@ async function buildAwsLambda(config, cwd, deps = {}, ctx) {
260
260
  const { runNodeBuild, bundleFunction, ensureDir } = resolveAwsLambdaDeps(deps);
261
261
  assertServicesUnsupported("aws-lambda", readManifest(cwd));
262
262
  if (config.ssrStreaming) {
263
- const { assertStreamingSupported } = await import("./config-support-MOZYHRWG.js");
263
+ const { assertStreamingSupported } = await import("./config-support-HUZ4DXR7.js");
264
264
  assertStreamingSupported(config, awsLambdaAdapter, "aws-lambda");
265
265
  }
266
266
  await runNodeBuild(config, cwd, ctx);
@@ -336,4 +336,4 @@ export {
336
336
  renderAwsLambdaEntry,
337
337
  responseToLambdaResultV2
338
338
  };
339
- //# sourceMappingURL=aws-lambda-ZYSPTD3O.js.map
339
+ //# sourceMappingURL=aws-lambda-K5Y6XS5V.js.map
@@ -38,18 +38,18 @@ import {
38
38
  } from "./chunk-Z7CJHDLS.js";
39
39
  import {
40
40
  loadConfig
41
- } from "./chunk-SZWGXHY3.js";
41
+ } from "./chunk-VOXLI66L.js";
42
42
  import {
43
43
  loadEnv
44
44
  } from "./chunk-3QPVEJ7D.js";
45
45
  import {
46
46
  importUserModule
47
47
  } from "./chunk-U5PWXS3J.js";
48
- import "./chunk-X2LFNDJQ.js";
48
+ import "./chunk-NX3P5MLH.js";
49
49
  import {
50
50
  buildManifest,
51
51
  writeManifest
52
- } from "./chunk-ZNZISJDZ.js";
52
+ } from "./chunk-L4V5V2TI.js";
53
53
  import "./chunk-D2R5SJEL.js";
54
54
 
55
55
  // src/cli/commands/build.ts
@@ -463,6 +463,19 @@ async function cleanOutDir(opts) {
463
463
  return { deleted, kept };
464
464
  }
465
465
 
466
+ // src/cli/commands/build/describe-services-manifest.ts
467
+ function describeServicesManifest(manifest, target) {
468
+ if (manifest.services.length > 0) {
469
+ const projectLabel = manifest.version === 2 ? ` project="${manifest.project}"` : "";
470
+ const names = manifest.services.map((s) => s.name).join(", ");
471
+ return `\u2713 Services manifest (v${String(manifest.version)}${projectLabel}): ${String(manifest.services.length)} service(s) (${names})`;
472
+ }
473
+ if (manifest.version === 1 && target === "theo-cloud") {
474
+ return "\u26A0 services.json emitted as v1 (no `name` in theo.config.ts), which TheoCloud reads as deprecated. Run `theokit migrate services-json-v1-to-v2` to upgrade.";
475
+ }
476
+ return null;
477
+ }
478
+
466
479
  // src/cli/commands/build-scan-routes.ts
467
480
  import { existsSync as existsSync4 } from "fs";
468
481
  import { join, relative, resolve, sep as sep2 } from "path";
@@ -520,9 +533,9 @@ async function buildCommand(options) {
520
533
  `Invalid build target "${target}". Available targets: ${VALID_TARGETS.join(", ")}`
521
534
  );
522
535
  }
523
- const { resolveAdapter, streamingTargets } = await import("./registry-WVUO2WNR.js");
536
+ const { resolveAdapter, streamingTargets } = await import("./registry-QSJ7X5NO.js");
524
537
  const adapter = await resolveAdapter(target);
525
- const { assertRateLimitEnforceable, assertStreamingSupported } = await import("./config-support-MOZYHRWG.js");
538
+ const { assertRateLimitEnforceable, assertStreamingSupported } = await import("./config-support-HUZ4DXR7.js");
526
539
  assertRateLimitEnforceable(config, adapter, target);
527
540
  assertStreamingSupported(config, adapter, target, await streamingTargets());
528
541
  const distDirAbs = resolve2(cwd, config.distDir);
@@ -557,17 +570,8 @@ async function buildCommand(options) {
557
570
  const projectName = config.name;
558
571
  const servicesManifest = buildManifest(config.services, projectName);
559
572
  writeManifest(cwd, servicesManifest);
560
- if (servicesManifest.services.length > 0) {
561
- const versionLabel = `v${String(servicesManifest.version)}`;
562
- const projectLabel = servicesManifest.version === 2 ? ` project="${servicesManifest.project}"` : "";
563
- console.log(
564
- ` \u2713 Services manifest (${versionLabel}${projectLabel}): ${String(servicesManifest.services.length)} service(s) (${servicesManifest.services.map((s) => s.name).join(", ")})`
565
- );
566
- } else if (servicesManifest.version === 1) {
567
- console.log(
568
- " \u26A0 services.json emitted as v1 (no `name` in theo.config.ts). TheoCloud will accept this with a deprecation warning; sunset in theokit 0.6.0. Run `theokit migrate services-json-v1-to-v2` to upgrade."
569
- );
570
- }
573
+ const servicesLine = describeServicesManifest(servicesManifest, target);
574
+ if (servicesLine !== null) console.log(` ${servicesLine}`);
571
575
  if (config.openapi !== void 0) {
572
576
  const hydrated = await loadRoutesForOpenApi({ serverDir, routes: manifest.routes });
573
577
  const devResult = emitOpenApi({
@@ -592,7 +596,7 @@ async function buildCommand(options) {
592
596
  `);
593
597
  }
594
598
  async function runAdapterBuild(target, config, cwd, adapter) {
595
- const { theoPluginAsync } = await import("./vite-plugin-3LTZJTUM.js");
599
+ const { theoPluginAsync } = await import("./vite-plugin-NXWE2AVM.js");
596
600
  const { default: react } = await import("@vitejs/plugin-react");
597
601
  const ctx = {
598
602
  // `react()` may return Plugin or Plugin[] depending on version; spread the
@@ -618,7 +622,7 @@ async function runAdapterBuild(target, config, cwd, adapter) {
618
622
  // any test while it lived in here, because reaching it meant running the whole build.
619
623
  scanRoutes: createBuildScanRoutes(cwd, config)
620
624
  };
621
- const { warnUnappliedConfig } = await import("./config-support-MOZYHRWG.js");
625
+ const { warnUnappliedConfig } = await import("./config-support-HUZ4DXR7.js");
622
626
  warnUnappliedConfig(config, adapter, target, (message) => {
623
627
  console.log(message);
624
628
  });
@@ -688,4 +692,4 @@ function relativize3(absPath, root) {
688
692
  export {
689
693
  buildCommand
690
694
  };
691
- //# sourceMappingURL=build-7YZSJGP2.js.map
695
+ //# sourceMappingURL=build-4NRHCMFB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/build.ts","../src/server/cron/adapter-translators.ts","../src/server/_internal/atomic-write.ts","../src/server/cron/cron-manifest.ts","../src/server/cron/cron-scan.ts","../src/server/jobs/job-manifest.ts","../src/server/jobs/job-scan.ts","../src/cli/cleanup/cleanup.ts","../src/cli/commands/build/describe-services-manifest.ts","../src/cli/commands/build-scan-routes.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\n// T1.1 (architecture-medium-deferrals) — nodeAdapter no longer static-imported.\n// All adapters dispatch via `adapterRegistry` (lazy-imported within runAdapterBuild).\nimport {\n VALID_TARGETS,\n targetRendersDocument,\n type BuildTarget,\n type AdapterBuildContext,\n type DeployAdapter,\n} from '../../adapters/types.js'\nimport { loadConfig } from '../../config/load-config.js'\nimport { loadEnv } from '../../config/load-env.js'\nimport { validateProjectStructure } from '../../config/validate-structure.js'\nimport {\n ExistingConfigUnparseableError,\n translateCronToAws,\n translateCronToCloudflare,\n translateCronToDeno,\n translateCronToVercel,\n} from '../../server/cron/adapter-translators.js'\nimport { writeCronManifest } from '../../server/cron/cron-manifest.js'\nimport { scanCronDirs } from '../../server/cron/cron-scan.js'\nimport { writeJobManifest } from '../../server/jobs/job-manifest.js'\nimport { scanJobs } from '../../server/jobs/job-scan.js'\nimport { generateManifest, writeManifest } from '../../server/scan/manifest.js'\nimport {\n buildManifest as buildServicesManifest,\n writeManifest as writeServicesManifest,\n} from '../../services/index.js'\n// G2 T2.2 — OpenAPI emit. Opt-in via `config.openapi`. Dual output:\n// 1. <distDir>/openapi.json (pre-Vite, dev surface + manifests sibling)\n// 2. dist/openapi.json (post-Vite, build artifact)\n// The dist emit awaits runAdapterBuild — if Vite fails, the second emit\n// never runs (EC-2 absorbed: no stale dist artifact).\nimport { emitOpenApi } from '../../vite-plugin/openapi-emit/emit.js'\nimport { loadRoutesForOpenApi } from '../../vite-plugin/openapi-emit/load-routes.js'\nimport { cleanOutDir } from '../cleanup/cleanup.js'\nimport { preflightNodeAndBindings } from '../preflight-node-version.js'\n\nimport { describeServicesManifest } from './build/describe-services-manifest.js'\nimport { describeControllerArtifacts, emitControllerArtifacts } from './build/emit-controllers.js'\nimport { createBuildScanRoutes } from './build-scan-routes.js'\n\n// Adapters that do NOT support cron triggers natively. Build still\n// succeeds with crons declared, but emits a warning + skip note.\nconst CRON_NA_TARGETS = new Set<BuildTarget>(['bun', 'netlify', 'static'])\n\n// DERIVED, never restated. A hand-written list here went stale and told users\n// that three working targets were unsupported: it named node/vercel/cloudflare\n// while aws-lambda, deno-deploy and theo-cloud also translate crons. Deriving\n// from the two constants means adding a target cannot desynchronise the message.\nconst CRON_SUPPORTED_TARGETS = VALID_TARGETS.filter((t) => !CRON_NA_TARGETS.has(t))\n\nexport async function buildCommand(options?: { target?: string }): Promise<void> {\n const cwd = process.cwd()\n // Preflight (FIRST — BEFORE anything that touches native bindings).\n preflightNodeAndBindings(cwd)\n // Phase 1 (T1.2) — Load .env BEFORE config load.\n loadEnv({ cwd, mode: 'production' })\n\n const config = await loadConfig(cwd)\n // #95 — honor config.appDir so a custom frontend dir (e.g. apps/web) passes the structure gate.\n validateProjectStructure(cwd, config.appDir)\n\n // B-336 — EVERY refusal that is decidable from the target and the config alone runs BEFORE the\n // clean. `cleanOutDir` used to sit here, above even the check that the target EXISTS: measured on a\n // real project, `theokit build --target nao-existe` destroyed 302 files in `.theokit/client/assets`\n // and answered with a message about the typo. The comment above\n // `assertRateLimitEnforceable` already stated this intent in its own words — \"refused by name,\n // BEFORE the build writes anything\" — and the order defeated it.\n const target = (options?.target ?? 'node') as BuildTarget\n\n if (!VALID_TARGETS.includes(target)) {\n throw new Error(\n `Invalid build target \"${target}\". Available targets: ${VALID_TARGETS.join(', ')}`,\n )\n }\n\n const { resolveAdapter, streamingTargets } = await import('../../adapters/registry.js')\n const adapter = await resolveAdapter(target)\n const { assertRateLimitEnforceable, assertStreamingSupported } =\n await import('../../adapters/config-support.js')\n\n // #461 — a dropped `cors` degrades where someone can see it; a dropped RATE LIMIT looks exactly like\n // success until the abuse it was meant to stop. Refused by name, and now genuinely before anything is\n // written or destroyed.\n assertRateLimitEnforceable(config, adapter, target)\n assertStreamingSupported(config, adapter, target, await streamingTargets())\n\n // T2.2 — Clean .theokit/ at build start (Astro pattern). Skip .git*.\n const distDirAbs = resolve(cwd, config.distDir)\n await cleanOutDir({ dir: distDirAbs })\n\n // EC-201 — cross-reference note when config.adapters[] diverges from\n // the --target flag. --target is authoritative per ADR D2.\n const configAdapters = (config as { adapters?: readonly string[] }).adapters\n if (configAdapters && configAdapters.length > 0) {\n const otherAdapters = configAdapters.filter((a) => a !== target)\n if (otherAdapters.length > 0) {\n console.log(\n `\\n Note: theo.config.ts.adapters lists [${otherAdapters.join(', ')}]; ` +\n `this build translates for ${target} only. ` +\n `Run \\`theokit build --target=<adapter>\\` separately for each (cross-reference).`,\n )\n }\n }\n\n console.log(`\\n Building for ${target}...\\n`)\n\n // Manifests emit BEFORE adapter bundling (Vite). Why: manifests are\n // fast + deterministic + don't depend on Vite. If Vite fails (missing\n // dep, malformed entry), the user still gets manifests for diagnostics.\n const serverDir = resolve(cwd, config.serverDir)\n const distDir = distDirAbs\n // #95 follow-up — pass projectRoot (cwd) + config.agentsDir so agents scan honors a custom dir.\n const manifest = generateManifest(serverDir, cwd, config.agentsDir)\n writeManifest(manifest, distDir)\n\n const totalEndpoints =\n manifest.routes.length + manifest.actions.length + manifest.websockets.length\n console.log(\n ` ✓ Manifest: ${manifest.routes.length} routes, ${manifest.actions.length} actions, ${manifest.websockets.length} ws (${totalEndpoints} total)`,\n )\n\n // T1.1 — cron scan + manifest + per-target adapter translation\n await emitCronArtifacts({ cwd, serverDir, agentsDir: config.agentsDir, distDir, target })\n\n // T1.2 — job scan + manifest (no per-target translation needed)\n await emitJobArtifacts({ cwd, serverDir, distDir })\n\n // theokit#123 — compile `server/controllers/**` so `theokit start` can serve them.\n //\n // #122 made controllers first-class in dev, where Vite's swc transform compiles them on the fly.\n // Production has neither, so an uncompiled `.controller.ts` cannot load and its routes 404'd —\n // working in dev and failing in prod, which is the worst place for a gap to live.\n //\n // Deliberately NOT folded into `generateManifest` (ADR-5): the manifest is the deploy-adapter\n // contract, and a parallel route source in it would ripple through every adapter. This writes a\n // separate artifact only the Node start path reads. No controllers ⇒ no artifact at all.\n const controllerManifest = await emitControllerArtifacts({ serverDir, distDir })\n if (controllerManifest !== null) {\n console.log(` ${describeControllerArtifacts(controllerManifest)}`)\n }\n\n // Wave 2 (T1.2) — services manifest at <cwd>/.theokit/services.json. Always\n // emit (empty array when services: {} is empty) so adapters can rely on\n // the file existing. Topological order preserved by buildServicesManifest.\n //\n // Plan v1.2 T2.1 — when theo.config.ts declares `name`, emit services.json\n // v2 with that project identifier. Falling back to v1 (no project field)\n // keeps TheoCloud's deprecation warning path intact (services-bundle).\n const projectName = config.name\n const servicesManifest = buildServicesManifest(config.services, projectName)\n writeServicesManifest(cwd, servicesManifest)\n const servicesLine = describeServicesManifest(servicesManifest, target)\n if (servicesLine !== null) console.log(` ${servicesLine}`)\n\n // G2 T2.2 — OpenAPI dev-surface emit (pre-Vite, sibling of manifests).\n // Opt-in: only when config.openapi is defined. Best-effort: a route load\n // failure produces a warning, not a build abort.\n if (config.openapi !== undefined) {\n const hydrated = await loadRoutesForOpenApi({ serverDir, routes: manifest.routes })\n const devResult = emitOpenApi({\n manifest: hydrated,\n config: { ...config.openapi, outDir: distDir },\n })\n console.log(` ✓ OpenAPI: ${String(hydrated.length)} ops → ${devResult.path}`)\n }\n\n // Now run the adapter-specific bundling (Vite + adapter-specific work).\n await runAdapterBuild(target, config, cwd, adapter)\n\n // G2 T2.2 — OpenAPI build-artifact emit (post-Vite, EC-2 gated on success).\n // If runAdapterBuild threw, execution never reaches this point — no stale\n // dist/openapi.json is written.\n if (config.openapi !== undefined) {\n const distOut = resolve(cwd, 'dist')\n const hydrated = await loadRoutesForOpenApi({ serverDir, routes: manifest.routes })\n const distResult = emitOpenApi({\n manifest: hydrated,\n config: { ...config.openapi, outDir: distOut },\n })\n console.log(` ✓ OpenAPI (dist): ${distResult.path}`)\n }\n\n // Derived, not asserted. This read `config.ssr` alone, so a target whose entry delegates the\n // document to a static host was announced as server-rendering — measured on `--target bun`, which\n // printed `(SSR)` and served an empty `<div id=\"root\">` (B-334).\n const ssrNote = config.ssr && targetRendersDocument(target) ? ' (SSR)' : ''\n console.log(`\\n ✓ Build complete → ${target}${ssrNote}\\n`)\n}\n\nasync function runAdapterBuild(\n target: BuildTarget,\n config: Awaited<ReturnType<typeof loadConfig>>,\n cwd: string,\n // Resolved by the caller, which needs it before `cleanOutDir` to run the refusals (B-336). Passing it\n // in rather than resolving again keeps one answer to \"which adapter is this build\".\n adapter: DeployAdapter,\n): Promise<void> {\n // T1.1 (architecture-cleanup) — CLI composes the Vite Plugin[] and INJECTS it into\n // the adapter via ctx.makeVitePlugins. This inverts the previous `adapters → vite-plugin`\n // edge — adapters no longer import from vite-plugin/ directly.\n //\n // theoPlugin AND `@vitejs/plugin-react` are dynamically imported so the deps are\n // materialized only when needed (adapter is `node`). This keeps the CLI's startup\n // path independent of optional build-time deps (so e.g. `theokit build --target=static`\n // does not need react installed). dep-cruiser's per-module rule allows `cli → vite-plugin`.\n //\n // 0.2.2 regression fix: switched sync `theoPlugin()` → `theoPluginAsync()` so the\n // returned Plugin[] includes the @theo/actions virtual module + typed-client +\n // services + @theokit/ui auto-chain. Without async, build-time Rollup couldn't\n // resolve `@theo/actions` even though dev-time Vite (which already used async)\n // could. See https://github.com/usetheo/theokit/commits — 0.2.2 changelog.\n const { theoPluginAsync } = await import('../../vite-plugin/index.js')\n const { default: react } = await import('@vitejs/plugin-react')\n const ctx: AdapterBuildContext = {\n // `react()` may return Plugin or Plugin[] depending on version; spread the\n // async chain so the contract returns a flat Plugin[] (AdapterBuildContext\n // type updated to `Plugin[] | Promise<Plugin[]>`).\n // #95 — inject the config dirs so the client build's router/entry + typed-client codegen honor\n // custom appDir/serverDir/agentsDir (e.g. \"apps/web\" / \"core\" / \"core/agents\").\n makeVitePlugins: async (opts) =>\n [\n react(),\n ...(await theoPluginAsync({\n ...opts,\n appDir: config.appDir,\n serverDir: config.serverDir,\n agentsDir: config.agentsDir,\n })),\n ].flat(),\n\n // #369 — the same inversion, for the same reason. A Worker has no filesystem, so the Cloudflare\n // entry bakes its routes at build time; importing the scanner from `adapters/` would add the\n // `adapters → server` edge that `adapters-may-only-depend-on-core-router-services` refuses. The\n // CLI already imports both sides, so it composes the scan and hands over the result.\n //\n // A module rather than a closure since B-312: the wrong argument it carried was unreachable from\n // any test while it lived in here, because reaching it meant running the whole build.\n scanRoutes: createBuildScanRoutes(cwd, config),\n }\n\n // T1.1 (architecture-medium-deferrals, ADR D1) — Adapter Registry replaces\n // the previous 9-case switch. New adapters add 1 line in `adapters/registry.ts`;\n // CLI is closed for modification (OCP).\n // #409 / #410 — a config key that validates and is then never read makes the\n // deployed app behave as if the operator had not written it, with nothing\n // anywhere saying so. Name it before the build output scrolls past.\n const { warnUnappliedConfig } = await import('../../adapters/config-support.js')\n\n // #461 / #321 / #322 — the rate-limit refusal moved to `buildCommand`, above `cleanOutDir`, because\n // this position made its own comment false: it claimed the combination was refused \"BEFORE the build\n // writes anything\" and it is reached a hundred lines after the output has been emptied (B-336).\n\n warnUnappliedConfig(config, adapter, target, (message) => {\n console.log(message)\n })\n\n await adapter.build(config, cwd, ctx)\n}\n\nasync function emitCronArtifacts(opts: {\n cwd: string\n serverDir: string\n agentsDir: string\n distDir: string\n target: BuildTarget\n}): Promise<void> {\n // Crons live in two conventional homes: `server/crons/` (a backend trigger) and\n // `agents/schedules/` (a scheduled agent run, kept in the agent domain). Both feed one manifest.\n const cronsDir = resolve(opts.serverDir, 'crons')\n const agentsSchedulesDir = resolve(opts.cwd, opts.agentsDir, 'schedules')\n\n const cronNodes = await scanCronDirs([cronsDir, agentsSchedulesDir])\n const manifestPath = resolve(opts.distDir, 'crons.json')\n writeCronManifest(manifestPath, cronNodes, opts.cwd)\n\n console.log(` ✓ Crons: ${cronNodes.length} declared`)\n\n if (cronNodes.length === 0) return\n\n // EC-201: target-specific translation. N/A targets emit a warning + skip.\n if (CRON_NA_TARGETS.has(opts.target)) {\n console.log(\n ` ⚠ Cron not supported by target \"${opts.target}\" — declared crons skipped. ` +\n `Supported targets: ${CRON_SUPPORTED_TARGETS.join(', ')}.`,\n )\n return\n }\n\n const manifestEntries = cronNodes.map((n) => ({\n name: n.name,\n filePath: relativize(n.filePath, opts.cwd),\n schedule: n.schedule,\n concurrency: n.concurrency,\n }))\n\n try {\n switch (opts.target) {\n case 'vercel':\n translateCronToVercel(resolve(opts.cwd, 'vercel.json'), manifestEntries)\n console.log(` ✓ Cron → vercel.json crons[] (${cronNodes.length} entries)`)\n break\n case 'cloudflare':\n translateCronToCloudflare(resolve(opts.cwd, 'wrangler.toml'), manifestEntries)\n console.log(` ✓ Cron → wrangler.toml [triggers] (${cronNodes.length})`)\n break\n case 'aws-lambda':\n translateCronToAws(resolve(opts.cwd, 'serverless.yml'), manifestEntries)\n console.log(` ✓ Cron → serverless.yml functions (${cronNodes.length})`)\n break\n case 'deno-deploy':\n translateCronToDeno(resolve(opts.distDir, 'crons-entry.ts'), manifestEntries)\n console.log(` ✓ Cron → ${opts.distDir}/crons-entry.ts (Deno.cron)`)\n break\n case 'node':\n console.log(` ✓ Cron → in-process scheduler (theokit start)`)\n break\n }\n } catch (err) {\n if (err instanceof ExistingConfigUnparseableError) throw err\n throw err\n }\n}\n\nasync function emitJobArtifacts(opts: {\n cwd: string\n serverDir: string\n distDir: string\n}): Promise<void> {\n const jobsDir = resolve(opts.serverDir, 'jobs')\n\n const jobNodes = existsSync(jobsDir) ? await scanJobs(jobsDir) : []\n const manifestPath = resolve(opts.distDir, 'jobs.json')\n writeJobManifest(manifestPath, jobNodes, opts.cwd)\n console.log(` ✓ Jobs: ${jobNodes.length} declared`)\n}\n\nfunction relativize(absPath: string, root: string): string {\n if (absPath.startsWith(root)) {\n const trimmed = absPath.slice(root.length)\n return trimmed.startsWith('/') ? trimmed.slice(1) : trimmed\n }\n return absPath\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time adapter translators: caller-controlled paths only.\n */\nimport { existsSync, readFileSync } from 'node:fs'\n\nimport { writeAtomic } from '../_internal/atomic-write.js'\n\nimport type { CronManifestEntry } from './cron-manifest.js'\n\n/**\n * Thrown when an existing platform-config file (vercel.json, wrangler.toml,\n * serverless.yml) cannot be parsed. Caller must fix the file before\n * re-running `theokit build`. We NEVER silently overwrite a user's config.\n */\nexport class ExistingConfigUnparseableError extends Error {\n readonly code = 'EXISTING_CONFIG_UNPARSEABLE'\n constructor(\n public readonly filePath: string,\n public readonly parseError: string,\n ) {\n super(\n `Existing config \"${filePath}\" could not be parsed: ${parseError}. ` +\n 'Fix or remove the file before re-running build — TheoKit never silently overwrites user configuration.',\n )\n this.name = 'ExistingConfigUnparseableError'\n }\n}\n\n// ──────────────────────────────────────────────────────────\n// Vercel — vercel.json crons[]\n// ──────────────────────────────────────────────────────────\n\ninterface VercelJson {\n crons?: { path: string; schedule: string }[]\n [key: string]: unknown\n}\n\n/**\n * Translate a TheoKit cron manifest into `vercel.json crons[]`.\n *\n * EC-105: existing fields (functions, headers, redirects, rewrites, env,\n * etc.) are preserved verbatim — ONLY the `crons[]` slice is replaced.\n */\nexport function translateCronToVercel(\n vercelJsonPath: string,\n crons: readonly CronManifestEntry[],\n): void {\n let existing: VercelJson = {}\n if (existsSync(vercelJsonPath)) {\n const raw = readFileSync(vercelJsonPath, 'utf8')\n try {\n existing = JSON.parse(raw) as VercelJson\n } catch (err) {\n throw new ExistingConfigUnparseableError(\n vercelJsonPath,\n err instanceof Error ? err.message : String(err),\n )\n }\n }\n const merged: VercelJson = {\n ...existing,\n crons: crons.map((c) => ({\n path: `/api/__crons/${c.name}`,\n schedule: c.schedule,\n })),\n }\n writeAtomic(vercelJsonPath, JSON.stringify(merged, null, 2))\n}\n\n// ──────────────────────────────────────────────────────────\n// Cloudflare — wrangler.toml [triggers] crons\n// ──────────────────────────────────────────────────────────\n\n/**\n * Translate a TheoKit cron manifest into `wrangler.toml [triggers] crons`.\n *\n * EC-105: regex-based mutation that preserves comments + other sections\n * verbatim. Replaces only the `[triggers]` block (or appends if absent).\n */\nexport function translateCronToCloudflare(\n wranglerTomlPath: string,\n crons: readonly CronManifestEntry[],\n): void {\n const schedules = crons.map((c) => `\"${c.schedule}\"`).join(', ')\n const triggersBlock = `[triggers]\\ncrons = [${schedules}]\\n`\n\n if (!existsSync(wranglerTomlPath)) {\n writeAtomic(wranglerTomlPath, triggersBlock)\n return\n }\n\n const existing = readFileSync(wranglerTomlPath, 'utf8')\n\n // Replace existing [triggers] section if present. Strategy: split into\n // line array, find the [triggers] header line, drop subsequent lines\n // until the next section header (line starting with `[`) or EOF.\n const lines = existing.split('\\n')\n const triggersIdx = lines.findIndex((l) => l.trim() === '[triggers]')\n\n let next: string\n if (triggersIdx !== -1) {\n let endIdx = lines.length\n for (let i = triggersIdx + 1; i < lines.length; i++) {\n if (lines[i].trim().startsWith('[')) {\n endIdx = i\n break\n }\n }\n const before = lines.slice(0, triggersIdx).join('\\n')\n const after = lines.slice(endIdx).join('\\n')\n next = `${before}\\n${triggersBlock.trimEnd()}\\n${after}`.replace(/\\n{3,}/g, '\\n\\n')\n } else {\n next = existing.endsWith('\\n')\n ? `${existing}\\n${triggersBlock}`\n : `${existing}\\n\\n${triggersBlock}`\n }\n writeAtomic(wranglerTomlPath, next)\n}\n\n// ──────────────────────────────────────────────────────────\n// AWS Lambda — serverless.yml functions.<fn>.events: schedule\n// ──────────────────────────────────────────────────────────\n\n/**\n * Convert TheoKit's 5-field UTC cron to AWS EventBridge's 6-field format.\n * EventBridge requires `?` in EITHER day-of-month OR day-of-week (not both `*`).\n *\n * Algorithm:\n * - If DOM is \"*\" and DOW is \"*\" → insert ? in DOW (default)\n * - If DOM is \"*\" and DOW is specific → insert ? in DOM\n * - If DOM is specific and DOW is \"*\" → insert ? in DOW\n * - Append \"*\" year field at end.\n */\nexport function convertToAwsCron(schedule: string): string {\n const parts = schedule.trim().split(/\\s+/)\n if (parts.length !== 5) {\n throw new Error(`Invalid 5-field schedule for AWS conversion: \"${schedule}\"`)\n }\n const [minute, hour, dom, month, dow] = parts\n let awsDom = dom\n let awsDow = dow\n if (dom === '*' && dow === '*') {\n awsDow = '?'\n } else if (dom === '*') {\n awsDom = '?'\n } else if (dow === '*') {\n awsDow = '?'\n }\n return `cron(${minute} ${hour} ${awsDom} ${month} ${awsDow} *)`\n}\n\n/**\n * Translate a TheoKit cron manifest into a `serverless.yml` functions\n * map with `events: - schedule: cron(...)` entries.\n *\n * EC-105: appends to `functions:` block, preserving all existing\n * functions/sections. Cron functions are named `cron_<name>` to avoid\n * collision with user-declared functions.\n */\nexport function translateCronToAws(\n serverlessYmlPath: string,\n crons: readonly CronManifestEntry[],\n): void {\n const cronFunctionsYaml = crons\n .map(\n (c) => ` cron_${c.name}:\n handler: .theokit/server/crons/${c.name}.handler\n events:\n - schedule: ${convertToAwsCron(c.schedule)}`,\n )\n .join('\\n')\n\n const block = `\\nfunctions:\\n${cronFunctionsYaml}\\n`\n\n if (!existsSync(serverlessYmlPath)) {\n // Minimal serverless.yml scaffold\n writeAtomic(\n serverlessYmlPath,\n `service: theokit-app\\nprovider:\\n name: aws\\n runtime: nodejs22.x\\n${block}`,\n )\n return\n }\n\n const existing = readFileSync(serverlessYmlPath, 'utf8')\n\n // Look for an existing top-level `functions:` block; if present, append our\n // cron entries under it (don't replace user-declared functions).\n const functionsRe = /^functions:\\s*\\n/m\n let next: string\n if (functionsRe.test(existing)) {\n next = existing.replace(functionsRe, (match) => `${match}${cronFunctionsYaml}\\n`)\n } else {\n next = existing.endsWith('\\n') ? `${existing}${block}` : `${existing}\\n${block}`\n }\n writeAtomic(serverlessYmlPath, next)\n}\n\n// ──────────────────────────────────────────────────────────\n// Deno Deploy — Deno.cron registrations\n// ──────────────────────────────────────────────────────────\n\n/**\n * Emit a Deno entry file that registers each cron via `Deno.cron`.\n *\n * Unlike Vercel/CF/AWS, Deno.cron is an in-process runtime API — the\n * entry file is a managed artifact (overwritten each build), not a user\n * config (so EC-105 doesn't apply here).\n */\nexport function translateCronToDeno(entryPath: string, crons: readonly CronManifestEntry[]): void {\n const lines = crons.map(\n (c) =>\n `Deno.cron(\"${c.name}\", \"${c.schedule}\", async () => {\n const mod = await import(\"../${c.filePath}\");\n const def = mod.default;\n await def.handler({\n traceId: crypto.randomUUID().replace(/-/g, \"\"),\n scheduledAt: new Date(),\n signal: AbortSignal.timeout(60_000),\n });\n});`,\n )\n const content = `// AUTOGENERATED by TheoKit cron build — DO NOT EDIT.\n// Source: server/crons/*.ts → .theokit/crons.json → this file.\n${lines.join('\\n\\n')}\n`\n writeAtomic(entryPath, content)\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time atomic write: caller-controlled paths only. No HTTP input\n * reaches these fs calls.\n */\n// T5a.1b — Web Crypto migration. Build-time only; node:fs + node:path stay\n// because this is a manifest-write leaf (e.g. .theokit/jobs.json) and per\n// ADR-0028 the runtime-portable boundary is the request handler, not the\n// scanner. Only node:crypto is swapped out — Web Crypto's\n// getRandomValues works in every supported runtime.\nimport { mkdirSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\n/**\n * Write `content` to `path` atomically via the tmp + rename pattern.\n *\n * Two concurrent calls to `writeAtomic(path, ...)` are guaranteed to\n * leave `path` containing valid content from ONE of the calls (never\n * truncated, never interleaved). POSIX rename is atomic on the same\n * filesystem.\n *\n * EC-106 (jobs-crons-webhooks-cost-tracking-plan) — shared helper for\n * `.theokit/crons.json` and `.theokit/jobs.json` manifest writes so a\n * concurrent dev-server scan + build manifest emit never produces\n * partial JSON.\n *\n * @param path destination path\n * @param content bytes (UTF-8 string) to write\n */\nexport function writeAtomic(path: string, content: string): void {\n mkdirSync(dirname(path), { recursive: true })\n // Include a random suffix so two concurrent writes don't trample each\n // other's tmp file. Web Crypto getRandomValues is non-blocking +\n // collision-safe for the tiny entropy we need (8 hex chars = 32 bits).\n // Hex-encoded manually to avoid Buffer (runtime-agnostic per ADR-0028).\n const randBuf = new Uint8Array(4)\n globalThis.crypto.getRandomValues(randBuf)\n let suffix = ''\n for (const b of randBuf) suffix += b.toString(16).padStart(2, '0')\n const tmp = `${path}.tmp-${process.pid}-${suffix}`\n writeFileSync(tmp, content, 'utf8')\n renameSync(tmp, path)\n}\n","import { writeAtomic } from '../_internal/atomic-write.js'\n\nimport type { CronNode } from './cron-scan.js'\n\nexport const CRON_MANIFEST_SCHEMA_VERSION = 1 as const\n\nexport interface CronManifestEntry {\n readonly name: string\n readonly filePath: string\n readonly schedule: string\n readonly concurrency: 'forbid' | 'allow'\n}\n\nexport interface CronManifest {\n readonly schemaVersion: typeof CRON_MANIFEST_SCHEMA_VERSION\n readonly generatedAt: string\n readonly crons: readonly CronManifestEntry[]\n}\n\n/**\n * Build a `CronManifest` from scanned `CronNode[]`. Filepaths are kept\n * relative to the caller's project root for portability.\n */\nexport function buildCronManifest(nodes: readonly CronNode[], projectRoot?: string): CronManifest {\n const crons: CronManifestEntry[] = nodes.map((n) => ({\n name: n.name,\n filePath: projectRoot ? relativize(n.filePath, projectRoot) : n.filePath,\n schedule: n.schedule,\n concurrency: n.concurrency,\n }))\n return {\n schemaVersion: CRON_MANIFEST_SCHEMA_VERSION,\n generatedAt: new Date().toISOString(),\n crons,\n }\n}\n\n/**\n * Write the cron manifest to `path` atomically (EC-106).\n *\n * Accepts either a pre-built `CronManifest` OR an array of `CronNode[]`\n * (which gets converted via `buildCronManifest`). The atomic-write\n * helper guarantees `path` always contains valid JSON, even under\n * concurrent writes (e.g., dev-server rescan + build).\n */\nexport function writeCronManifest(\n path: string,\n input: readonly CronNode[] | CronManifest,\n projectRoot?: string,\n): void {\n const manifest: CronManifest = isManifest(input) ? input : buildCronManifest(input, projectRoot)\n writeAtomic(path, JSON.stringify(manifest, null, 2))\n}\n\nfunction isManifest(value: unknown): value is CronManifest {\n return typeof value === 'object' && value !== null && 'schemaVersion' in value && 'crons' in value\n}\n\nfunction relativize(absPath: string, root: string): string {\n if (absPath.startsWith(root)) {\n const trimmed = absPath.slice(root.length)\n return trimmed.startsWith('/') ? trimmed.slice(1) : trimmed\n }\n return absPath\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: caller-controlled directory paths only. No HTTP\n * input ever reaches these fs calls.\n */\nimport { existsSync } from 'node:fs'\nimport { basename } from 'node:path'\n\nimport { importUserModule } from '../../config/import-user-module.js'\nimport { compareByCodeUnit } from '../_internal/compare-by-code-unit.js'\nimport { walkSourceFiles } from '../_internal/scan-walker.js'\n\nimport type { CronConcurrencyPolicy, CronDefinition } from './cron-types.js'\n\n/**\n * One discovered cron from build-time scan. The handler is intentionally\n * NOT included — manifest is platform-neutral and consumed by adapters\n * that emit static config. Runtime dispatch loads the handler at fire time.\n */\nexport interface CronNode {\n readonly name: string\n readonly filePath: string\n readonly schedule: string\n readonly concurrency: CronConcurrencyPolicy\n}\n\nexport class DuplicateCronNameError extends Error {\n readonly code = 'DUPLICATE_CRON_NAME'\n constructor(\n public readonly cronName: string,\n public readonly filePaths: readonly string[],\n ) {\n super(\n `Duplicate cron name \"${cronName}\" defined in: ${filePaths.join(', ')}. ` +\n 'Cron names must be unique across server/crons/ and agents/schedules/.',\n )\n this.name = 'DuplicateCronNameError'\n }\n}\n\nconst CRON_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.mjs'])\n\ninterface CronModule {\n default?: unknown\n}\n\nfunction isCronDefinition(value: unknown): value is CronDefinition {\n if (typeof value !== 'object' || value === null) return false\n const def = value as Record<string, unknown>\n return (\n typeof def.name === 'string' &&\n typeof def.schedule === 'string' &&\n typeof def.handler === 'function' &&\n (def.concurrency === 'forbid' || def.concurrency === 'allow')\n )\n}\n\n/**\n * Scan a directory for cron definition files and return the discovered\n * `CronNode[]` sorted by name. Throws `DuplicateCronNameError` on name\n * collision and `Error` on missing default export.\n *\n * Sequential by design — module imports are awaited one-by-one to keep\n * error messages anchored to the file that failed.\n */\nexport async function scanCrons(cronsDir: string): Promise<CronNode[]> {\n return scanCronDirs([cronsDir])\n}\n\n/**\n * Scan MULTIPLE cron directories and merge the results with a UNIFIED\n * duplicate-name guard across all of them. The framework discovers crons in\n * two conventional homes: `server/crons/` (a backend trigger) and\n * `agents/schedules/` (a scheduled agent run — kept in the agent domain). Both\n * feed the same manifest + deploy translation; a name may not collide across\n * the two dirs. Missing dirs are skipped (no error). Nodes are returned sorted\n * by name for a stable manifest.\n */\nexport async function scanCronDirs(dirs: readonly string[]): Promise<CronNode[]> {\n const filePaths: string[] = []\n for (const dir of dirs) {\n if (!existsSync(dir)) continue\n walkSourceFiles(dir, { extensions: CRON_EXTENSIONS }, (p) => {\n const base = basename(p)\n // Skip private helpers (`_helper.ts`) and OS junk (`.DS_Store`).\n if (base.startsWith('_') || base.startsWith('.')) return\n filePaths.push(p)\n })\n }\n\n const nodes: CronNode[] = []\n for (const filePath of filePaths) {\n let mod: CronModule\n try {\n mod = await importUserModule(filePath)\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to import cron file \"${filePath}\": ${reason}`)\n }\n const exported = mod.default\n if (!isCronDefinition(exported)) {\n throw new Error(\n `Cron file \"${filePath}\" is missing a valid default export. ` +\n 'Expected `export default defineCron(name, { schedule, handler })`.',\n )\n }\n nodes.push({\n name: exported.name,\n filePath,\n schedule: exported.schedule,\n concurrency: exported.concurrency,\n })\n }\n\n // Dup-name detection (unified across every scanned dir).\n const byName = new Map<string, string[]>()\n for (const node of nodes) {\n const bucket = byName.get(node.name) ?? []\n bucket.push(node.filePath)\n byName.set(node.name, bucket)\n }\n for (const [name, paths] of byName) {\n if (paths.length > 1) {\n throw new DuplicateCronNameError(name, paths)\n }\n }\n\n return nodes.sort((a, b) => compareByCodeUnit(a.name, b.name))\n}\n","import { writeAtomic } from '../_internal/atomic-write.js'\n\nimport type { JobNode } from './job-scan.js'\n\nexport const JOB_MANIFEST_SCHEMA_VERSION = 1 as const\n\nexport interface JobManifestEntry {\n readonly name: string\n readonly filePath: string\n readonly maxAttempts: number\n readonly hasInputSchema: boolean\n}\n\nexport interface JobManifest {\n readonly schemaVersion: typeof JOB_MANIFEST_SCHEMA_VERSION\n readonly generatedAt: string\n readonly jobs: readonly JobManifestEntry[]\n}\n\nexport function buildJobManifest(nodes: readonly JobNode[], projectRoot?: string): JobManifest {\n const jobs: JobManifestEntry[] = nodes.map((n) => ({\n name: n.name,\n filePath: projectRoot ? relativize(n.filePath, projectRoot) : n.filePath,\n maxAttempts: n.maxAttempts,\n hasInputSchema: n.hasInputSchema,\n }))\n return {\n schemaVersion: JOB_MANIFEST_SCHEMA_VERSION,\n generatedAt: new Date().toISOString(),\n jobs,\n }\n}\n\nexport function writeJobManifest(\n path: string,\n input: readonly JobNode[] | JobManifest,\n projectRoot?: string,\n): void {\n const manifest: JobManifest = isManifest(input) ? input : buildJobManifest(input, projectRoot)\n writeAtomic(path, JSON.stringify(manifest, null, 2))\n}\n\nfunction isManifest(value: unknown): value is JobManifest {\n return typeof value === 'object' && value !== null && 'schemaVersion' in value && 'jobs' in value\n}\n\nfunction relativize(absPath: string, root: string): string {\n if (absPath.startsWith(root)) {\n const trimmed = absPath.slice(root.length)\n return trimmed.startsWith('/') ? trimmed.slice(1) : trimmed\n }\n return absPath\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: caller-controlled directory paths only.\n */\nimport { existsSync } from 'node:fs'\nimport { basename } from 'node:path'\n\nimport { importUserModule } from '../../config/import-user-module.js'\nimport { compareByCodeUnit } from '../_internal/compare-by-code-unit.js'\nimport { walkSourceFiles } from '../_internal/scan-walker.js'\n\nimport type { JobDefinition } from './job-types.js'\n\nexport interface JobNode {\n readonly name: string\n readonly filePath: string\n readonly maxAttempts: number\n readonly hasInputSchema: boolean\n}\n\nexport class DuplicateJobNameError extends Error {\n readonly code = 'DUPLICATE_JOB_NAME'\n constructor(\n public readonly jobName: string,\n public readonly filePaths: readonly string[],\n ) {\n super(\n `Duplicate job name \"${jobName}\" defined in: ${filePaths.join(', ')}. ` +\n 'Job names must be unique across server/jobs/.',\n )\n this.name = 'DuplicateJobNameError'\n }\n}\n\nconst JOB_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.mjs'])\n\ninterface JobModule {\n default?: unknown\n}\n\nfunction isJobDefinition(value: unknown): value is JobDefinition {\n if (typeof value !== 'object' || value === null) return false\n const def = value as Record<string, unknown>\n return (\n typeof def.name === 'string' &&\n typeof def.handler === 'function' &&\n typeof def.maxAttempts === 'number' &&\n typeof def.hasInputSchema === 'boolean'\n )\n}\n\nexport async function scanJobs(jobsDir: string): Promise<JobNode[]> {\n if (!existsSync(jobsDir)) return []\n\n const filePaths: string[] = []\n walkSourceFiles(jobsDir, { extensions: JOB_EXTENSIONS }, (p) => {\n const base = basename(p)\n if (base.startsWith('_') || base.startsWith('.')) return\n filePaths.push(p)\n })\n\n const nodes: JobNode[] = []\n for (const filePath of filePaths) {\n let mod: JobModule\n try {\n mod = await importUserModule(filePath)\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to import job file \"${filePath}\": ${reason}`)\n }\n const exported = mod.default\n if (!isJobDefinition(exported)) {\n throw new Error(\n `Job file \"${filePath}\" is missing a valid default export. ` +\n 'Expected `export default defineJob(name, { handler })`.',\n )\n }\n nodes.push({\n name: exported.name,\n filePath,\n maxAttempts: exported.maxAttempts,\n hasInputSchema: exported.hasInputSchema,\n })\n }\n\n const byName = new Map<string, string[]>()\n for (const node of nodes) {\n const bucket = byName.get(node.name) ?? []\n bucket.push(node.filePath)\n byName.set(node.name, bucket)\n }\n for (const [name, paths] of byName) {\n if (paths.length > 1) {\n throw new DuplicateJobNameError(name, paths)\n }\n }\n\n return nodes.sort((a, b) => compareByCodeUnit(a.name, b.name))\n}\n","/**\n * State cleanup utilities (Phase 2 of\n *\n * - `cleanOutDir` — Astro pattern: empty a directory except a skip list,\n * used at `theokit build` start.\n * - `gcAgentRegistry` — Nuxt LRU pattern: delete oldest agent dirs when\n * count exceeds cap, used at `theokit dev` startup.\n *\n * EC-3 (MUST FIX, CRITICAL): cleanOutDir refuses to wipe anything outside\n * the current cwd. Prevents catastrophic `distDir: '/'` data loss.\n * EC-9 (SHOULD TEST): gcAgentRegistry handles dirs with mtime=0 (Docker overlay).\n * EC-11 (SHOULD TEST): cleanOutDir normalizes trailing-slash in skip basenames.\n * EC-12 (SHOULD TEST): cleanOutDir catches EROFS and continues.\n */\n\nimport { promises as fs } from 'node:fs'\nimport { basename, resolve as resolvePath, sep } from 'node:path'\n\nimport type {\n CleanOutDirOptions,\n CleanOutDirResult,\n GcAgentRegistryOptions,\n GcAgentRegistryResult,\n} from './cleanup-types.js'\n\nconst DEFAULT_SKIP = ['.git', '.gitkeep', '.gitignore']\n// DEFAULT_MAX_AGENTS removed in Phase 7 — gcAgentRegistry is a tombstone.\n\nfunction normalizeSkipName(name: string): string {\n // EC-11 — strip trailing slash + leading `./`\n return basename(name.replace(/\\/$/, ''))\n}\n\n/**\n * Empty a directory, preserving entries in the skip list.\n *\n * Throws if `opts.dir` is not inside `process.cwd()` (EC-3 path safety).\n * Returns `{deleted:0, kept:0}` when the directory does not exist.\n */\nexport async function cleanOutDir(opts: CleanOutDirOptions): Promise<CleanOutDirResult> {\n const resolvedDir = resolvePath(opts.dir)\n const resolvedCwd = resolvePath(process.cwd())\n\n // EC-3 — path safety guard. CRITICAL.\n if (resolvedDir === resolvedCwd) {\n throw new Error(\n `cleanOutDir refused to wipe ${resolvedDir} — must be a child of cwd, not cwd itself`,\n )\n }\n if (!resolvedDir.startsWith(resolvedCwd + sep)) {\n throw new Error(\n `cleanOutDir refused to wipe ${resolvedDir} — must be inside cwd (${resolvedCwd})`,\n )\n }\n\n const skip = new Set((opts.skip ?? DEFAULT_SKIP).map(normalizeSkipName))\n\n let entries: { name: string }[]\n try {\n entries = await fs.readdir(resolvedDir, { withFileTypes: true })\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ENOENT') return { deleted: 0, kept: 0 }\n throw err\n }\n\n let deleted = 0\n let kept = 0\n for (const entry of entries) {\n const name = entry.name\n if (skip.has(name)) {\n kept++\n continue\n }\n const fullPath = resolvePath(resolvedDir, name)\n try {\n await fs.rm(fullPath, { recursive: true, force: true, maxRetries: 3 })\n deleted++\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ENOENT') {\n deleted++ // already gone\n continue\n }\n // EC-12 — EROFS or other rm failure: warn + continue, don't crash.\n console.warn(\n `[theokit] cleanOutDir could not remove ${fullPath} (${code ?? 'unknown'}); skipping`,\n )\n kept++\n }\n }\n\n return { deleted, kept }\n}\n\n/**\n * Phase 7 — TOMBSTONE for backward-compat. The SDK v1.1.0's `Agent.registry`\n * handles GC natively; this function is a no-op + emits a deprecation warning\n * ONCE per process (EC-10).\n *\n * Will be deleted entirely in TheoKit 0.4.0. Marked deprecated via runtime\n * warning rather than `@deprecated` JSDoc tag to avoid the eslint\n * sonarjs/deprecation flagging our own internal symbols.\n */\nlet warnedOnce = false\nexport async function gcAgentRegistry(\n _opts: GcAgentRegistryOptions,\n): Promise<GcAgentRegistryResult> {\n if (!warnedOnce) {\n warnedOnce = true\n console.warn(\n '[theokit] gcAgentRegistry is deprecated; SDK Agent.registry handles GC natively (configure via theo.config.ts > agents.registry)',\n )\n }\n return Promise.resolve({ deleted: 0, kept: 0 })\n}\n\n/**\n * @internal — testing helper. Resets the module-scoped warnedOnce flag.\n */\nexport function __resetGcDeprecationWarnedForTests(): void {\n warnedOnce = false\n}\n","import type { BuildTarget } from '../../../adapters/types.js'\nimport type { ServicesManifest } from '../../../services/index.js'\n\n/**\n * The build line about `.theokit/services.json`, or `null` when there is nothing worth saying.\n *\n * The v1 warning is addressed to `theo-cloud`, the one target that reads the file. It used to print\n * on every target, for apps that declare no services, and it named a sunset in `theokit 0.6.0` that\n * had passed 68 minors earlier without anything being removed. A deadline nobody enforces teaches\n * the reader to skip the line, so the warning states what the file is and how to upgrade it.\n */\nexport function describeServicesManifest(\n manifest: ServicesManifest,\n target: BuildTarget,\n): string | null {\n if (manifest.services.length > 0) {\n const projectLabel = manifest.version === 2 ? ` project=\"${manifest.project}\"` : ''\n const names = manifest.services.map((s) => s.name).join(', ')\n return (\n `✓ Services manifest (v${String(manifest.version)}${projectLabel}): ` +\n `${String(manifest.services.length)} service(s) (${names})`\n )\n }\n if (manifest.version === 1 && target === 'theo-cloud') {\n return (\n '⚠ services.json emitted as v1 (no `name` in theo.config.ts), which TheoCloud reads as ' +\n 'deprecated. Run `theokit migrate services-json-v1-to-v2` to upgrade.'\n )\n }\n return null\n}\n","import { existsSync } from 'node:fs'\nimport { join, relative, resolve, sep } from 'node:path'\n\nimport type { AdapterBuildContext } from '../../adapters/types.js'\nimport { scanAgents } from '../../server/scan/agent-scan.js'\nimport { scanServerRoutes } from '../../server/scan/scan.js'\nimport { scanWebSocketRoutes } from '../../server/scan/ws-scan.js'\n\n/**\n * What a scanned deploy target is handed instead of a filesystem.\n *\n * #369 — a Worker has no filesystem at request time, so the Cloudflare entry bakes its routes at\n * build time. Importing the scanner from `adapters/` would add the `adapters → server` edge that\n * `adapters-may-only-depend-on-core-router-services` refuses, so the CLI composes the scan and\n * hands over the result.\n *\n * ## Why this is a module rather than a closure inside `buildCommand`\n *\n * It was a closure, and the defect it carried was invisible to every test: `buildCommand` loads a\n * config, runs vite twice and writes a tree, so nothing could ask it one question about one call.\n * Extracted at B-312, whose whole content was a single argument being wrong.\n *\n * Paths are made relative to the project root here, where `projectRoot` is known: that string is\n * both the emitted import specifier and the key the executor looks a module up by, and the scanners\n * return absolute paths.\n */\nexport function createBuildScanRoutes(\n projectRoot: string,\n config: { agentsDir?: string },\n): NonNullable<AdapterBuildContext['scanRoutes']> {\n return (serverDir: string) => {\n const abs = resolve(projectRoot, serverDir)\n const toProjectRelative = (p: string): string => relative(projectRoot, p).split(sep).join('/')\n\n return {\n routes: scanServerRoutes(abs).map((route) => ({\n filePath: toProjectRelative(route.filePath),\n routePath: route.routePath,\n methods: route.methods ?? [],\n })),\n wsRoutes: scanWebSocketRoutes(abs).map((ws) =>\n toProjectRelative(typeof ws === 'string' ? ws : ws.filePath),\n ),\n // #367 — agents are a DIFFERENT scan served by a DIFFERENT function, which is why no adapter\n // had ever heard of them: the entries route `/api/` through `scanServerRoutes` +\n // `executeRoute` alone, so `/api/agents/<name>` matched nothing and 404'd on every target.\n // Scanned here, beside the routes, because the same inversion argument applies verbatim.\n //\n // B-312 — the root is the PROJECT ROOT, and was `dirname(abs)`. `config.agentsDir` is\n // documented and declared relative to the project root, while `dirname(serverDir)` is the\n // root only when `serverDir` is a direct child of it. The scaffold's own nested layout\n // (`serverDir: 'src/server'`, `agentsDir: 'src/server/agents'`) made the two disagree, and\n // `join()` produced `<root>/src/src/server/agents` — so `scanAgents` returned `[]` and every\n // `/api/agents/*` route 404'd on every scanned target. Measured on a live Cloudflare deploy,\n // 2026-09-26. Every other caller in the tree already passes the project root.\n agents: scanAgents(projectRoot, config.agentsDir).map((agent) => ({\n filePath: toProjectRelative(agent.filePath),\n agentPath: agent.agentPath,\n name: agent.name,\n })),\n // B-185 — the identity module, decided here for the same reason the agents are: this provider\n // is handed `serverDir`, and a Worker has no filesystem to look for it on. An app with no\n // `server/context.ts` yields `undefined`, and the generator then emits no import — importing\n // a file that is not there would fail the BUILD rather than one request.\n contextModule: existsSync(join(abs, 'context.ts'))\n ? toProjectRelative(join(abs, 'context.ts'))\n : undefined,\n }\n }\n}\n"],"mappings":"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","names":["existsSync","resolve","existsSync","existsSync","relativize","isManifest","existsSync","basename","existsSync","basename","basename","existsSync","sep","sep","existsSync","resolve","writeManifest","relativize","existsSync"]}
@@ -21,21 +21,22 @@ import {
21
21
  } from "./chunk-EQJF2EH5.js";
22
22
  import {
23
23
  nodeAdapter
24
- } from "./chunk-UFBBFP75.js";
24
+ } from "./chunk-NLHAYGQQ.js";
25
25
  import "./chunk-3PWQQWT6.js";
26
26
  import "./chunk-WSMLSIS5.js";
27
27
  import {
28
28
  assertServicesUnsupported,
29
29
  readManifest
30
- } from "./chunk-ZNZISJDZ.js";
30
+ } from "./chunk-L4V5V2TI.js";
31
31
 
32
32
  // src/adapters/bun.ts
33
33
  import { mkdirSync, writeFileSync } from "fs";
34
34
  import { resolve } from "path";
35
+ var BUN_START_COMMAND = "NODE_ENV=production bun .theokit/bun/server.mjs";
35
36
  var RUNTIME_GUARDS = [
36
37
  `// EC-1: dev-mode guard`,
37
38
  `if (process.env.NODE_ENV !== 'production') {`,
38
- ` console.error('TheoBunAdapter is production-only. Use \\'theokit dev\\' (Node) for development.')`,
39
+ ` console.error('TheoBunAdapter is production-only: start it with \\'${BUN_START_COMMAND}\\' from the project root. For development, use \\'theokit dev\\' (Node).')`,
39
40
  ` process.exit(1)`,
40
41
  `}`,
41
42
  ``,
@@ -259,6 +260,7 @@ async function buildBun(config, cwd, deps = {}, ctx) {
259
260
  }
260
261
  write(resolve(outputDir, "server.mjs"), entry);
261
262
  console.log("\n \u2713 Bun output \u2192 .theokit/bun/server.mjs");
263
+ console.log(` start it with: ${BUN_START_COMMAND}`);
262
264
  console.log(
263
265
  `${describeDeployedSecurityHeaders({
264
266
  target: "bun",
@@ -320,4 +322,4 @@ export {
320
322
  bunAdapter,
321
323
  renderBunEntry
322
324
  };
323
- //# sourceMappingURL=bun-I7YM3RDB.js.map
325
+ //# sourceMappingURL=bun-VPXMWFBA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/bun.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Bun deploy adapter. Writes to `cwd/.theokit/bun/`. Build-time.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport type { TheoConfig } from '../config/schema.js'\nimport type { SecurityHeadersConfig } from '../core/contracts/security-headers.js'\nimport { assertServicesUnsupported, readManifest } from '../services/index.js'\n\nimport { deployedAgentsFragment } from './deployed-agents.js'\nimport { type DeployedCorsOptions } from './deployed-cors.js'\nimport { type DeployedCsrfOptions } from './deployed-csrf.js'\nimport { readDocumentShell } from './deployed-document-shell.js'\nimport { planDeployedPlugins } from './deployed-plugins-module.js'\nimport { deployedEntryPreamble } from './deployed-preamble.js'\nimport {\n deployedRateLimitFragment,\n rateLimitCheckFragment,\n type DeployedRateLimitOptions,\n} from './deployed-rate-limit.js'\nimport {\n deployedRuntimeConfigFragment,\n agentsDirLiteral,\n serverDirLiteral,\n type DeployedRuntimeConfigOptions,\n type DeployedAgentsDirOptions,\n type DeployedServerDirOptions,\n} from './deployed-runtime-config.js'\nimport { deployedTraceFragment } from './deployed-trace.js'\nimport { nodeAdapter } from './node.js'\nimport { describeDeployedSecurityHeaders } from './security-headers.js'\nimport type { AdapterBuildContext, DeployAdapter } from './types.js'\n\nexport interface BunBuildDeps {\n runNodeBuild?: (config: TheoConfig, cwd: string, ctx?: AdapterBuildContext) => Promise<void>\n writeEntry?: (path: string, content: string) => void\n ensureDir?: (path: string) => void\n}\n\n/**\n * How a person starts the emitted entry. Printed by the build and repeated by the dev-mode guard,\n * because the guard is what someone meets after running the path the build printed without\n * `NODE_ENV` (measured 2026-10-02).\n */\nconst BUN_START_COMMAND = 'NODE_ENV=production bun .theokit/bun/server.mjs'\n\n/**\n * The module-scope refusals: this entry is production-only and Bun-only.\n *\n * Extracted from `renderBunEntry` when adding the configured-directory literal pushed it past the\n * per-function line budget. They are a cohesive block — three checks that all refuse to start —\n * and lifting them keeps the budget a signal about the renderer rather than about its preamble.\n */\nconst RUNTIME_GUARDS: readonly string[] = [\n `// EC-1: dev-mode guard`,\n `if (process.env.NODE_ENV !== 'production') {`,\n ` console.error('TheoBunAdapter is production-only: start it with \\\\'${BUN_START_COMMAND}\\\\' from the project root. For development, use \\\\'theokit dev\\\\' (Node).')`,\n ` process.exit(1)`,\n `}`,\n ``,\n `// Version check: Bun >= 1.1`,\n `if (typeof Bun === 'undefined') {`,\n ` console.error('TheoBunAdapter must run inside Bun. Got Node.js or unknown runtime.')`,\n ` process.exit(1)`,\n `}`,\n `{`,\n ` const [maj, min] = (Bun.version ?? '0.0').split('.').map(Number)`,\n ` if (maj < 1 || (maj === 1 && min < 1)) {`,\n ` console.error('TheoBunAdapter requires Bun >= 1.1; got ' + Bun.version)`,\n ` process.exit(1)`,\n ` }`,\n `}`,\n]\n\nexport function renderBunEntry(\n port: number,\n opts: {\n ssrStreaming?: boolean\n /**\n * Whether this build renders the document on the server.\n *\n * Bun is the one Web target whose own handler answers the HTML document, and it answered it from\n * `.theokit/client/index.html` — the client shell. So an `ssr: true` project was served an empty\n * `<div id=\"root\">` while the build printed `(SSR)` (B-334).\n */\n ssr?: boolean\n /** The document up to `<div id=\"root\">`, read from the built client shell. */\n htmlHead?: string\n /** The document from `<div id=\"root\">` on. */\n htmlTail?: string\n securityHeaders?: SecurityHeadersConfig\n } & DeployedAgentsDirOptions &\n DeployedCsrfOptions &\n DeployedRuntimeConfigOptions &\n DeployedServerDirOptions &\n DeployedCorsOptions &\n DeployedRateLimitOptions = {},\n): string {\n // The whole implementation of `ssrStreaming` in this adapter used to be the text of this comment:\n // `opts.ssrStreaming` was read, and its only effect was which string landed on line 4 of the emitted\n // file. `rules/foreign-config-surfaces.md` names that exact failure — \"A surface is read, or it is\n // refused with a reason. It is never accepted and ignored\" — and it was in this adapter.\n const document =\n opts.ssr === true ? { htmlHead: opts.htmlHead, htmlTail: opts.htmlTail } : undefined\n const streamingComment =\n document !== undefined\n ? `// ssr on — the document is rendered by this handler, not read from .theokit/client`\n : `// ssr off — the document is the built client shell, served from disk`\n const runtimeConfig = deployedRuntimeConfigFragment(opts)\n const agentsFragment = deployedAgentsFragment(\n {\n kind: 'scan',\n projectRoot: 'cwd',\n loadModule: 'loadModule',\n serverDir: 'serverDir',\n agentsDirLiteral: agentsDirLiteral(opts),\n },\n {\n pathname: 'pathname',\n // B-185 — bound only when the runtime-config fragment declared the const, which is\n // exactly when a plugins module was emitted. Referencing it otherwise would emit an\n // identifier the entry never declares.\n pluginRunnerExpr:\n opts.runtimeConfigModule === undefined ? undefined : 'await THEO_PLUGIN_RUNNER',\n },\n )\n return [\n `// Generated by Theo — Bun Adapter`,\n `// Run: bun run .theokit/bun/server.mjs`,\n `// Requires Bun >= 1.1`,\n streamingComment,\n ``,\n ...RUNTIME_GUARDS,\n ``,\n `import { resolve, join } from 'node:path'`,\n `import { existsSync } from 'node:fs'`,\n // One element per emitted line, like every neighbour, and the conditional import is a spread\n // rather than an interpolated `\\n`. That is not a style preference: this line carried the\n // fragment inside a nested double-quoted string, where an escaped backslash is a backslash, so\n // the import reached the module joined by two characters and Bun refused it. A construct that\n // cannot express a malformed line beats one escaped correctly (B-325), and `sonarjs` refuses the\n // nesting outright — the lint was naming the cause.\n `import { scanServerRoutes, matchRoute, createProductionLoader } from 'theokit/server/scan'`,\n `import { executeRoute, extractTraceIdFromRequest, TRACE_HEADER, createCorsWebHandler } from 'theokit/server/http'`,\n ...(opts.rateLimit === undefined\n ? []\n : [`import { createRateLimiterWeb } from 'theokit/server/rate-limit'`]),\n `import { createWebShim } from 'theokit/adapters/web-shim'`,\n `import { buildSecurityHeaders, withSecurityHeaders } from 'theokit/adapters/security-headers'`,\n // The renderer the node build already emits for this target and nothing imported. Its own header\n // names Bun: \"Web Standards streaming entry for edge runtimes (Cloudflare, Bun, Deno, Vercel\n // Edge)\". Measured on a real build: `.theokit/server/entry-server.js` is 95513 bytes and exports\n // the render, and `.theokit/bun/server.mjs` referenced it zero times.\n ...(document === undefined\n ? []\n : [`import { renderStreamingWeb } from '../server/entry-server.js'`]),\n `// T3.2 — WS bridge for Bun runtime`,\n `import { createBunWsBridge } from 'theokit/adapters/ws-shim'`,\n `import { scanWebSocketRoutes } from 'theokit/server/scan'`,\n ``,\n `const cwd = process.cwd()`,\n `const clientDir = resolve(cwd, '.theokit/client')`,\n `const serverDir = resolve(cwd, ${serverDirLiteral(opts)})`,\n `const port = process.env.PORT ? Number(process.env.PORT) : ${port}`,\n ``,\n `// #410 — the security baseline \\`theokit start\\` puts on every response,`,\n `// carried here as a literal because the deployed process has no`,\n `// theo.config.ts to read. Bun is the one Web target whose own handler serves`,\n `// the HTML document (static file + SPA fallback below), so the document gets`,\n `// these headers too -- with a nonce-less CSP, because that HTML was written`,\n `// at build time and carries no nonce on its script tags (EC-4).`,\n ...deployedEntryPreamble(runtimeConfig, agentsFragment, opts, 'bun'),\n ``,\n ...deployedRateLimitFragment(opts.rateLimit, 'bun', 'server.requestIP(request)?.address'),\n ``,\n `const routes = existsSync(serverDir) ? scanServerRoutes(serverDir) : []`,\n `const wsRoutes = existsSync(serverDir) ? scanWebSocketRoutes(serverDir) : []`,\n `const loadModule = createProductionLoader()`,\n ``,\n `// Bun WebSocket config — single handler dispatches to first ws route,`,\n `// or a default no-op when none declared. Per-route routing happens above`,\n `// (the upgrade decision is made in fetch handler before Bun.serve hands off).`,\n `const wsBridge = wsRoutes.length > 0`,\n ` ? createBunWsBridge({`,\n ` onOpen: () => {},`,\n ` onMessage: (ws, data) => { ws.send(data) },`,\n ` onClose: () => {},`,\n ` })`,\n ` : { open: () => {}, message: () => {}, close: () => {} }`,\n ``,\n `function notFoundResponse() {`,\n ` return new Response(JSON.stringify({ error: { code: 'NOT_FOUND', message: 'Route not found' } }), {`,\n ` status: 404,`,\n ` headers: { 'Content-Type': 'application/json' },`,\n ` })`,\n `}`,\n ``,\n `Bun.serve({`,\n ` port,`,\n ` websocket: wsBridge,`,\n ` async fetch(request, server) {`,\n ` // #409 — the preflight is answered BEFORE anything routes: an OPTIONS the router`,\n ` // handles is an OPTIONS the browser never gets a CORS answer to.`,\n ` const preflight = corsPreflight(request)`,\n ` if (preflight !== null) return withSecurityHeaders(preflight, SECURITY_HEADERS)`,\n ...rateLimitCheckFragment(opts.rateLimit, ' '),\n ` return withCors(request, withSecurityHeaders(await handleRequest(request), SECURITY_HEADERS))`,\n ` },`,\n `})`,\n ``,\n ...bunHandleRequestFragment(runtimeConfig.executeRouteSpread, agentsFragment.branch, document),\n ].join('\\n')\n}\n\n/**\n * The request handler, as generated source.\n *\n * Extracted for the reason `vercel.ts` extracts its own fragments: the emitter is one array\n * literal, so every line the entry gains counts against `max-lines-per-function`, and #410 added\n * the CSRF literal to an emitter that was already sitting exactly at the ceiling.\n */\nfunction bunHandleRequestFragment(\n runtimeSpread: string,\n agentBranch: readonly string[],\n document: { htmlHead?: string; htmlTail?: string } | undefined,\n): string[] {\n return [\n `async function handleRequest(request) {`,\n ` const url = new URL(request.url)`,\n ` const pathname = url.pathname`,\n ``,\n ` // 1) Static assets`,\n ...(document === undefined\n ? [\n ` const staticPath = pathname === '/' ? '/index.html' : pathname`,\n ` const fullStatic = join(clientDir, staticPath)`,\n ` if (existsSync(fullStatic)) {`,\n ` const file = Bun.file(fullStatic)`,\n ` if (await file.exists()) return new Response(file)`,\n ` }`,\n ]\n : [\n ` // \\`/\\` is deliberately NOT mapped to index.html here: that file is the client shell,`,\n ` // and answering the document from it is what served an empty <div id=\"root\"> on an`,\n ` // ssr build. Real assets still come from disk; the document falls through to (3).`,\n ` if (pathname !== '/') {`,\n ` const fullStatic = join(clientDir, pathname)`,\n ` if (existsSync(fullStatic)) {`,\n ` const file = Bun.file(fullStatic)`,\n ` if (await file.exists()) return new Response(file)`,\n ` }`,\n ` }`,\n ]),\n ``,\n ` // 2) API routes through the full executeRoute pipeline via the shim`,\n ` if (pathname.startsWith('/api/') || __theoIsAgentCardPath(pathname)) {`,\n ...agentBranch,\n ``,\n ` const match = matchRoute(pathname, routes)`,\n ` if (!match) return notFoundResponse()`,\n ` const { req, res, toResponse } = createWebShim(request)`,\n ...deployedTraceFragment('request', ' '),\n ` const method = request.method.toUpperCase()`,\n ` // #382 — not awaited: toResponse() settles at the headers and carries`,\n ` // a live body, so Bun.serve streams while the handler writes.`,\n ` return toResponse(executeRoute({ route: match.route, method, params: match.params, req, res, loadModule, serverDir, requestId, ...CSRF_CONFIG, ${runtimeSpread} }))`,\n ` }`,\n ``,\n ...(document === undefined\n ? [\n ` // 3) SPA fallback`,\n ` const indexPath = join(clientDir, 'index.html')`,\n ` if (existsSync(indexPath)) return new Response(Bun.file(indexPath))`,\n ]\n : [\n ` // 3) The document, rendered here rather than read from disk.`,\n ` //`,\n ` // No nonce is minted: the outer wrapper applies a precomputed SECURITY_HEADERS constant,`,\n ` // so a per-request value would have to be threaded through it. That is a separate change`,\n ` // with its own blast radius, and the shell this replaces carries only external`,\n ` // <script src> tags, which \\`script-src 'self'\\` already allows.`,\n ` return await renderStreamingWeb(request, {`,\n ` htmlHead: ${JSON.stringify(document.htmlHead ?? '')},`,\n ` htmlTail: ${JSON.stringify(document.htmlTail ?? '')},`,\n ` })`,\n ]),\n ``,\n ` return notFoundResponse()`,\n `}`,\n ``,\n `console.log('Theo (Bun) listening on http://localhost:' + port)`,\n ]\n}\n\nexport async function buildBun(\n config: TheoConfig,\n cwd: string,\n deps: BunBuildDeps = {},\n ctx?: AdapterBuildContext,\n): Promise<void> {\n // Wave 2 (T2.2) — reject polyglot services on this adapter.\n assertServicesUnsupported('bun', readManifest(cwd))\n\n const runNodeBuild = deps.runNodeBuild ?? nodeAdapter.build.bind(nodeAdapter)\n await runNodeBuild(config, cwd, ctx)\n\n const outputDir = resolve(cwd, '.theokit/bun')\n const ensureDir = deps.ensureDir ?? ((p: string) => mkdirSync(p, { recursive: true }))\n ensureDir(outputDir)\n\n const pluginsPlan = planDeployedPlugins(config.plugins, 'bun')\n const entry = renderBunEntry(config.port, {\n ssrStreaming: config.ssrStreaming,\n // B-334 — the sixth time this shape has been fixed one target at a time: the renderer honoured an\n // option no build passed (B-185, B-235, B-312, B-315, B-317). Here it was worse — the option only\n // changed a comment. The shell is read HERE rather than in the emitter, because reading a file is\n // the build's job and not a string emitter's.\n ssr: config.ssr,\n ...readDocumentShell(cwd, config.ssr),\n securityHeaders: config.security?.headers,\n csrf: config.security?.csrf,\n disallowed: config.security?.disallowed,\n cors: config.security?.cors,\n // #425 — a selector, not a transformer, so it rides as a literal like the values above.\n serialization: config.serialization,\n // #425 — the ONE concern that is not a literal. A closure cannot be baked, so a plugin\n // declared by module specifier is imported by the emitted module instead; a constructed one\n // is refused by name at build time rather than dropped in silence.\n runtimeConfigModule: pluginsPlan?.moduleSpecifier,\n // #95 — the configured directories, which `build.ts:210` already threads into the Vite\n // plugins. Without these two lines the literals above fall to their defaults and a project\n // with a custom dir deploys an entry that resolves a directory it does not have.\n serverDir: config.serverDir,\n agentsDir: config.agentsDir,\n })\n const write =\n deps.writeEntry ??\n ((p, c) => {\n writeFileSync(p, c)\n })\n if (pluginsPlan !== undefined) {\n // Beside the entry, so the emitted import is a sibling. Written through the same seam as\n // the entry so a test that captures one captures both (#425).\n write(resolve(outputDir, 'theo.plugins.mjs'), pluginsPlan.source)\n }\n write(resolve(outputDir, 'server.mjs'), entry)\n\n // eslint-disable-next-line no-console -- CLI build progress\n console.log('\\n ✓ Bun output → .theokit/bun/server.mjs')\n // eslint-disable-next-line no-console -- CLI build progress\n console.log(` start it with: ${BUN_START_COMMAND}`)\n // eslint-disable-next-line no-console -- CLI build progress\n console.log(\n `${describeDeployedSecurityHeaders({\n target: 'bun',\n securityHeaders: config.security?.headers,\n // Bun renders the document at request time when `ssr` is on (B-334), and still mints no nonce:\n // the outer wrapper applies a precomputed SECURITY_HEADERS constant, so a per-request value\n // would have to be threaded through it.\n //\n // This used to read \"No deploy target other than the streamed Cloudflare worker renders HTML at\n // request time, so none of the rest can mint a nonce.\" True when written, false the moment B-317\n // shipped — a CONSEQUENCE of the fleet at the time, never a prohibition, which is why rendering\n // here is consistent with the intent rather than against it.\n mintsNonce: false,\n // Bun serves `.theokit/client` itself, so the document DOES pass through\n // the handler these headers are attached to.\n documentHeaders: 'handler',\n })}\\n`,\n )\n}\n\nexport const bunAdapter: DeployAdapter = {\n // The entry runs IN the project: it resolves `serverDir` against `cwd`, so `node_modules` is\n // present and the scan has a tree to read. `docs/adr/0020` leaves this target alone for exactly\n // that reason.\n readsSourceAtRunTime: true,\n specifiersResolvedBy: 'the-project-at-run-time',\n name: 'bun',\n streamsResponses: true,\n // #409 / #410 — the generated entry calls `executeRoute` with routes, loader\n // and serverDir only. CSRF, route policy, file middleware and Zod validation\n // still run because they live inside `executeRoute`; none of the remaining\n // configurable concerns reach it. Declared explicitly rather than omitted so\n // the gap is a statement in the source and not an absence.\n //\n // `securityHeaders` IS applied: the entry carries `security.headers` as a\n // literal and puts the built baseline on every response, the served document\n // included.\n servesAgents: true,\n appliesConfig: [\n 'securityHeaders',\n 'csrf',\n 'disallowed',\n 'cors',\n 'serialization',\n 'plugins',\n // #508 — bun is the first Web target to ENFORCE a declared limit rather than refuse the\n // build: `Bun.serve` is long-lived, so the in-process counter survives, and its handler\n // already receives `server`, whose `requestIP` gives the peer address without a header.\n 'rateLimit',\n ],\n // B-257 — a long-lived process: the in-process counter survives between requests.\n enforcesRateLimit: 'always',\n build(config, cwd, ctx) {\n return buildBun(config, cwd, {}, ctx)\n },\n}\n"],"mappings":"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","names":[]}
@@ -145,7 +145,7 @@ async function agentCommand(name, message, deps = {}) {
145
145
  );
146
146
  }
147
147
  const projectRoot = deps.projectRoot ?? process.cwd();
148
- const agentsDir = deps.agentsDir ?? (await (await import("./load-config-52H3EKAA.js")).loadConfig(projectRoot)).agentsDir;
148
+ const agentsDir = deps.agentsDir ?? (await (await import("./load-config-2DXLI7NW.js")).loadConfig(projectRoot)).agentsDir;
149
149
  const agents = scanAgents(projectRoot, agentsDir);
150
150
  const agent = agents.find((a) => a.name === name);
151
151
  if (!agent) {
@@ -178,8 +178,8 @@ async function agentCommand(name, message, deps = {}) {
178
178
  async function createAgentSsrLoader(projectRoot) {
179
179
  const { createServer } = await import("vite");
180
180
  const react = (await import("@vitejs/plugin-react")).default;
181
- const { theoPluginAsync } = await import("./vite-plugin-3LTZJTUM.js");
182
- const { loadConfig } = await import("./load-config-52H3EKAA.js");
181
+ const { theoPluginAsync } = await import("./vite-plugin-NXWE2AVM.js");
182
+ const { loadConfig } = await import("./load-config-2DXLI7NW.js");
183
183
  const config = await loadConfig(projectRoot);
184
184
  const theoPlugins = await theoPluginAsync({
185
185
  root: projectRoot,
@@ -212,4 +212,4 @@ export {
212
212
  agentCommand,
213
213
  createAgentSsrLoader
214
214
  };
215
- //# sourceMappingURL=chunk-SG62LZOJ.js.map
215
+ //# sourceMappingURL=chunk-25OXNMVO.js.map
@@ -12,7 +12,7 @@ import {
12
12
  serveMatchedAuxRoute,
13
13
  serveThroughPluginLifecycle,
14
14
  setupSsrDevMiddleware
15
- } from "./chunk-QAS5SKZP.js";
15
+ } from "./chunk-VD3BCME6.js";
16
16
  import {
17
17
  resolveTheoRootDir
18
18
  } from "./chunk-FDOOBTXJ.js";
@@ -34,7 +34,7 @@ import {
34
34
  mountAgent,
35
35
  readAgentPolicy,
36
36
  writeWebResponseToServerResponse
37
- } from "./chunk-SHIXTMQE.js";
37
+ } from "./chunk-DA3GGICE.js";
38
38
  import {
39
39
  getApprovalRegistry,
40
40
  resolveProvider
@@ -68,10 +68,10 @@ import {
68
68
  } from "./chunk-4WP7A7RX.js";
69
69
  import {
70
70
  loadConfig
71
- } from "./chunk-SZWGXHY3.js";
71
+ } from "./chunk-VOXLI66L.js";
72
72
  import {
73
73
  buildServicesProxyConfig
74
- } from "./chunk-ZNZISJDZ.js";
74
+ } from "./chunk-L4V5V2TI.js";
75
75
  import {
76
76
  broadcastToDevtools
77
77
  } from "./chunk-5ODOE6EF.js";
@@ -2228,7 +2228,7 @@ async function theoPluginAsync(rootOrOptions) {
2228
2228
  const studioPlugins = await integrateStudio();
2229
2229
  const servicesPlugins = [];
2230
2230
  if (options.services && Object.keys(options.services).length > 0) {
2231
- const { servicesTypedClientPlugin } = await import("./services-typed-client-XGT5SUUN.js");
2231
+ const { servicesTypedClientPlugin } = await import("./services-typed-client-FOBFCRD6.js");
2232
2232
  servicesPlugins.push(
2233
2233
  servicesTypedClientPlugin({
2234
2234
  cwd: projectRoot,
@@ -2238,7 +2238,7 @@ async function theoPluginAsync(rootOrOptions) {
2238
2238
  }
2239
2239
  const { assetsMapPlugin } = await import("./assets-map-BMQASQHW.js");
2240
2240
  const assetsMap = assetsMapPlugin({ appDir: resolve5(projectRoot, options.appDir ?? "app") });
2241
- const { appTypedClientPlugin } = await import("./app-typed-client-XD4DZBV7.js");
2241
+ const { appTypedClientPlugin } = await import("./app-typed-client-AZMUYIYV.js");
2242
2242
  const appClientPlugin = appTypedClientPlugin({
2243
2243
  cwd: projectRoot,
2244
2244
  serverDir: serverDirAbs,
@@ -2246,13 +2246,13 @@ async function theoPluginAsync(rootOrOptions) {
2246
2246
  // B-313 — the same name line 226 already passes. This call passed neither it nor the root.
2247
2247
  agentsDir: agentsDirName
2248
2248
  });
2249
- const { actionsVirtualModule } = await import("./actions-virtual-module-JV7URROJ.js");
2249
+ const { actionsVirtualModule } = await import("./actions-virtual-module-4J7Z37Y4.js");
2250
2250
  const actionsPlugin = actionsVirtualModule({
2251
2251
  serverDir: serverDirAbs,
2252
2252
  distDir: resolve5(projectRoot, ".theokit")
2253
2253
  });
2254
2254
  const { agentsTypedClientPlugin } = await import("./agents-typed-client-D4OA2TXB.js");
2255
- const { generateManifest } = await import("./internal-api-GKPJYL3G.js");
2255
+ const { generateManifest } = await import("./internal-api-ATSPOXI2.js");
2256
2256
  const agentsClientPlugin = agentsTypedClientPlugin({
2257
2257
  projectRoot,
2258
2258
  agentsDir: agentsDirName,
@@ -2269,7 +2269,7 @@ async function theoPluginAsync(rootOrOptions) {
2269
2269
  const controllerTransformPlugin = controllerSwcTransformPlugin({
2270
2270
  serverDir: serverDirAbs
2271
2271
  });
2272
- const { serverOnlyImportBoundary } = await import("./server-boundary-QCJNECJP.js");
2272
+ const { serverOnlyImportBoundary } = await import("./server-boundary-JM72DQLA.js");
2273
2273
  const serverBoundaryPlugin = serverOnlyImportBoundary({
2274
2274
  projectRoot,
2275
2275
  serverDir: serverDirAbs
@@ -2446,4 +2446,4 @@ export {
2446
2446
  buildOptimizeDepsInclude,
2447
2447
  theoPlugin
2448
2448
  };
2449
- //# sourceMappingURL=chunk-QX5Q3FBJ.js.map
2449
+ //# sourceMappingURL=chunk-7FIK5NKN.js.map
@@ -2431,6 +2431,18 @@ async function admitRequest(request, policy, resolveSubject, agentName) {
2431
2431
  if (!decision.allowed) return agentAccessDenied(decision, params);
2432
2432
  return input;
2433
2433
  }
2434
+ function resolveKeyOrError(apiKey, compiled, identity) {
2435
+ try {
2436
+ return {
2437
+ key: typeof apiKey === "function" ? apiKey(compiled.model, compiled.plugins) : apiKey,
2438
+ failure: void 0
2439
+ };
2440
+ } catch (err) {
2441
+ const message = err instanceof Error ? err.message : String(err);
2442
+ console.error(`[theokit] agent "${identity}" cannot resolve a provider credential: ${message}`);
2443
+ return { failure: jsonError(500, "INTERNAL", message) };
2444
+ }
2445
+ }
2434
2446
  async function mountAgent(mod, request, apiKey, {
2435
2447
  source = "agent module",
2436
2448
  csrfMode = "strict",
@@ -2452,7 +2464,9 @@ async function mountAgent(mod, request, apiKey, {
2452
2464
  if (admitted instanceof Response) return admitted;
2453
2465
  const input = admitted;
2454
2466
  const compiled = compileLoadedAgentModule2(mod, source);
2455
- const resolvedApiKey = typeof apiKey === "function" ? apiKey(compiled.model, compiled.plugins) : apiKey;
2467
+ const keyResult = resolveKeyOrError(apiKey, compiled, identity);
2468
+ if (keyResult.failure !== void 0) return keyResult.failure;
2469
+ const resolvedApiKey = keyResult.key;
2456
2470
  if (compiled.skillsResolver) {
2457
2471
  const enabled = await resolveEnabledSkills2(compiled.skillsResolver, compiled.runContext ?? {});
2458
2472
  if (enabled !== void 0) compiled.skills = { enabled, autoInject: true };
@@ -2770,4 +2784,4 @@ export {
2770
2784
  CsrfReadinessStore,
2771
2785
  applySecurityHeaders
2772
2786
  };
2773
- //# sourceMappingURL=chunk-SHIXTMQE.js.map
2787
+ //# sourceMappingURL=chunk-DA3GGICE.js.map