theokit 0.57.1 → 0.58.1

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 (67) hide show
  1. package/dist/{actions-virtual-module-GMRXCAVN.js → actions-virtual-module-L6SCJLDI.js} +3 -3
  2. package/dist/{actions-virtual-module-XAWZOWSY.js → actions-virtual-module-YQBEDNHN.js} +4 -4
  3. package/dist/{agent-LS7I3ZQB.js → agent-X7RDENTI.js} +2 -2
  4. package/dist/{app-typed-client-NMKJ4DR7.js → app-typed-client-BE4LZPK2.js} +4 -4
  5. package/dist/{app-typed-client-W74QO5LH.js → app-typed-client-F3YLMV4N.js} +3 -3
  6. package/dist/{build-FHE72YXR.js → build-H2UDKBV7.js} +5 -5
  7. package/dist/{chunk-KEDRCI2L.js → chunk-6YRZWT5X.js} +9 -9
  8. package/dist/{chunk-2HWWJTOH.js → chunk-BCFA6LHL.js} +1 -1
  9. package/dist/chunk-BCFA6LHL.js.map +1 -0
  10. package/dist/{chunk-XJOU425Y.js → chunk-GP6OJBXP.js} +1 -1
  11. package/dist/{chunk-XJOU425Y.js.map → chunk-GP6OJBXP.js.map} +1 -1
  12. package/dist/{chunk-G5JYB2LO.js → chunk-IF7CZXPW.js} +2 -2
  13. package/dist/{chunk-CLBJTDI6.js → chunk-KZ3PXNPT.js} +2 -2
  14. package/dist/{chunk-CTRVTBGY.js → chunk-L4TB6FXQ.js} +26 -4
  15. package/dist/chunk-L4TB6FXQ.js.map +1 -0
  16. package/dist/{chunk-NC2OPE22.js → chunk-MWPC7EOR.js} +2 -2
  17. package/dist/{chunk-OKDCBENR.js → chunk-VJRPOUKM.js} +3 -3
  18. package/dist/{chunk-CMCEGW3B.js → chunk-WOANPZBT.js} +26 -4
  19. package/dist/chunk-WOANPZBT.js.map +1 -0
  20. package/dist/{chunk-Q6HS3NFG.js → chunk-YGL3H3UW.js} +8 -8
  21. package/dist/cli/index.js +7 -7
  22. package/dist/{dev-WDKROZBS.js → dev-SJE2GSAC.js} +6 -6
  23. package/dist/{dev-emit-FIQASO3D.js → dev-emit-7RT624PM.js} +2 -2
  24. package/dist/{dev-emit-QGSMUZLU.js → dev-emit-ZLB2J5ME.js} +2 -2
  25. package/dist/index.js +3 -3
  26. package/dist/{internal-api-732K3H75.js → internal-api-4FBFRQ4G.js} +4 -4
  27. package/dist/{internal-api-EVJSGGO3.js → internal-api-W5RURFU7.js} +3 -3
  28. package/dist/{mcp-PBUCHHAS.js → mcp-I5HCW4QF.js} +2 -2
  29. package/dist/{openapi-PKDDJ7M2.js → openapi-WDX3XX2J.js} +2 -2
  30. package/dist/{preview-VFIFKVP4.js → preview-PWGO5LUE.js} +3 -3
  31. package/dist/server/index.js +1 -1
  32. package/dist/server/scan/index.d.ts +11 -0
  33. package/dist/server/scan/index.js +1 -1
  34. package/dist/{server-boundary-B6U4DRRH.js → server-boundary-CJIXOPCF.js} +4 -4
  35. package/dist/{server-boundary-QRVK3OIJ.js → server-boundary-WVWEJNUJ.js} +3 -3
  36. package/dist/{start-UAMJ5TSC.js → start-KEWSYVVU.js} +36 -21
  37. package/dist/start-KEWSYVVU.js.map +1 -0
  38. package/dist/vite-plugin/index.js +3 -3
  39. package/dist/{vite-plugin-ABJIDKE6.js → vite-plugin-TU3HQA43.js} +6 -6
  40. package/package.json +2 -2
  41. package/dist/chunk-2HWWJTOH.js.map +0 -1
  42. package/dist/chunk-CMCEGW3B.js.map +0 -1
  43. package/dist/chunk-CTRVTBGY.js.map +0 -1
  44. package/dist/start-UAMJ5TSC.js.map +0 -1
  45. /package/dist/{actions-virtual-module-GMRXCAVN.js.map → actions-virtual-module-L6SCJLDI.js.map} +0 -0
  46. /package/dist/{actions-virtual-module-XAWZOWSY.js.map → actions-virtual-module-YQBEDNHN.js.map} +0 -0
  47. /package/dist/{agent-LS7I3ZQB.js.map → agent-X7RDENTI.js.map} +0 -0
  48. /package/dist/{app-typed-client-NMKJ4DR7.js.map → app-typed-client-BE4LZPK2.js.map} +0 -0
  49. /package/dist/{app-typed-client-W74QO5LH.js.map → app-typed-client-F3YLMV4N.js.map} +0 -0
  50. /package/dist/{build-FHE72YXR.js.map → build-H2UDKBV7.js.map} +0 -0
  51. /package/dist/{chunk-KEDRCI2L.js.map → chunk-6YRZWT5X.js.map} +0 -0
  52. /package/dist/{chunk-G5JYB2LO.js.map → chunk-IF7CZXPW.js.map} +0 -0
  53. /package/dist/{chunk-CLBJTDI6.js.map → chunk-KZ3PXNPT.js.map} +0 -0
  54. /package/dist/{chunk-NC2OPE22.js.map → chunk-MWPC7EOR.js.map} +0 -0
  55. /package/dist/{chunk-OKDCBENR.js.map → chunk-VJRPOUKM.js.map} +0 -0
  56. /package/dist/{chunk-Q6HS3NFG.js.map → chunk-YGL3H3UW.js.map} +0 -0
  57. /package/dist/{dev-WDKROZBS.js.map → dev-SJE2GSAC.js.map} +0 -0
  58. /package/dist/{dev-emit-FIQASO3D.js.map → dev-emit-7RT624PM.js.map} +0 -0
  59. /package/dist/{dev-emit-QGSMUZLU.js.map → dev-emit-ZLB2J5ME.js.map} +0 -0
  60. /package/dist/{internal-api-732K3H75.js.map → internal-api-4FBFRQ4G.js.map} +0 -0
  61. /package/dist/{internal-api-EVJSGGO3.js.map → internal-api-W5RURFU7.js.map} +0 -0
  62. /package/dist/{mcp-PBUCHHAS.js.map → mcp-I5HCW4QF.js.map} +0 -0
  63. /package/dist/{openapi-PKDDJ7M2.js.map → openapi-WDX3XX2J.js.map} +0 -0
  64. /package/dist/{preview-VFIFKVP4.js.map → preview-PWGO5LUE.js.map} +0 -0
  65. /package/dist/{server-boundary-B6U4DRRH.js.map → server-boundary-CJIXOPCF.js.map} +0 -0
  66. /package/dist/{server-boundary-QRVK3OIJ.js.map → server-boundary-WVWEJNUJ.js.map} +0 -0
  67. /package/dist/{vite-plugin-ABJIDKE6.js.map → vite-plugin-TU3HQA43.js.map} +0 -0
@@ -10,8 +10,24 @@ import {
10
10
  // src/server/http/controller-dispatch.ts
11
11
  import { readdirSync } from "node:fs";
12
12
  import { join } from "node:path";
13
- import { createDecoratorHandler, isControllerClass } from "@theokit/http";
13
+ import {
14
+ CONTROLLER_PREFIX,
15
+ createDecoratorHandler,
16
+ getMeta,
17
+ isControllerClass,
18
+ Reflector
19
+ } from "@theokit/http";
14
20
  var CSRF_PROTECTED_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
21
+ var CSRF_EXEMPT_METADATA = "theokit:csrf-exempt";
22
+ function segments(value) {
23
+ return value.split("/").filter(Boolean);
24
+ }
25
+ function pathOwnedByPrefix(pathname, prefix) {
26
+ const want = segments(prefix);
27
+ const got = segments(pathname);
28
+ if (want.length === 0 || got.length < want.length) return false;
29
+ return want.every((segment, i) => got[i] === segment);
30
+ }
15
31
  function findControllerFiles(dir) {
16
32
  const found = [];
17
33
  const walk = (current) => {
@@ -52,9 +68,15 @@ async function createControllerDispatcher(opts) {
52
68
  const classes = await scanControllers(opts.controllersDir, opts.loadModule);
53
69
  if (classes.length === 0) return null;
54
70
  const handle = createDecoratorHandler({ controllers: classes, serveAgent: opts.serveAgent });
71
+ const reflector = new Reflector();
72
+ const exemptPrefixes = classes.filter((cls) => reflector.getByKey(CSRF_EXEMPT_METADATA, cls) === true).map((cls) => {
73
+ const meta = getMeta(CONTROLLER_PREFIX, cls);
74
+ return meta?.prefix ?? "";
75
+ }).filter((prefix) => prefix !== "");
55
76
  return {
56
77
  dispatch: (request) => handle(request),
57
- matches: (method, pathname) => handle.matches(method, pathname)
78
+ matches: (method, pathname) => handle.matches(method, pathname),
79
+ isCsrfExempt: (pathname) => exemptPrefixes.some((p) => pathOwnedByPrefix(pathname, p))
58
80
  };
59
81
  }
60
82
  async function writeControllerResponse(res, response) {
@@ -79,7 +101,7 @@ async function dispatchControllerRequest(args) {
79
101
  const method = (req.method ?? "GET").toUpperCase();
80
102
  const webRequest = incomingMessageToWebRequest(req);
81
103
  const pathname = new URL(webRequest.url).pathname;
82
- if (CSRF_PROTECTED_METHODS.has(method) && dispatcher.matches(method, pathname)) {
104
+ if (CSRF_PROTECTED_METHODS.has(method) && dispatcher.matches(method, pathname) && !dispatcher.isCsrfExempt(pathname)) {
83
105
  const decision = enforceCsrf(
84
106
  req,
85
107
  csrfMode,
@@ -108,4 +130,4 @@ export {
108
130
  scanControllerModules,
109
131
  dispatchControllerRequest
110
132
  };
111
- //# sourceMappingURL=chunk-CMCEGW3B.js.map
133
+ //# sourceMappingURL=chunk-WOANPZBT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/http/controller-dispatch.ts"],"mappings":"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","names":[]}
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-SSYDEKWF.js";
8
8
  import {
9
9
  dispatchControllerRequest
10
- } from "./chunk-CMCEGW3B.js";
10
+ } from "./chunk-WOANPZBT.js";
11
11
  import {
12
12
  RUN_ID_HEADER,
13
13
  SSE_BASE_HEADERS,
@@ -89,7 +89,7 @@ import {
89
89
  scanServerActions,
90
90
  scanServerRoutes,
91
91
  scanWebSocketRoutes
92
- } from "./chunk-XJOU425Y.js";
92
+ } from "./chunk-GP6OJBXP.js";
93
93
  import {
94
94
  scanAgents
95
95
  } from "./chunk-KDP2HURW.js";
@@ -2333,7 +2333,7 @@ async function runConfigureServer(server, ctx) {
2333
2333
  server.watcher.on("unlink", handleRouteChange);
2334
2334
  if (ctx.resolvedOpenApi !== void 0) {
2335
2335
  const openApiCfg = ctx.resolvedOpenApi;
2336
- const { reEmitOpenApi } = await import("./dev-emit-FIQASO3D.js");
2336
+ const { reEmitOpenApi } = await import("./dev-emit-7RT624PM.js");
2337
2337
  const openApiServerDir = ctx.serverDir;
2338
2338
  const openApiDistDir = resolve8(ctx.projectRoot, ctx.resolvedDistDir);
2339
2339
  const isRouteFileForOpenApi = (file) => file.startsWith(openApiServerDir) && /\.(ts|tsx|js|mjs)$/.test(file);
@@ -3484,19 +3484,19 @@ async function theoPluginAsync(rootOrOptions) {
3484
3484
  })
3485
3485
  );
3486
3486
  }
3487
- const { appTypedClientPlugin } = await import("./app-typed-client-W74QO5LH.js");
3487
+ const { appTypedClientPlugin } = await import("./app-typed-client-F3YLMV4N.js");
3488
3488
  const appClientPlugin = appTypedClientPlugin({
3489
3489
  cwd: projectRoot,
3490
3490
  serverDir: serverDirAbs,
3491
3491
  distDir: resolve10(projectRoot, ".theokit")
3492
3492
  });
3493
- const { actionsVirtualModule } = await import("./actions-virtual-module-GMRXCAVN.js");
3493
+ const { actionsVirtualModule } = await import("./actions-virtual-module-L6SCJLDI.js");
3494
3494
  const actionsPlugin = actionsVirtualModule({
3495
3495
  serverDir: serverDirAbs,
3496
3496
  distDir: resolve10(projectRoot, ".theokit")
3497
3497
  });
3498
3498
  const { agentsTypedClientPlugin } = await import("./agents-typed-client-PVUZU65B.js");
3499
- const { generateManifest } = await import("./internal-api-EVJSGGO3.js");
3499
+ const { generateManifest } = await import("./internal-api-W5RURFU7.js");
3500
3500
  const agentsClientPlugin = agentsTypedClientPlugin({
3501
3501
  projectRoot,
3502
3502
  agentsDir: agentsDirName,
@@ -3513,7 +3513,7 @@ async function theoPluginAsync(rootOrOptions) {
3513
3513
  const controllerTransformPlugin = controllerSwcTransformPlugin({
3514
3514
  serverDir: serverDirAbs
3515
3515
  });
3516
- const { serverOnlyImportBoundary } = await import("./server-boundary-QRVK3OIJ.js");
3516
+ const { serverOnlyImportBoundary } = await import("./server-boundary-WVWEJNUJ.js");
3517
3517
  const serverBoundaryPlugin = serverOnlyImportBoundary({
3518
3518
  projectRoot,
3519
3519
  serverDir: serverDirAbs
@@ -3696,4 +3696,4 @@ export {
3696
3696
  theoPluginAsync,
3697
3697
  theoPlugin
3698
3698
  };
3699
- //# sourceMappingURL=chunk-Q6HS3NFG.js.map
3699
+ //# sourceMappingURL=chunk-YGL3H3UW.js.map
package/dist/cli/index.js CHANGED
@@ -15,12 +15,12 @@ function cliVersion() {
15
15
  // src/cli/index.ts
16
16
  var cli = cac("theokit");
17
17
  cli.command("dev", "Start development server").option("--port <port>", "Port number").action(async (options) => {
18
- const { devCommand } = await import("../dev-WDKROZBS.js");
18
+ const { devCommand } = await import("../dev-SJE2GSAC.js");
19
19
  await devCommand({ port: options.port ? Number(options.port) : void 0 });
20
20
  });
21
21
  cli.command("build", "Build for production").option("--target <target>", "Deploy target (node, vercel, cloudflare)").action(async (options) => {
22
22
  try {
23
- const { buildCommand } = await import("../build-FHE72YXR.js");
23
+ const { buildCommand } = await import("../build-H2UDKBV7.js");
24
24
  await buildCommand({ target: options.target });
25
25
  } catch (err) {
26
26
  const msg = err instanceof Error ? err.message : String(err);
@@ -32,7 +32,7 @@ cli.command("build", "Build for production").option("--target <target>", "Deploy
32
32
  });
33
33
  cli.command("start", "Start production server").option("--port <port>", "Port number").action(async (options) => {
34
34
  try {
35
- const { startCommand } = await import("../start-UAMJ5TSC.js");
35
+ const { startCommand } = await import("../start-KEWSYVVU.js");
36
36
  await startCommand({ port: options.port ? Number(options.port) : void 0 });
37
37
  } catch (err) {
38
38
  const msg = err instanceof Error ? err.message : String(err);
@@ -44,7 +44,7 @@ cli.command("start", "Start production server").option("--port <port>", "Port nu
44
44
  });
45
45
  cli.command("preview", "Build for production, then serve it \u2014 one step (B-030)").option("--port <port>", "Port number").option("--target <target>", "Deploy target (node, vercel, cloudflare)").action(async (options) => {
46
46
  try {
47
- const { previewCommand } = await import("../preview-VFIFKVP4.js");
47
+ const { previewCommand } = await import("../preview-PWGO5LUE.js");
48
48
  await previewCommand({
49
49
  port: options.port ? Number(options.port) : void 0,
50
50
  target: options.target
@@ -77,7 +77,7 @@ cli.command(
77
77
  "Run an agent in the terminal (stream + tool calls + approval)"
78
78
  ).action(async (name, message) => {
79
79
  try {
80
- const { agentCommand } = await import("../agent-LS7I3ZQB.js");
80
+ const { agentCommand } = await import("../agent-X7RDENTI.js");
81
81
  const { sawError } = await agentCommand(name, message);
82
82
  if (sawError) process.exit(1);
83
83
  } catch (err) {
@@ -108,7 +108,7 @@ cli.command("agent sessions gc", "Collect old transcripts for this project (dry
108
108
  });
109
109
  cli.command("mcp <agent>", "Serve an agent as an MCP server over stdio (for desktop MCP clients)").action(async (agent) => {
110
110
  try {
111
- const { mcpCommand } = await import("../mcp-PBUCHHAS.js");
111
+ const { mcpCommand } = await import("../mcp-I5HCW4QF.js");
112
112
  await mcpCommand(agent);
113
113
  } catch (err) {
114
114
  const msg = err instanceof Error ? err.message : String(err);
@@ -173,7 +173,7 @@ cli.command(
173
173
  "Generate <distDir>/openapi.json from route schemas (opt-in via config.openapi)"
174
174
  ).option("--dry-run", "Print the document to stdout without writing to disk (EC-3)").action(async (options) => {
175
175
  try {
176
- const { openapiCommand } = await import("../openapi-PKDDJ7M2.js");
176
+ const { openapiCommand } = await import("../openapi-WDX3XX2J.js");
177
177
  await openapiCommand({ dryRun: Boolean(options.dryRun) });
178
178
  } catch (err) {
179
179
  const msg = err instanceof Error ? err.message : String(err);
@@ -11,20 +11,20 @@ import {
11
11
  } from "./chunk-KTMQUYED.js";
12
12
  import {
13
13
  theoPluginAsync
14
- } from "./chunk-KEDRCI2L.js";
15
- import "./chunk-OKDCBENR.js";
14
+ } from "./chunk-6YRZWT5X.js";
15
+ import "./chunk-VJRPOUKM.js";
16
16
  import "./chunk-2CVV6CNN.js";
17
17
  import "./chunk-3PWQQWT6.js";
18
18
  import "./chunk-FDOOBTXJ.js";
19
19
  import "./chunk-47MM2JUK.js";
20
- import "./chunk-G5JYB2LO.js";
20
+ import "./chunk-IF7CZXPW.js";
21
21
  import "./chunk-35QIWOHT.js";
22
- import "./chunk-CTRVTBGY.js";
22
+ import "./chunk-L4TB6FXQ.js";
23
23
  import "./chunk-RPET332G.js";
24
24
  import "./chunk-5VLP3GQ2.js";
25
25
  import "./chunk-C27VRUVN.js";
26
26
  import "./chunk-7UZZHCRN.js";
27
- import "./chunk-2HWWJTOH.js";
27
+ import "./chunk-BCFA6LHL.js";
28
28
  import "./chunk-5NNFO7R7.js";
29
29
  import "./chunk-NO6HA4FG.js";
30
30
  import "./chunk-Z7CJHDLS.js";
@@ -123,4 +123,4 @@ export {
123
123
  devCommand,
124
124
  startDevServer
125
125
  };
126
- //# sourceMappingURL=dev-WDKROZBS.js.map
126
+ //# sourceMappingURL=dev-SJE2GSAC.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  generateManifest
3
- } from "./chunk-XJOU425Y.js";
3
+ } from "./chunk-GP6OJBXP.js";
4
4
  import "./chunk-KDP2HURW.js";
5
5
  import "./chunk-DV34VG3N.js";
6
6
  import "./chunk-SOYOYGWY.js";
@@ -339,4 +339,4 @@ export {
339
339
  _resetInFlightForTests,
340
340
  reEmitOpenApi
341
341
  };
342
- //# sourceMappingURL=dev-emit-FIQASO3D.js.map
342
+ //# sourceMappingURL=dev-emit-7RT624PM.js.map
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-47VNWTL4.js";
7
7
  import {
8
8
  generateManifest
9
- } from "./chunk-2HWWJTOH.js";
9
+ } from "./chunk-BCFA6LHL.js";
10
10
  import "./chunk-5NNFO7R7.js";
11
11
  import "./chunk-NO6HA4FG.js";
12
12
  import "./chunk-Z7CJHDLS.js";
@@ -41,4 +41,4 @@ export {
41
41
  _resetInFlightForTests,
42
42
  reEmitOpenApi
43
43
  };
44
- //# sourceMappingURL=dev-emit-QGSMUZLU.js.map
44
+ //# sourceMappingURL=dev-emit-ZLB2J5ME.js.map
package/dist/index.js CHANGED
@@ -8,10 +8,10 @@ import {
8
8
  scanRoutes,
9
9
  theoConfigSchema,
10
10
  theoPlugin
11
- } from "./chunk-Q6HS3NFG.js";
11
+ } from "./chunk-YGL3H3UW.js";
12
12
  import "./chunk-7NRFZBAL.js";
13
13
  import "./chunk-SSYDEKWF.js";
14
- import "./chunk-CMCEGW3B.js";
14
+ import "./chunk-WOANPZBT.js";
15
15
  import "./chunk-M357ILK5.js";
16
16
  import "./chunk-OIGJOYX6.js";
17
17
  import "./chunk-U3SPBLJF.js";
@@ -32,7 +32,7 @@ import "./chunk-AVQU5CQF.js";
32
32
  import "./chunk-VSLTKX5L.js";
33
33
  import "./chunk-TNI4MARH.js";
34
34
  import "./chunk-4ERYQBL6.js";
35
- import "./chunk-XJOU425Y.js";
35
+ import "./chunk-GP6OJBXP.js";
36
36
  import "./chunk-KDP2HURW.js";
37
37
  import "./chunk-DV34VG3N.js";
38
38
  import "./chunk-V6Y2SMRG.js";
@@ -16,7 +16,7 @@ import {
16
16
  handleCspReport,
17
17
  handleCsrfReadiness,
18
18
  mountAgent
19
- } from "./chunk-G5JYB2LO.js";
19
+ } from "./chunk-IF7CZXPW.js";
20
20
  import {
21
21
  resolveProvider
22
22
  } from "./chunk-35QIWOHT.js";
@@ -24,7 +24,7 @@ import {
24
24
  dispatchControllerRequest,
25
25
  incomingMessageToHandlerRequest,
26
26
  sendError
27
- } from "./chunk-CTRVTBGY.js";
27
+ } from "./chunk-L4TB6FXQ.js";
28
28
  import {
29
29
  generateNonce
30
30
  } from "./chunk-RPET332G.js";
@@ -38,7 +38,7 @@ import {
38
38
  import "./chunk-7UZZHCRN.js";
39
39
  import {
40
40
  generateManifest
41
- } from "./chunk-2HWWJTOH.js";
41
+ } from "./chunk-BCFA6LHL.js";
42
42
  import {
43
43
  scanAgents
44
44
  } from "./chunk-5NNFO7R7.js";
@@ -87,4 +87,4 @@ export {
87
87
  scanWebSocketRoutes,
88
88
  sendError
89
89
  };
90
- //# sourceMappingURL=internal-api-732K3H75.js.map
90
+ //# sourceMappingURL=internal-api-4FBFRQ4G.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  dispatchControllerRequest
3
- } from "./chunk-CMCEGW3B.js";
3
+ } from "./chunk-WOANPZBT.js";
4
4
  import {
5
5
  mountAgent
6
6
  } from "./chunk-M357ILK5.js";
@@ -54,7 +54,7 @@ import {
54
54
  scanServerActionsEnriched,
55
55
  scanServerRoutes,
56
56
  scanWebSocketRoutes
57
- } from "./chunk-XJOU425Y.js";
57
+ } from "./chunk-GP6OJBXP.js";
58
58
  import {
59
59
  scanAgents
60
60
  } from "./chunk-KDP2HURW.js";
@@ -107,4 +107,4 @@ export {
107
107
  scanWebSocketRoutes,
108
108
  sendError
109
109
  };
110
- //# sourceMappingURL=internal-api-EVJSGGO3.js.map
110
+ //# sourceMappingURL=internal-api-W5RURFU7.js.map
@@ -2,7 +2,7 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  createAgentSsrLoader
5
- } from "./chunk-NC2OPE22.js";
5
+ } from "./chunk-MWPC7EOR.js";
6
6
  import {
7
7
  extractAppResources,
8
8
  handleMcpJsonRpc
@@ -75,4 +75,4 @@ async function mcpCommand(name, deps = {}) {
75
75
  export {
76
76
  mcpCommand
77
77
  };
78
- //# sourceMappingURL=mcp-PBUCHHAS.js.map
78
+ //# sourceMappingURL=mcp-I5HCW4QF.js.map
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-47VNWTL4.js";
7
7
  import {
8
8
  generateManifest
9
- } from "./chunk-2HWWJTOH.js";
9
+ } from "./chunk-BCFA6LHL.js";
10
10
  import "./chunk-5NNFO7R7.js";
11
11
  import "./chunk-NO6HA4FG.js";
12
12
  import "./chunk-Z7CJHDLS.js";
@@ -84,4 +84,4 @@ function emitOpenApiInMemory(manifest, config) {
84
84
  export {
85
85
  openapiCommand
86
86
  };
87
- //# sourceMappingURL=openapi-PKDDJ7M2.js.map
87
+ //# sourceMappingURL=openapi-WDX3XX2J.js.map
@@ -4,8 +4,8 @@ import "tsx/esm";
4
4
  // src/cli/commands/preview.ts
5
5
  async function defaultSteps() {
6
6
  const [{ buildCommand }, { startCommand }] = await Promise.all([
7
- import("./build-FHE72YXR.js"),
8
- import("./start-UAMJ5TSC.js")
7
+ import("./build-H2UDKBV7.js"),
8
+ import("./start-KEWSYVVU.js")
9
9
  ]);
10
10
  return {
11
11
  build: (opts) => buildCommand(opts),
@@ -20,4 +20,4 @@ async function previewCommand(options = {}, steps) {
20
20
  export {
21
21
  previewCommand
22
22
  };
23
- //# sourceMappingURL=preview-VFIFKVP4.js.map
23
+ //# sourceMappingURL=preview-PWGO5LUE.js.map
@@ -208,7 +208,7 @@ import {
208
208
  scanServerRoutes,
209
209
  scanWebSocketRoutes,
210
210
  writeManifest
211
- } from "../chunk-XJOU425Y.js";
211
+ } from "../chunk-GP6OJBXP.js";
212
212
  import "../chunk-KDP2HURW.js";
213
213
  import "../chunk-DV34VG3N.js";
214
214
  import {
@@ -139,6 +139,17 @@ interface ManifestAgent {
139
139
  interface TheoManifest {
140
140
  version: 1;
141
141
  generatedAt: string;
142
+ /**
143
+ * FILE routes — what `scanServerRoutes` finds under `<serverDir>/routes`. Controllers are NOT
144
+ * here, and that is deliberate: they ship as a separate `controllers.json` so a deploy adapter
145
+ * that knows nothing about them keeps working unchanged (see `emit-controllers.ts`).
146
+ *
147
+ * Which makes `routes: []` ambiguous, and the ambiguity is worth stating rather than leaving for
148
+ * each reader to rediscover. It means "no file routes" — never "this app serves nothing". Measured
149
+ * on a nine-controller app: sixteen routes served, `routes: []` written (theokit#543). Anything
150
+ * answering "what does this app serve?" must read `controllers.json` too; `public-exposure-gate`
151
+ * is the one that had to learn this the expensive way.
152
+ */
142
153
  routes: ManifestRoute[];
143
154
  actions: ManifestAction[];
144
155
  websockets: ManifestWebSocket[];
@@ -17,7 +17,7 @@ import {
17
17
  scanServerRoutes,
18
18
  scanWebSocketRoutes,
19
19
  writeManifest
20
- } from "../../chunk-XJOU425Y.js";
20
+ } from "../../chunk-GP6OJBXP.js";
21
21
  import "../../chunk-KDP2HURW.js";
22
22
  import "../../chunk-DV34VG3N.js";
23
23
  import {
@@ -3,14 +3,14 @@ import "tsx/esm";
3
3
  import {
4
4
  resolveTheoRootDir
5
5
  } from "./chunk-FDOOBTXJ.js";
6
- import "./chunk-G5JYB2LO.js";
6
+ import "./chunk-IF7CZXPW.js";
7
7
  import "./chunk-35QIWOHT.js";
8
- import "./chunk-CTRVTBGY.js";
8
+ import "./chunk-L4TB6FXQ.js";
9
9
  import "./chunk-RPET332G.js";
10
10
  import "./chunk-5VLP3GQ2.js";
11
11
  import "./chunk-C27VRUVN.js";
12
12
  import "./chunk-7UZZHCRN.js";
13
- import "./chunk-2HWWJTOH.js";
13
+ import "./chunk-BCFA6LHL.js";
14
14
  import "./chunk-5NNFO7R7.js";
15
15
  import {
16
16
  ACTION_SCHEMAS_DIR
@@ -131,4 +131,4 @@ export {
131
131
  ServerOnlyImportError,
132
132
  serverOnlyImportBoundary
133
133
  };
134
- //# sourceMappingURL=server-boundary-B6U4DRRH.js.map
134
+ //# sourceMappingURL=server-boundary-CJIXOPCF.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  resolveTheoRootDir
3
3
  } from "./chunk-7NRFZBAL.js";
4
- import "./chunk-CMCEGW3B.js";
4
+ import "./chunk-WOANPZBT.js";
5
5
  import "./chunk-M357ILK5.js";
6
6
  import "./chunk-BPYMC7SU.js";
7
7
  import "./chunk-IRQGAC4L.js";
@@ -21,7 +21,7 @@ import "./chunk-TNI4MARH.js";
21
21
  import "./chunk-4ERYQBL6.js";
22
22
  import {
23
23
  ACTION_SCHEMAS_DIR
24
- } from "./chunk-XJOU425Y.js";
24
+ } from "./chunk-GP6OJBXP.js";
25
25
  import "./chunk-KDP2HURW.js";
26
26
  import "./chunk-DV34VG3N.js";
27
27
  import "./chunk-V6Y2SMRG.js";
@@ -147,4 +147,4 @@ export {
147
147
  ServerOnlyImportError,
148
148
  serverOnlyImportBoundary
149
149
  };
150
- //# sourceMappingURL=server-boundary-QRVK3OIJ.js.map
150
+ //# sourceMappingURL=server-boundary-WVWEJNUJ.js.map
@@ -2,7 +2,7 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  CONTROLLER_MANIFEST_FILE
5
- } from "./chunk-CLBJTDI6.js";
5
+ } from "./chunk-KZ3PXNPT.js";
6
6
  import {
7
7
  parseCookieHeader
8
8
  } from "./chunk-V7MTRM6Q.js";
@@ -25,7 +25,7 @@ import {
25
25
  resolveTransformer,
26
26
  serveMatchedAuxRoute,
27
27
  serveThroughPluginLifecycle
28
- } from "./chunk-OKDCBENR.js";
28
+ } from "./chunk-VJRPOUKM.js";
29
29
  import "./chunk-2CVV6CNN.js";
30
30
  import {
31
31
  findRootDiv
@@ -41,7 +41,7 @@ import {
41
41
  mountAgent,
42
42
  readAgentPolicy,
43
43
  writeWebResponseToServerResponse
44
- } from "./chunk-G5JYB2LO.js";
44
+ } from "./chunk-IF7CZXPW.js";
45
45
  import {
46
46
  getApprovalRegistry,
47
47
  resolveProvider
@@ -50,7 +50,7 @@ import {
50
50
  createWebRequestSource,
51
51
  dispatchControllerRequest,
52
52
  sendError
53
- } from "./chunk-CTRVTBGY.js";
53
+ } from "./chunk-L4TB6FXQ.js";
54
54
  import {
55
55
  buildSecurityHeaders,
56
56
  generateNonce
@@ -68,7 +68,7 @@ import {
68
68
  import "./chunk-7UZZHCRN.js";
69
69
  import {
70
70
  loadManifest
71
- } from "./chunk-2HWWJTOH.js";
71
+ } from "./chunk-BCFA6LHL.js";
72
72
  import {
73
73
  scanAgents
74
74
  } from "./chunk-5NNFO7R7.js";
@@ -577,10 +577,28 @@ function unauthenticatedWrites(routes) {
577
577
  }
578
578
  return found;
579
579
  }
580
- function cannotAnswer(routes) {
581
- const anyDetected = routes.some((r) => r.publicMethods !== void 0);
582
- if (anyDetected) return false;
583
- return routes.some((r) => (r.methods ?? []).some((m) => MUTATING_METHODS.has(m)));
580
+ function whyCannotAnswer(routes, hasControllers) {
581
+ if (routes.length === 0) {
582
+ return hasControllers === false ? null : "empty-table";
583
+ }
584
+ if (routes.some((r) => r.publicMethods !== void 0)) return null;
585
+ return routes.some((r) => (r.methods ?? []).some((m) => MUTATING_METHODS.has(m))) ? "stale-manifest" : null;
586
+ }
587
+ function unverifiedMessage(reason, host) {
588
+ const head = `Binding ${host} without checking whether its write routes are authenticated.`;
589
+ return reason === "stale-manifest" ? [
590
+ head,
591
+ " This manifest predates the check and records no policy kinds. Run `theo build` to",
592
+ " regenerate it; until then the server starts, and this warning is the whole of what",
593
+ " is known about the exposure."
594
+ ].join("\n") : [
595
+ head,
596
+ " The manifest describes no routes, so there is nothing here to judge. If this app serves",
597
+ " through controllers, that is expected and rebuilding will not change it \u2014 the route scan",
598
+ " reads `server/routes/` only (usetheokit/theokit#543). Whatever your controllers mark",
599
+ " `theokit:public` on a POST/PUT/PATCH/DELETE is reachable from this address, and this",
600
+ " warning is the whole of what is known about it."
601
+ ].join("\n");
584
602
  }
585
603
  function refusalMessage(exposures, host) {
586
604
  const list = exposures.map((e) => ` ${e.method} ${e.routePath}`).join("\n");
@@ -602,16 +620,9 @@ function refusalMessage(exposures, host) {
602
620
  }
603
621
  function assessPublicExposure(input) {
604
622
  if (!isPubliclyBound(input.target.host)) return { kind: "not-exposed" };
605
- if (cannotAnswer(input.routes)) {
606
- return {
607
- kind: "unverified",
608
- message: [
609
- `Binding ${input.target.host} without checking whether its write routes are authenticated.`,
610
- " This manifest predates the check and records no policy kinds. Run `theo build` to",
611
- " regenerate it; until then the server starts, and this warning is the whole of what",
612
- " is known about the exposure."
613
- ].join("\n")
614
- };
623
+ const blind = whyCannotAnswer(input.routes, input.hasControllers);
624
+ if (blind !== null) {
625
+ return { kind: "unverified", message: unverifiedMessage(blind, input.target.host) };
615
626
  }
616
627
  const exposures = unauthenticatedWrites(input.routes);
617
628
  if (exposures.length === 0) return { kind: "allowed" };
@@ -1343,7 +1354,11 @@ async function startCommand(options) {
1343
1354
  const exposure = assessPublicExposure({
1344
1355
  routes: cachedRoutes,
1345
1356
  target: listenTarget,
1346
- allowUnauthenticatedWrites: config.security?.allowUnauthenticatedWrites ?? false
1357
+ allowUnauthenticatedWrites: config.security?.allowUnauthenticatedWrites ?? false,
1358
+ // `cachedRoutes` comes from the file-route scan and never describes controllers. Without this
1359
+ // the gate reads an empty table as "nothing is exposed" and binds a public interface in silence,
1360
+ // while a controller marked `theokit:public` on a POST sits on it (theokit#543).
1361
+ hasControllers: controllersDistDir !== void 0
1347
1362
  });
1348
1363
  if (exposure.kind === "refused") {
1349
1364
  console.error(`
@@ -1381,4 +1396,4 @@ export {
1381
1396
  resolveSsrEntry,
1382
1397
  startCommand
1383
1398
  };
1384
- //# sourceMappingURL=start-UAMJ5TSC.js.map
1399
+ //# sourceMappingURL=start-KEWSYVVU.js.map