theokit 0.54.1 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/dist/{actions-virtual-module-M4MTKOAX.js → actions-virtual-module-3V7VG2YL.js} +3 -3
  2. package/dist/{actions-virtual-module-FGJR3I7V.js → actions-virtual-module-KJBCM7PP.js} +21 -21
  3. package/dist/adapters/agent-mount.d.ts +1 -1
  4. package/dist/adapters/agent-mount.js +9 -9
  5. package/dist/{agent-TKCC4WZ6.js → agent-NLG77PFN.js} +3 -3
  6. package/dist/{agents-typed-client-INR2E7B3.js → agents-typed-client-PVUZU65B.js} +3 -3
  7. package/dist/{app-typed-client-6MNNVMJU.js → app-typed-client-XSXAORG6.js} +21 -21
  8. package/dist/{app-typed-client-22BZ3KDX.js → app-typed-client-ZO3VKJ3O.js} +3 -3
  9. package/dist/boot/index.js +3 -3
  10. package/dist/{build-JH53TZJI.js → build-4GQLIFTD.js} +5 -4
  11. package/dist/build-4GQLIFTD.js.map +1 -0
  12. package/dist/{bun-L7PP6ID5.js → bun-POLTY2HK.js} +118 -3
  13. package/dist/bun-POLTY2HK.js.map +1 -0
  14. package/dist/{chunk-IHAQUUT2.js → chunk-22ZZSUKD.js} +2 -2
  15. package/dist/chunk-22ZZSUKD.js.map +1 -0
  16. package/dist/{chunk-5YPXXSYY.js → chunk-35QIWOHT.js} +9 -8
  17. package/dist/chunk-35QIWOHT.js.map +1 -0
  18. package/dist/{chunk-JDN5SAAD.js → chunk-44E7XIZC.js} +6 -6
  19. package/dist/{chunk-OQCRCXCP.js → chunk-4ERYQBL6.js} +2 -2
  20. package/dist/{chunk-52PDWL5S.js → chunk-5KRMDP46.js} +2 -2
  21. package/dist/{chunk-HLDXHDCB.js → chunk-5TPBOAAH.js} +8 -8
  22. package/dist/{chunk-6VYF5PMG.js → chunk-6PFF5HMY.js} +3 -3
  23. package/dist/{chunk-VQPHPQ5L.js → chunk-7NRFZBAL.js} +3 -3
  24. package/dist/{chunk-3PBAN2YE.js → chunk-CF2DNN5R.js} +9 -8
  25. package/dist/{chunk-3PBAN2YE.js.map → chunk-CF2DNN5R.js.map} +1 -1
  26. package/dist/{chunk-HK4AZBKX.js → chunk-D5KBBTVD.js} +7 -7
  27. package/dist/{chunk-BU6RJPPJ.js → chunk-GO7UWJ47.js} +2 -2
  28. package/dist/{chunk-BU6RJPPJ.js.map → chunk-GO7UWJ47.js.map} +1 -1
  29. package/dist/{chunk-VZTYCAO6.js → chunk-IDEZ7FU2.js} +3 -3
  30. package/dist/{chunk-FVFYACYK.js → chunk-JW5UFKQ3.js} +17 -17
  31. package/dist/chunk-JW5UFKQ3.js.map +1 -0
  32. package/dist/{chunk-IRASEXOG.js → chunk-KDP2HURW.js} +6 -6
  33. package/dist/{chunk-AI7GBBRB.js → chunk-KQ27YDLG.js} +8 -8
  34. package/dist/{chunk-WX6NHGKS.js → chunk-M357ILK5.js} +10 -10
  35. package/dist/{chunk-ZQO37YQJ.js → chunk-PELXWPDF.js} +5 -5
  36. package/dist/{chunk-2OEN3YTE.js → chunk-PVNMLZ5G.js} +2 -2
  37. package/dist/{chunk-5K4TDLRG.js → chunk-SOYOYGWY.js} +3 -3
  38. package/dist/{chunk-SIGUGCBS.js → chunk-TUO2FE3S.js} +3 -3
  39. package/dist/{chunk-4X6H2BXP.js → chunk-U3SPBLJF.js} +3 -3
  40. package/dist/{chunk-BX6EUYHU.js → chunk-V6Y2SMRG.js} +3 -3
  41. package/dist/{chunk-I2UN46ZX.js → chunk-XJOU425Y.js} +17 -17
  42. package/dist/{chunk-DAE7BJ7H.js → chunk-XYVZJCZU.js} +4 -4
  43. package/dist/{chunk-BND4YZTQ.js → chunk-ZDCCILMP.js} +2 -2
  44. package/dist/{chunk-S6RWUH3J.js → chunk-ZTIB4QSV.js} +63 -63
  45. package/dist/cli/index.js +6 -6
  46. package/dist/{config-support-WQHQIJTA.js → config-support-O4REYSK5.js} +32 -1
  47. package/dist/{config-support-WQHQIJTA.js.map → config-support-O4REYSK5.js.map} +1 -1
  48. package/dist/{controller-swc-transform-T7ZTD55V.js → controller-swc-transform-7EZKG2IS.js} +2 -2
  49. package/dist/cost-types-BALTuBpG.d.ts +79 -0
  50. package/dist/{dev-6KDYNF5E.js → dev-ZNTHPBBN.js} +5 -5
  51. package/dist/{dev-emit-W27J3DLU.js → dev-emit-FIQASO3D.js} +7 -7
  52. package/dist/index.js +23 -23
  53. package/dist/{internal-api-TA37BXH7.js → internal-api-D76JZGSC.js} +3 -3
  54. package/dist/{internal-api-VUDJUWYE.js → internal-api-JNX3MTIM.js} +26 -26
  55. package/dist/{mcp-2RQCKWQR.js → mcp-IMY3NUCL.js} +3 -3
  56. package/dist/{preview-J57QZNTO.js → preview-K4NIQLAK.js} +3 -3
  57. package/dist/{provider-resolver-Dx6QuWrw.d.ts → provider-resolver-VS61zqsw.d.ts} +0 -11
  58. package/dist/{registry-KBZDCFVQ.js → registry-3LUHO4IB.js} +2 -2
  59. package/dist/server/agent/index.d.ts +1 -1
  60. package/dist/server/agent/index.js +3 -3
  61. package/dist/server/cost/index.d.ts +3 -80
  62. package/dist/server/cost/sqlite/index.d.ts +21 -0
  63. package/dist/server/cost/sqlite/index.js +102 -0
  64. package/dist/server/cost/sqlite/index.js.map +1 -0
  65. package/dist/server/cron/index.js +4 -4
  66. package/dist/server/http/index.js +7 -7
  67. package/dist/server/index.d.ts +5 -4
  68. package/dist/server/index.js +79 -79
  69. package/dist/server/jobs/index.d.ts +2 -2
  70. package/dist/server/jobs/index.js +4 -4
  71. package/dist/server/observability/index.js +2 -2
  72. package/dist/server/scan/index.js +6 -6
  73. package/dist/server/storage/index.d.ts +2 -2
  74. package/dist/server/webhook/index.js +1 -1
  75. package/dist/{server-boundary-4UIGB3G5.js → server-boundary-654WC5SA.js} +23 -23
  76. package/dist/{server-boundary-A2PUD4JV.js → server-boundary-NW6LNNGK.js} +3 -3
  77. package/dist/{server-routes-hmr-BWN3WIGR.js → server-routes-hmr-TNI3FNGM.js} +2 -2
  78. package/dist/{services-typed-client-IXNOPVZA.js → services-typed-client-ACTJHAEP.js} +2 -2
  79. package/dist/{start-3F4LVHWS.js → start-ONZXIWEG.js} +4 -4
  80. package/dist/{storage-manager-C6hmsaer.d.ts → storage-manager-BtG38jYl.d.ts} +1 -1
  81. package/dist/{storage-types-DsDTCPbp.d.ts → storage-types-CFGPFIdB.d.ts} +1 -1
  82. package/dist/vite-plugin/index.js +21 -21
  83. package/dist/{vite-plugin-VYNUCEI2.js → vite-plugin-UET2BUFW.js} +5 -5
  84. package/package.json +7 -3
  85. package/dist/build-JH53TZJI.js.map +0 -1
  86. package/dist/bun-L7PP6ID5.js.map +0 -1
  87. package/dist/chunk-5YPXXSYY.js.map +0 -1
  88. package/dist/chunk-FVFYACYK.js.map +0 -1
  89. package/dist/chunk-IHAQUUT2.js.map +0 -1
  90. /package/dist/{actions-virtual-module-M4MTKOAX.js.map → actions-virtual-module-3V7VG2YL.js.map} +0 -0
  91. /package/dist/{actions-virtual-module-FGJR3I7V.js.map → actions-virtual-module-KJBCM7PP.js.map} +0 -0
  92. /package/dist/{agent-TKCC4WZ6.js.map → agent-NLG77PFN.js.map} +0 -0
  93. /package/dist/{agents-typed-client-INR2E7B3.js.map → agents-typed-client-PVUZU65B.js.map} +0 -0
  94. /package/dist/{app-typed-client-6MNNVMJU.js.map → app-typed-client-XSXAORG6.js.map} +0 -0
  95. /package/dist/{app-typed-client-22BZ3KDX.js.map → app-typed-client-ZO3VKJ3O.js.map} +0 -0
  96. /package/dist/{chunk-JDN5SAAD.js.map → chunk-44E7XIZC.js.map} +0 -0
  97. /package/dist/{chunk-OQCRCXCP.js.map → chunk-4ERYQBL6.js.map} +0 -0
  98. /package/dist/{chunk-52PDWL5S.js.map → chunk-5KRMDP46.js.map} +0 -0
  99. /package/dist/{chunk-HLDXHDCB.js.map → chunk-5TPBOAAH.js.map} +0 -0
  100. /package/dist/{chunk-6VYF5PMG.js.map → chunk-6PFF5HMY.js.map} +0 -0
  101. /package/dist/{chunk-VQPHPQ5L.js.map → chunk-7NRFZBAL.js.map} +0 -0
  102. /package/dist/{chunk-HK4AZBKX.js.map → chunk-D5KBBTVD.js.map} +0 -0
  103. /package/dist/{chunk-VZTYCAO6.js.map → chunk-IDEZ7FU2.js.map} +0 -0
  104. /package/dist/{chunk-IRASEXOG.js.map → chunk-KDP2HURW.js.map} +0 -0
  105. /package/dist/{chunk-AI7GBBRB.js.map → chunk-KQ27YDLG.js.map} +0 -0
  106. /package/dist/{chunk-WX6NHGKS.js.map → chunk-M357ILK5.js.map} +0 -0
  107. /package/dist/{chunk-ZQO37YQJ.js.map → chunk-PELXWPDF.js.map} +0 -0
  108. /package/dist/{chunk-2OEN3YTE.js.map → chunk-PVNMLZ5G.js.map} +0 -0
  109. /package/dist/{chunk-5K4TDLRG.js.map → chunk-SOYOYGWY.js.map} +0 -0
  110. /package/dist/{chunk-SIGUGCBS.js.map → chunk-TUO2FE3S.js.map} +0 -0
  111. /package/dist/{chunk-4X6H2BXP.js.map → chunk-U3SPBLJF.js.map} +0 -0
  112. /package/dist/{chunk-BX6EUYHU.js.map → chunk-V6Y2SMRG.js.map} +0 -0
  113. /package/dist/{chunk-I2UN46ZX.js.map → chunk-XJOU425Y.js.map} +0 -0
  114. /package/dist/{chunk-DAE7BJ7H.js.map → chunk-XYVZJCZU.js.map} +0 -0
  115. /package/dist/{chunk-BND4YZTQ.js.map → chunk-ZDCCILMP.js.map} +0 -0
  116. /package/dist/{chunk-S6RWUH3J.js.map → chunk-ZTIB4QSV.js.map} +0 -0
  117. /package/dist/{controller-swc-transform-T7ZTD55V.js.map → controller-swc-transform-7EZKG2IS.js.map} +0 -0
  118. /package/dist/{dev-6KDYNF5E.js.map → dev-ZNTHPBBN.js.map} +0 -0
  119. /package/dist/{dev-emit-W27J3DLU.js.map → dev-emit-FIQASO3D.js.map} +0 -0
  120. /package/dist/{internal-api-TA37BXH7.js.map → internal-api-D76JZGSC.js.map} +0 -0
  121. /package/dist/{internal-api-VUDJUWYE.js.map → internal-api-JNX3MTIM.js.map} +0 -0
  122. /package/dist/{mcp-2RQCKWQR.js.map → mcp-IMY3NUCL.js.map} +0 -0
  123. /package/dist/{preview-J57QZNTO.js.map → preview-K4NIQLAK.js.map} +0 -0
  124. /package/dist/{registry-KBZDCFVQ.js.map → registry-3LUHO4IB.js.map} +0 -0
  125. /package/dist/{server-boundary-4UIGB3G5.js.map → server-boundary-654WC5SA.js.map} +0 -0
  126. /package/dist/{server-boundary-A2PUD4JV.js.map → server-boundary-NW6LNNGK.js.map} +0 -0
  127. /package/dist/{server-routes-hmr-BWN3WIGR.js.map → server-routes-hmr-TNI3FNGM.js.map} +0 -0
  128. /package/dist/{services-typed-client-IXNOPVZA.js.map → services-typed-client-ACTJHAEP.js.map} +0 -0
  129. /package/dist/{start-3F4LVHWS.js.map → start-ONZXIWEG.js.map} +0 -0
  130. /package/dist/{vite-plugin-VYNUCEI2.js.map → vite-plugin-UET2BUFW.js.map} +0 -0
@@ -1,16 +1,13 @@
1
1
  import {
2
2
  resolveTheoRootDir
3
- } from "./chunk-VQPHPQ5L.js";
3
+ } from "./chunk-7NRFZBAL.js";
4
4
  import {
5
5
  buildServicesProxyConfig,
6
6
  servicesConfigSchema
7
7
  } from "./chunk-SSYDEKWF.js";
8
8
  import {
9
9
  dispatchControllerRequest
10
- } from "./chunk-DAE7BJ7H.js";
11
- import {
12
- broadcastToDevtools
13
- } from "./chunk-OIGJOYX6.js";
10
+ } from "./chunk-XYVZJCZU.js";
14
11
  import {
15
12
  RUN_ID_HEADER,
16
13
  SSE_BASE_HEADERS,
@@ -35,10 +32,20 @@ import {
35
32
  securitySchema,
36
33
  storageSchema,
37
34
  uploadSchema
38
- } from "./chunk-WX6NHGKS.js";
35
+ } from "./chunk-M357ILK5.js";
36
+ import {
37
+ broadcastToDevtools
38
+ } from "./chunk-OIGJOYX6.js";
39
39
  import {
40
40
  loadEnv
41
- } from "./chunk-4X6H2BXP.js";
41
+ } from "./chunk-U3SPBLJF.js";
42
+ import {
43
+ CSP_REPORT_PATH,
44
+ CsrfReadinessStore,
45
+ applySecurityHeaders,
46
+ handleCspReport,
47
+ handleCsrfReadiness
48
+ } from "./chunk-BPYMC7SU.js";
42
49
  import {
43
50
  resolveTransformer
44
51
  } from "./chunk-OGLS76RN.js";
@@ -53,7 +60,13 @@ import {
53
60
  incomingMessageToHandlerRequest,
54
61
  sendError,
55
62
  writeWebResponseToServerResponse
56
- } from "./chunk-FVFYACYK.js";
63
+ } from "./chunk-JW5UFKQ3.js";
64
+ import {
65
+ validateCsrfRequest
66
+ } from "./chunk-P6OS7652.js";
67
+ import {
68
+ subjectFromContext
69
+ } from "./chunk-YN4W7LCX.js";
57
70
  import {
58
71
  findSuggestion
59
72
  } from "./chunk-NTDN54XO.js";
@@ -61,7 +74,7 @@ import {
61
74
  TRACE_HEADER,
62
75
  extractTraceId,
63
76
  logRequest
64
- } from "./chunk-BND4YZTQ.js";
77
+ } from "./chunk-ZDCCILMP.js";
65
78
  import {
66
79
  createPluginRunnerFromConfig
67
80
  } from "./chunk-VSLTKX5L.js";
@@ -70,26 +83,16 @@ import {
70
83
  } from "./chunk-TNI4MARH.js";
71
84
  import {
72
85
  createViteLoader
73
- } from "./chunk-OQCRCXCP.js";
86
+ } from "./chunk-4ERYQBL6.js";
74
87
  import {
75
88
  matchRoute,
76
89
  scanServerActions,
77
90
  scanServerRoutes,
78
91
  scanWebSocketRoutes
79
- } from "./chunk-I2UN46ZX.js";
92
+ } from "./chunk-XJOU425Y.js";
80
93
  import {
81
94
  scanAgents
82
- } from "./chunk-IRASEXOG.js";
83
- import {
84
- CSP_REPORT_PATH,
85
- CsrfReadinessStore,
86
- applySecurityHeaders,
87
- handleCspReport,
88
- handleCsrfReadiness
89
- } from "./chunk-BPYMC7SU.js";
90
- import {
91
- validateCsrfRequest
92
- } from "./chunk-P6OS7652.js";
95
+ } from "./chunk-KDP2HURW.js";
93
96
  import {
94
97
  extractAppResources,
95
98
  handleMcpJsonRpc,
@@ -97,25 +100,22 @@ import {
97
100
  } from "./chunk-YOIVCCZT.js";
98
101
  import {
99
102
  resolveProvider
100
- } from "./chunk-3PBAN2YE.js";
103
+ } from "./chunk-CF2DNN5R.js";
101
104
  import {
102
105
  generateNonce
103
106
  } from "./chunk-Z4PJMZLM.js";
104
107
  import {
105
108
  importUserModule
106
- } from "./chunk-52PDWL5S.js";
107
- import {
108
- subjectFromContext
109
- } from "./chunk-YN4W7LCX.js";
109
+ } from "./chunk-5KRMDP46.js";
110
110
 
111
111
  // src/vite-plugin/index.ts
112
- import { existsSync as existsSync8 } from "fs";
113
- import { resolve as resolve10, dirname as dirname4 } from "path";
114
- import { fileURLToPath } from "url";
112
+ import { existsSync as existsSync8 } from "node:fs";
113
+ import { resolve as resolve10, dirname as dirname4 } from "node:path";
114
+ import { fileURLToPath } from "node:url";
115
115
 
116
116
  // src/vite-plugin/config-hook.ts
117
- import { existsSync } from "fs";
118
- import { resolve } from "path";
117
+ import { existsSync } from "node:fs";
118
+ import { resolve } from "node:path";
119
119
  function runConfigHook(ctx) {
120
120
  const ext = existsSync(resolve(ctx.theoSrcDir, "index.ts")) ? ".ts" : ".js";
121
121
  const warmupClientFiles = [];
@@ -211,8 +211,8 @@ function runConfigHook(ctx) {
211
211
  }
212
212
 
213
213
  // src/config/load-config.ts
214
- import { existsSync as existsSync2 } from "fs";
215
- import { resolve as resolve2 } from "path";
214
+ import { existsSync as existsSync2 } from "node:fs";
215
+ import { resolve as resolve2 } from "node:path";
216
216
 
217
217
  // src/config/errors.ts
218
218
  var TheoConfigError = class extends Error {
@@ -571,8 +571,8 @@ async function loadConfig(dir) {
571
571
  }
572
572
 
573
573
  // src/config/resolve-plugin-specifiers.ts
574
- import { isAbsolute, resolve as resolve3 } from "path";
575
- import { pathToFileURL } from "url";
574
+ import { isAbsolute, resolve as resolve3 } from "node:path";
575
+ import { pathToFileURL } from "node:url";
576
576
  var UnresolvablePluginSpecifierError = class extends Error {
577
577
  constructor(index, specifier, reason) {
578
578
  super(`plugins[${index}] (${specifier}) could not be loaded: ${reason}`);
@@ -611,8 +611,8 @@ function messageOf(err) {
611
611
  }
612
612
 
613
613
  // src/vite-plugin/theoui-detect.ts
614
- import { existsSync as existsSync3, readFileSync } from "fs";
615
- import { dirname, join } from "path";
614
+ import { existsSync as existsSync3, readFileSync } from "node:fs";
615
+ import { dirname, join } from "node:path";
616
616
  function resolveTheoUiConfig(raw) {
617
617
  return {
618
618
  theme: raw?.theme ?? "violet-forge",
@@ -750,7 +750,7 @@ async function resolvePluginConfig(projectRoot) {
750
750
  }
751
751
 
752
752
  // src/vite-plugin/configure-server-hook.ts
753
- import { resolve as resolve8, basename } from "path";
753
+ import { resolve as resolve8, basename } from "node:path";
754
754
 
755
755
  // src/devtools/server-side/route-manifest.ts
756
756
  function buildPath(parents, segment) {
@@ -787,8 +787,8 @@ function broadcastRouteManifest(tree) {
787
787
  }
788
788
 
789
789
  // src/router/scan.ts
790
- import { readdirSync, statSync, existsSync as existsSync4 } from "fs";
791
- import { join as join2, resolve as resolve4 } from "path";
790
+ import { readdirSync, statSync, existsSync as existsSync4 } from "node:fs";
791
+ import { join as join2, resolve as resolve4 } from "node:path";
792
792
 
793
793
  // src/router/types.ts
794
794
  var ROUTE_FILE_NAMES = ["page", "layout", "error", "loading", "not-found"];
@@ -905,7 +905,7 @@ function scanRoutes(appDir) {
905
905
  }
906
906
 
907
907
  // src/vite-plugin/action-middleware.ts
908
- import { randomUUID } from "crypto";
908
+ import { randomUUID } from "node:crypto";
909
909
  var PREFIX = "/api/__actions/";
910
910
  function createActionMiddleware(vite, serverDir, options) {
911
911
  const loadModule = createViteLoader(vite);
@@ -988,7 +988,7 @@ function createActionMiddleware(vite, serverDir, options) {
988
988
  }
989
989
 
990
990
  // src/vite-plugin/agent-middleware.ts
991
- import { randomUUID as randomUUID2 } from "crypto";
991
+ import { randomUUID as randomUUID2 } from "node:crypto";
992
992
 
993
993
  // src/server/agent/agent-card-handler.ts
994
994
  import { buildAgentCard, compileAgentModule } from "@theokit/agents";
@@ -1820,7 +1820,7 @@ async function serveAgentTurn(t) {
1820
1820
  }
1821
1821
 
1822
1822
  // src/vite-plugin/api-middleware.ts
1823
- import { resolve as resolve6 } from "path";
1823
+ import { resolve as resolve6 } from "node:path";
1824
1824
  function shouldBypassApiMiddleware(url, prefixes) {
1825
1825
  if (!url.startsWith("/api/")) return true;
1826
1826
  if (prefixes.length === 0) return false;
@@ -2070,8 +2070,8 @@ function createApiMiddleware(vite, serverDir, rateLimitConfigOrOptions) {
2070
2070
  }
2071
2071
 
2072
2072
  // src/vite-plugin/ssr-dev-middleware.ts
2073
- import { readFileSync as readFileSync2 } from "fs";
2074
- import { resolve as resolve7 } from "path";
2073
+ import { readFileSync as readFileSync2 } from "node:fs";
2074
+ import { resolve as resolve7 } from "node:path";
2075
2075
 
2076
2076
  // src/core/contracts/find-root-div.ts
2077
2077
  function maskHtmlComments(html) {
@@ -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-W27J3DLU.js");
2336
+ const { reEmitOpenApi } = await import("./dev-emit-FIQASO3D.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);
@@ -2383,13 +2383,13 @@ async function integrateStudio(importStudio = () => import(
2383
2383
  }
2384
2384
 
2385
2385
  // src/vite-plugin/integrate-ui.ts
2386
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
2387
- import { dirname as dirname3, join as join4 } from "path";
2388
- import { pathToFileURL as pathToFileURL2 } from "url";
2386
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
2387
+ import { dirname as dirname3, join as join4 } from "node:path";
2388
+ import { pathToFileURL as pathToFileURL2 } from "node:url";
2389
2389
 
2390
2390
  // src/vite-plugin/auto-detect.ts
2391
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
2392
- import { dirname as dirname2, join as join3 } from "path";
2391
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
2392
+ import { dirname as dirname2, join as join3 } from "node:path";
2393
2393
  function isDeclared(name, projectRoot) {
2394
2394
  try {
2395
2395
  const raw = readFileSync3(join3(projectRoot, "package.json"), "utf-8");
@@ -2641,8 +2641,8 @@ async function integrateUseTheoUI(cwd, opts) {
2641
2641
  }
2642
2642
 
2643
2643
  // src/vite-plugin/transform-html-hook.ts
2644
- import { existsSync as existsSync7 } from "fs";
2645
- import { resolve as resolve9 } from "path";
2644
+ import { existsSync as existsSync7 } from "node:fs";
2645
+ import { resolve as resolve9 } from "node:path";
2646
2646
 
2647
2647
  // src/vite-plugin/inject-devtools.ts
2648
2648
  var DEVTOOLS_VIRTUAL_ID = "/@theo/devtools/entry.js";
@@ -3476,7 +3476,7 @@ async function theoPluginAsync(rootOrOptions) {
3476
3476
  const studioPlugins = await integrateStudio();
3477
3477
  const servicesPlugins = [];
3478
3478
  if (options.services && Object.keys(options.services).length > 0) {
3479
- const { servicesTypedClientPlugin } = await import("./services-typed-client-IXNOPVZA.js");
3479
+ const { servicesTypedClientPlugin } = await import("./services-typed-client-ACTJHAEP.js");
3480
3480
  servicesPlugins.push(
3481
3481
  servicesTypedClientPlugin({
3482
3482
  cwd: projectRoot,
@@ -3484,19 +3484,19 @@ async function theoPluginAsync(rootOrOptions) {
3484
3484
  })
3485
3485
  );
3486
3486
  }
3487
- const { appTypedClientPlugin } = await import("./app-typed-client-6MNNVMJU.js");
3487
+ const { appTypedClientPlugin } = await import("./app-typed-client-XSXAORG6.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-FGJR3I7V.js");
3493
+ const { actionsVirtualModule } = await import("./actions-virtual-module-KJBCM7PP.js");
3494
3494
  const actionsPlugin = actionsVirtualModule({
3495
3495
  serverDir: serverDirAbs,
3496
3496
  distDir: resolve10(projectRoot, ".theokit")
3497
3497
  });
3498
- const { agentsTypedClientPlugin } = await import("./agents-typed-client-INR2E7B3.js");
3499
- const { generateManifest } = await import("./internal-api-VUDJUWYE.js");
3498
+ const { agentsTypedClientPlugin } = await import("./agents-typed-client-PVUZU65B.js");
3499
+ const { generateManifest } = await import("./internal-api-JNX3MTIM.js");
3500
3500
  const agentsClientPlugin = agentsTypedClientPlugin({
3501
3501
  projectRoot,
3502
3502
  agentsDir: agentsDirName,
@@ -3505,15 +3505,15 @@ async function theoPluginAsync(rootOrOptions) {
3505
3505
  // parent (projectRoot for the canonical layout) + the agents dir name (#95 follow-up).
3506
3506
  scanManifest: () => generateManifest(serverDirAbs, projectRoot, agentsDirName)
3507
3507
  });
3508
- const { serverRoutesHmrPlugin } = await import("./server-routes-hmr-BWN3WIGR.js");
3508
+ const { serverRoutesHmrPlugin } = await import("./server-routes-hmr-TNI3FNGM.js");
3509
3509
  const routesHmrPlugin = serverRoutesHmrPlugin({
3510
3510
  serverDir: serverDirAbs
3511
3511
  });
3512
- const { controllerSwcTransformPlugin } = await import("./controller-swc-transform-T7ZTD55V.js");
3512
+ const { controllerSwcTransformPlugin } = await import("./controller-swc-transform-7EZKG2IS.js");
3513
3513
  const controllerTransformPlugin = controllerSwcTransformPlugin({
3514
3514
  serverDir: serverDirAbs
3515
3515
  });
3516
- const { serverOnlyImportBoundary } = await import("./server-boundary-4UIGB3G5.js");
3516
+ const { serverOnlyImportBoundary } = await import("./server-boundary-654WC5SA.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-S6RWUH3J.js.map
3699
+ //# sourceMappingURL=chunk-ZTIB4QSV.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-6KDYNF5E.js");
18
+ const { devCommand } = await import("../dev-ZNTHPBBN.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-JH53TZJI.js");
23
+ const { buildCommand } = await import("../build-4GQLIFTD.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-3F4LVHWS.js");
35
+ const { startCommand } = await import("../start-ONZXIWEG.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-J57QZNTO.js");
47
+ const { previewCommand } = await import("../preview-K4NIQLAK.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-TKCC4WZ6.js");
80
+ const { agentCommand } = await import("../agent-NLG77PFN.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-2RQCKWQR.js");
111
+ const { mcpCommand } = await import("../mcp-IMY3NUCL.js");
112
112
  await mcpCommand(agent);
113
113
  } catch (err) {
114
114
  const msg = err instanceof Error ? err.message : String(err);
@@ -95,10 +95,41 @@ function warnUnappliedConfig(config, adapter, target, log) {
95
95
  ${describeUnappliedConfig(target, dropped)}
96
96
  `);
97
97
  }
98
+ var UnenforceableRateLimitError = class extends Error {
99
+ constructor(target) {
100
+ super(
101
+ [
102
+ `Refusing to build for \`${target}\`: theo.config.ts declares a rate limit and this target does not enforce one.`,
103
+ ``,
104
+ ` The config reads as protection the deploy will not have. Nothing at runtime reports the`,
105
+ ` absence, so the first sign is abuse \u2014 which is why this refuses rather than warns.`,
106
+ ``,
107
+ ` Two honest ways forward:`,
108
+ ` \u2022 build for \`node\` and run \`theokit start\`, which applies the limit; or`,
109
+ ` \u2022 remove \`rateLimit\` from theo.config.ts, so the file states what actually runs.`,
110
+ ``,
111
+ ` There is deliberately no flag to keep the key and skip the check: a config that stays`,
112
+ ` while doing nothing is the state this refusal exists to end (usetheokit/theokit#461).`
113
+ ].join("\n")
114
+ );
115
+ this.target = target;
116
+ }
117
+ target;
118
+ name = "UnenforceableRateLimitError";
119
+ };
120
+ function assertRateLimitEnforceable(config, adapter, target) {
121
+ const applied = adapter.appliesConfig ?? [];
122
+ if (applied === "runtime-not-emitted-here") return;
123
+ if (!isDeclared(config, "rateLimit")) return;
124
+ if (applied.includes("rateLimit")) return;
125
+ throw new UnenforceableRateLimitError(target);
126
+ }
98
127
  export {
99
128
  CONFIG_CONCERNS,
129
+ UnenforceableRateLimitError,
130
+ assertRateLimitEnforceable,
100
131
  describeUnappliedConfig,
101
132
  findUnappliedConfig,
102
133
  warnUnappliedConfig
103
134
  };
104
- //# sourceMappingURL=config-support-WQHQIJTA.js.map
135
+ //# sourceMappingURL=config-support-O4REYSK5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapters/config-support.ts"],"sourcesContent":["/**\n * Which configuration a deploy target's emitted handler actually applies.\n *\n * `theo.config.ts` validates `rateLimit`, `security.cors`, `security.csrf`,\n * `security.disallowed` and `serialization` for every target. Applying them is\n * the handler's job, and the six Web-standards adapters build `executeRoute`'s\n * context from a subset of its fields, so the rest fall back to hard-coded\n * defaults on a deployed app (usetheokit/theokit#410). `security.cors` was read\n * only by the dev server until #409 wired it into `theokit start`; the six Web\n * targets still drop it.\n *\n * This module does not fix that. It makes it **audible at build time**: a\n * config key that is parsed and then dropped is named, with the target that\n * drops it and the next action. Silence was the defect — an operator who\n * declares a rate limit and gets none has no reason to look.\n *\n * It warns rather than refuses, deliberately. Refusing would break every\n * deployment that declares `rateLimit` today, and the real fix — wiring a\n * limiter that needs a per-runtime client address — is not a build away\n * (`docs/program/journeys/j07-rate-limit.md` § Correction measured what it\n * costs). Forcing an operator to delete valid configuration in order to ship\n * would trade a silent gap for a loud one that also loses information.\n */\nimport type { TheoConfig } from '../config/schema.js'\n\nimport { nodeAdapter } from './node.js'\nimport type { ConfigConcern, DeployAdapter } from './types.js'\n\n/**\n * The closed set. A concern belongs here when it is (a) declarable in\n * `theo.config.ts` and (b) applied by a request handler rather than at build\n * time — a build-time key cannot be silently dropped by a runtime.\n */\nexport const CONFIG_CONCERNS = [\n 'rateLimit',\n 'cors',\n 'csrf',\n 'disallowed',\n 'serialization',\n 'plugins',\n 'securityHeaders',\n] as const satisfies readonly ConfigConcern[]\n\n/**\n * Does any production target apply this concern?\n *\n * DERIVED from what the `node` adapter declares, rather than listed. This was a hand-maintained\n * `APPLIED_BY_NO_TARGET` set holding `cors`, kept in step with `nodeAdapter.appliesConfig` by a\n * test — and #409, which taught `theokit start` to apply `cors`, emptied it. An empty hardcoded\n * set is not merely redundant: it makes the branch below provably unreachable, which the linter\n * says out loud (`sonarjs/no-empty-collection`).\n *\n * Deriving keeps the branch honest AND reachable: the moment a concern is added that `node` does\n * not apply, the advice stops claiming a target exists for it, with nothing to remember.\n */\nfunction appliedByNoTarget(concern: ConfigConcern): boolean {\n const applied = nodeAdapter.appliesConfig\n if (applied === undefined || applied === 'runtime-not-emitted-here') return true\n return !applied.includes(concern)\n}\n\n/** Where each concern lives in the config, for a message the operator can grep. */\nconst CONFIG_KEY: Record<ConfigConcern, string> = {\n rateLimit: 'rateLimit',\n cors: 'security.cors',\n csrf: 'security.csrf',\n disallowed: 'security.disallowed',\n serialization: 'serialization',\n plugins: 'plugins',\n securityHeaders: 'security.headers',\n}\n\nfunction isDeclared(config: TheoConfig, concern: ConfigConcern): boolean {\n const security = config.security\n switch (concern) {\n case 'rateLimit':\n return config.rateLimit !== undefined\n case 'cors':\n return security?.cors !== undefined\n case 'csrf':\n // `csrf` carries `.default('strict')` (config/schemas/security.ts:100) and\n // the deployed fallback is also `'strict'` (server/http/execute.ts:144).\n // A config that says `'strict'` therefore gets what it asked for, by\n // coincidence rather than by wiring -- reporting it dropped would be noise\n // over an identical outcome. Only a weaker setting is silently ignored.\n return security?.csrf !== undefined && security.csrf !== 'strict'\n case 'disallowed':\n return security?.disallowed !== undefined && security.disallowed.routes.length > 0\n case 'securityHeaders':\n return security?.headers !== undefined\n case 'serialization':\n // Same shape: `.default('json')` (config/schema.ts:147), and a target with\n // no transformer serializes as JSON. `'json'` is honoured by coincidence;\n // `'superjson'` is the case where the deployed app quietly disagrees with\n // the file.\n return config.serialization !== 'json'\n case 'plugins':\n return config.plugins !== undefined && config.plugins.length > 0\n }\n}\n\n/**\n * The concerns this config declares and this adapter does not apply.\n *\n * An adapter that emits no request handler of its own answers\n * `'runtime-not-emitted-here'` and is never reported against: it is not that\n * the configuration is dropped, it is that this build cannot know. Saying\n * nothing is the honest output, and it is a different fact from saying no.\n */\nexport function findUnappliedConfig(\n config: TheoConfig,\n adapter: Pick<DeployAdapter, 'appliesConfig'>,\n): ConfigConcern[] {\n const applied = adapter.appliesConfig ?? []\n if (applied === 'runtime-not-emitted-here') return []\n return CONFIG_CONCERNS.filter(\n (concern) => isDeclared(config, concern) && !applied.includes(concern),\n )\n}\n\n/**\n * The build-time message. Empty string when nothing was dropped, so the caller\n * neither branches nor prints a header over an empty list.\n */\nexport function describeUnappliedConfig(target: string, dropped: readonly ConfigConcern[]): string {\n if (dropped.length === 0) return ''\n const one = dropped.length === 1\n const list = dropped.map((concern) => ` - ${CONFIG_KEY[concern]}`).join('\\n')\n const elsewhere = dropped.filter((concern) => !appliedByNoTarget(concern))\n const nowhere = dropped.filter(appliedByNoTarget)\n\n // The advice has to change with the target, or it degenerates. Building for\n // `node` with only `security.cors` dropped once produced \"deploy to `node`,\n // which applies all of the above except security.cors\" -- an instruction to\n // do what you are already doing, about the one key it then excepts.\n const actions: string[] = []\n if (elsewhere.length > 0 && target !== 'node') {\n actions.push(\n ` - ${elsewhere.map((c) => CONFIG_KEY[c]).join(', ')}: build for \\`node\\` and run \\`theokit start\\`,`,\n ` which applies ${elsewhere.length === 1 ? 'it' : 'them'}; or remove ${elsewhere.length === 1 ? 'it' : 'them'} so the file states what runs.`,\n )\n } else if (elsewhere.length > 0) {\n actions.push(\n ` - ${elsewhere.map((c) => CONFIG_KEY[c]).join(', ')}: remove ${elsewhere.length === 1 ? 'it' : 'them'} so the file states what runs.`,\n )\n }\n if (nowhere.length > 0) {\n actions.push(\n ` - ${nowhere.map((c) => CONFIG_KEY[c]).join(', ')}: no production target applies ${nowhere.length === 1 ? 'this' : 'these'} today`,\n ` (usetheokit/theokit#409) -- terminate it in front of the app, or remove it.`,\n )\n }\n\n return [\n ` ! ${String(dropped.length)} configuration ${one ? 'key is' : 'keys are'} validated and NOT applied on \\`${target}\\`:`,\n list,\n ` The handler this target emits never reads ${one ? 'it' : 'them'}, so the deployed app`,\n ` behaves as if ${one ? 'the key were' : 'the keys were'} absent.`,\n ` What to do:`,\n ...actions,\n ` Tracked: usetheokit/theokit#410 (deploy targets), usetheokit/theokit#409 (cors).`,\n ].join('\\n')\n}\n\n/**\n * Emit the warning, if there is one. The sink is injected so the behaviour is\n * exercisable without driving a whole build: the alternative was a caller that\n * only a full `theokit build` could reach, which in practice means a caller\n * nothing tests.\n */\nexport function warnUnappliedConfig(\n config: TheoConfig,\n adapter: Pick<DeployAdapter, 'appliesConfig'>,\n target: string,\n log: (message: string) => void,\n): void {\n const dropped = findUnappliedConfig(config, adapter)\n if (dropped.length === 0) return\n log(`\\n${describeUnappliedConfig(target, dropped)}\\n`)\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/adapters/config-support.ts"],"sourcesContent":["/**\n * Which configuration a deploy target's emitted handler actually applies.\n *\n * `theo.config.ts` validates `rateLimit`, `security.cors`, `security.csrf`,\n * `security.disallowed` and `serialization` for every target. Applying them is\n * the handler's job, and the six Web-standards adapters build `executeRoute`'s\n * context from a subset of its fields, so the rest fall back to hard-coded\n * defaults on a deployed app (usetheokit/theokit#410). `security.cors` was read\n * only by the dev server until #409 wired it into `theokit start`; the six Web\n * targets still drop it.\n *\n * This module does not fix that. It makes it **audible at build time**: a\n * config key that is parsed and then dropped is named, with the target that\n * drops it and the next action. Silence was the defect — an operator who\n * declares a rate limit and gets none has no reason to look.\n *\n * It warns rather than refuses, deliberately. Refusing would break every\n * deployment that declares `rateLimit` today, and the real fix — wiring a\n * limiter that needs a per-runtime client address — is not a build away\n * (`docs/program/journeys/j07-rate-limit.md` § Correction measured what it\n * costs). Forcing an operator to delete valid configuration in order to ship\n * would trade a silent gap for a loud one that also loses information.\n */\nimport type { TheoConfig } from '../config/schema.js'\n\nimport { nodeAdapter } from './node.js'\nimport type { ConfigConcern, DeployAdapter } from './types.js'\n\n/**\n * The closed set. A concern belongs here when it is (a) declarable in\n * `theo.config.ts` and (b) applied by a request handler rather than at build\n * time — a build-time key cannot be silently dropped by a runtime.\n */\nexport const CONFIG_CONCERNS = [\n 'rateLimit',\n 'cors',\n 'csrf',\n 'disallowed',\n 'serialization',\n 'plugins',\n 'securityHeaders',\n] as const satisfies readonly ConfigConcern[]\n\n/**\n * Does any production target apply this concern?\n *\n * DERIVED from what the `node` adapter declares, rather than listed. This was a hand-maintained\n * `APPLIED_BY_NO_TARGET` set holding `cors`, kept in step with `nodeAdapter.appliesConfig` by a\n * test — and #409, which taught `theokit start` to apply `cors`, emptied it. An empty hardcoded\n * set is not merely redundant: it makes the branch below provably unreachable, which the linter\n * says out loud (`sonarjs/no-empty-collection`).\n *\n * Deriving keeps the branch honest AND reachable: the moment a concern is added that `node` does\n * not apply, the advice stops claiming a target exists for it, with nothing to remember.\n */\nfunction appliedByNoTarget(concern: ConfigConcern): boolean {\n const applied = nodeAdapter.appliesConfig\n if (applied === undefined || applied === 'runtime-not-emitted-here') return true\n return !applied.includes(concern)\n}\n\n/** Where each concern lives in the config, for a message the operator can grep. */\nconst CONFIG_KEY: Record<ConfigConcern, string> = {\n rateLimit: 'rateLimit',\n cors: 'security.cors',\n csrf: 'security.csrf',\n disallowed: 'security.disallowed',\n serialization: 'serialization',\n plugins: 'plugins',\n securityHeaders: 'security.headers',\n}\n\nfunction isDeclared(config: TheoConfig, concern: ConfigConcern): boolean {\n const security = config.security\n switch (concern) {\n case 'rateLimit':\n return config.rateLimit !== undefined\n case 'cors':\n return security?.cors !== undefined\n case 'csrf':\n // `csrf` carries `.default('strict')` (config/schemas/security.ts:100) and\n // the deployed fallback is also `'strict'` (server/http/execute.ts:144).\n // A config that says `'strict'` therefore gets what it asked for, by\n // coincidence rather than by wiring -- reporting it dropped would be noise\n // over an identical outcome. Only a weaker setting is silently ignored.\n return security?.csrf !== undefined && security.csrf !== 'strict'\n case 'disallowed':\n return security?.disallowed !== undefined && security.disallowed.routes.length > 0\n case 'securityHeaders':\n return security?.headers !== undefined\n case 'serialization':\n // Same shape: `.default('json')` (config/schema.ts:147), and a target with\n // no transformer serializes as JSON. `'json'` is honoured by coincidence;\n // `'superjson'` is the case where the deployed app quietly disagrees with\n // the file.\n return config.serialization !== 'json'\n case 'plugins':\n return config.plugins !== undefined && config.plugins.length > 0\n }\n}\n\n/**\n * The concerns this config declares and this adapter does not apply.\n *\n * An adapter that emits no request handler of its own answers\n * `'runtime-not-emitted-here'` and is never reported against: it is not that\n * the configuration is dropped, it is that this build cannot know. Saying\n * nothing is the honest output, and it is a different fact from saying no.\n */\nexport function findUnappliedConfig(\n config: TheoConfig,\n adapter: Pick<DeployAdapter, 'appliesConfig'>,\n): ConfigConcern[] {\n const applied = adapter.appliesConfig ?? []\n if (applied === 'runtime-not-emitted-here') return []\n return CONFIG_CONCERNS.filter(\n (concern) => isDeclared(config, concern) && !applied.includes(concern),\n )\n}\n\n/**\n * The build-time message. Empty string when nothing was dropped, so the caller\n * neither branches nor prints a header over an empty list.\n */\nexport function describeUnappliedConfig(target: string, dropped: readonly ConfigConcern[]): string {\n if (dropped.length === 0) return ''\n const one = dropped.length === 1\n const list = dropped.map((concern) => ` - ${CONFIG_KEY[concern]}`).join('\\n')\n const elsewhere = dropped.filter((concern) => !appliedByNoTarget(concern))\n const nowhere = dropped.filter(appliedByNoTarget)\n\n // The advice has to change with the target, or it degenerates. Building for\n // `node` with only `security.cors` dropped once produced \"deploy to `node`,\n // which applies all of the above except security.cors\" -- an instruction to\n // do what you are already doing, about the one key it then excepts.\n const actions: string[] = []\n if (elsewhere.length > 0 && target !== 'node') {\n actions.push(\n ` - ${elsewhere.map((c) => CONFIG_KEY[c]).join(', ')}: build for \\`node\\` and run \\`theokit start\\`,`,\n ` which applies ${elsewhere.length === 1 ? 'it' : 'them'}; or remove ${elsewhere.length === 1 ? 'it' : 'them'} so the file states what runs.`,\n )\n } else if (elsewhere.length > 0) {\n actions.push(\n ` - ${elsewhere.map((c) => CONFIG_KEY[c]).join(', ')}: remove ${elsewhere.length === 1 ? 'it' : 'them'} so the file states what runs.`,\n )\n }\n if (nowhere.length > 0) {\n actions.push(\n ` - ${nowhere.map((c) => CONFIG_KEY[c]).join(', ')}: no production target applies ${nowhere.length === 1 ? 'this' : 'these'} today`,\n ` (usetheokit/theokit#409) -- terminate it in front of the app, or remove it.`,\n )\n }\n\n return [\n ` ! ${String(dropped.length)} configuration ${one ? 'key is' : 'keys are'} validated and NOT applied on \\`${target}\\`:`,\n list,\n ` The handler this target emits never reads ${one ? 'it' : 'them'}, so the deployed app`,\n ` behaves as if ${one ? 'the key were' : 'the keys were'} absent.`,\n ` What to do:`,\n ...actions,\n ` Tracked: usetheokit/theokit#410 (deploy targets), usetheokit/theokit#409 (cors).`,\n ].join('\\n')\n}\n\n/**\n * Emit the warning, if there is one. The sink is injected so the behaviour is\n * exercisable without driving a whole build: the alternative was a caller that\n * only a full `theokit build` could reach, which in practice means a caller\n * nothing tests.\n */\nexport function warnUnappliedConfig(\n config: TheoConfig,\n adapter: Pick<DeployAdapter, 'appliesConfig'>,\n target: string,\n log: (message: string) => void,\n): void {\n const dropped = findUnappliedConfig(config, adapter)\n if (dropped.length === 0) return\n log(`\\n${describeUnappliedConfig(target, dropped)}\\n`)\n}\n\n/**\n * A declared rate limit the chosen target cannot enforce.\n *\n * Its own class so a caller can distinguish it from a configuration typo — this is not the build\n * failing to understand the file, it is the build understanding it and refusing the combination.\n */\nexport class UnenforceableRateLimitError extends Error {\n override readonly name = 'UnenforceableRateLimitError'\n constructor(readonly target: string) {\n super(\n [\n `Refusing to build for \\`${target}\\`: theo.config.ts declares a rate limit and this target does not enforce one.`,\n ``,\n ` The config reads as protection the deploy will not have. Nothing at runtime reports the`,\n ` absence, so the first sign is abuse — which is why this refuses rather than warns.`,\n ``,\n ` Two honest ways forward:`,\n ` • build for \\`node\\` and run \\`theokit start\\`, which applies the limit; or`,\n ` • remove \\`rateLimit\\` from theo.config.ts, so the file states what actually runs.`,\n ``,\n ` There is deliberately no flag to keep the key and skip the check: a config that stays`,\n ` while doing nothing is the state this refusal exists to end (usetheokit/theokit#461).`,\n ].join('\\n'),\n )\n }\n}\n\n/**\n * Refuse a build whose target drops a DECLARED rate limit.\n *\n * Only `rateLimit`, and the narrowness is the design. A dropped `cors` or `serialization` degrades\n * where someone can see it, and `describeUnappliedConfig`'s warning is proportionate for those.\n * `rateLimit` is the one whose absence looks exactly like success, which is the same reasoning\n * `MissingRoutePolicyError` applies to an undeclared route policy: refuse where silence would be\n * read as safety.\n *\n * `'runtime-not-emitted-here'` is not judged. That adapter's runtime is someone else's and this\n * build cannot answer for it; refusing there would be asserting something unmeasured.\n */\nexport function assertRateLimitEnforceable(\n config: TheoConfig,\n adapter: Pick<DeployAdapter, 'appliesConfig'>,\n target: string,\n): void {\n const applied = adapter.appliesConfig ?? []\n if (applied === 'runtime-not-emitted-here') return\n if (!isDeclared(config, 'rateLimit')) return\n if (applied.includes('rateLimit')) return\n throw new UnenforceableRateLimitError(target)\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import "./chunk-XTHN6JBX.js";
2
2
 
3
3
  // src/vite-plugin/controller-swc-transform.ts
4
- import { resolve } from "path";
4
+ import { resolve } from "node:path";
5
5
  import { transformControllerSource } from "@theokit/http";
6
6
  function toPosix(p) {
7
7
  return p.replace(/\\/g, "/");
@@ -24,4 +24,4 @@ function controllerSwcTransformPlugin(options) {
24
24
  export {
25
25
  controllerSwcTransformPlugin
26
26
  };
27
- //# sourceMappingURL=controller-swc-transform-T7ZTD55V.js.map
27
+ //# sourceMappingURL=controller-swc-transform-7EZKG2IS.js.map
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Cost tracking types (R0.5.11).
3
+ *
4
+ * Phase 5 — Production-Readiness #4: adds `ToolUsageRecord` for per-tool
5
+ * latency / error tracking via SDK's onToolStart/onToolEnd/onToolError hooks.
6
+ * Same UsageStorageAdapter handles both via discriminated union.
7
+ *
8
+ * EC-9 (SHOULD TEST): backward compat — record() input without `kind` is
9
+ * normalized to 'llm' by the framework so external adapters from older
10
+ * versions keep working.
11
+ */
12
+ /**
13
+ * Per-LLM-call cost record (existing — gains optional `kind` discriminator).
14
+ */
15
+ interface UsageRecord {
16
+ /** Discriminator. Optional for backward-compat; defaults to 'llm'. */
17
+ kind?: 'llm';
18
+ /** User identifier (e.g., session userId, tenantId, apiKey hash). */
19
+ userId: string;
20
+ /** Model id (e.g., 'claude-sonnet-4-5-20250929'). */
21
+ model: string;
22
+ /** Token counts per direction. */
23
+ tokens: {
24
+ input: number;
25
+ output: number;
26
+ };
27
+ /** USD cost in fractional dollars. */
28
+ costUsd: number;
29
+ /** When the run happened. */
30
+ timestamp: Date;
31
+ }
32
+ /**
33
+ * Per-tool-invocation record (Phase 5 — Production-Readiness #4).
34
+ *
35
+ * Emitted by `trackAgentTools` on every `onToolEnd` / `onToolError`. The same
36
+ * `UsageStorageAdapter.record` accepts both record kinds via union.
37
+ */
38
+ interface ToolUsageRecord {
39
+ kind: 'tool';
40
+ userId: string;
41
+ conversationId: string;
42
+ toolName: string;
43
+ /**
44
+ * Unique per invocation; correlates onToolStart with onToolEnd / onToolError.
45
+ * EC-16 (DOCUMENT): callId uniqueness is SDK contract — if SDK ever reuses
46
+ * a callId, `trackAgentTools`'s Map uses last-write-wins (defensive).
47
+ */
48
+ callId: string;
49
+ /** True when the tool handler returned; false when it threw. */
50
+ success: boolean;
51
+ /** Milliseconds from onToolStart to onToolEnd / onToolError. */
52
+ durationMs: number;
53
+ /** Populated only when success === false. */
54
+ errorMessage?: string;
55
+ timestamp: Date;
56
+ }
57
+ interface UsageQuery {
58
+ userId: string;
59
+ period: {
60
+ from: Date;
61
+ to: Date;
62
+ };
63
+ }
64
+ interface UsageResult {
65
+ totalTokens: number;
66
+ totalCostUsd: number;
67
+ runs: number;
68
+ }
69
+ interface UsageStorageAdapter {
70
+ readonly name: string;
71
+ /**
72
+ * Record a usage event. Accepts both kinds; framework normalizes input
73
+ * without `kind` to 'llm' before calling adapter (EC-9 backward compat).
74
+ */
75
+ record(input: UsageRecord | ToolUsageRecord): Promise<void>;
76
+ getUsage(query: UsageQuery): Promise<UsageResult>;
77
+ }
78
+
79
+ export type { ToolUsageRecord as T, UsageStorageAdapter as U, UsageRecord as a, UsageQuery as b, UsageResult as c };
@@ -11,14 +11,14 @@ import {
11
11
  } from "./chunk-KTMQUYED.js";
12
12
  import {
13
13
  theoPluginAsync
14
- } from "./chunk-HLDXHDCB.js";
15
- import "./chunk-6VYF5PMG.js";
14
+ } from "./chunk-5TPBOAAH.js";
15
+ import "./chunk-6PFF5HMY.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-IHAQUUT2.js";
21
- import "./chunk-5YPXXSYY.js";
20
+ import "./chunk-22ZZSUKD.js";
21
+ import "./chunk-35QIWOHT.js";
22
22
  import "./chunk-MWWFXYW3.js";
23
23
  import "./chunk-RPET332G.js";
24
24
  import "./chunk-5VLP3GQ2.js";
@@ -123,4 +123,4 @@ export {
123
123
  devCommand,
124
124
  startDevServer
125
125
  };
126
- //# sourceMappingURL=dev-6KDYNF5E.js.map
126
+ //# sourceMappingURL=dev-ZNTHPBBN.js.map
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  generateManifest
3
- } from "./chunk-I2UN46ZX.js";
3
+ } from "./chunk-XJOU425Y.js";
4
+ import "./chunk-KDP2HURW.js";
4
5
  import "./chunk-DV34VG3N.js";
5
- import "./chunk-IRASEXOG.js";
6
- import "./chunk-5K4TDLRG.js";
6
+ import "./chunk-SOYOYGWY.js";
7
7
  import "./chunk-ZWN3AODA.js";
8
8
  import "./chunk-XTHN6JBX.js";
9
9
 
10
10
  // src/vite-plugin/openapi-emit/emit.ts
11
- import { mkdirSync, writeFileSync } from "fs";
12
- import { join } from "path";
11
+ import { mkdirSync, writeFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
13
 
14
14
  // src/vite-plugin/openapi-emit/zod-to-openapi.ts
15
15
  import { z } from "zod";
@@ -235,7 +235,7 @@ function applyServerOverride(servers) {
235
235
  }
236
236
 
237
237
  // src/vite-plugin/openapi-emit/load-routes.ts
238
- import { resolve } from "path";
238
+ import { resolve } from "node:path";
239
239
  var HTTP_METHOD_KEYS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
240
240
  async function loadRoutesForOpenApi(options) {
241
241
  const { serverDir, routes } = options;
@@ -339,4 +339,4 @@ export {
339
339
  _resetInFlightForTests,
340
340
  reEmitOpenApi
341
341
  };
342
- //# sourceMappingURL=dev-emit-W27J3DLU.js.map
342
+ //# sourceMappingURL=dev-emit-FIQASO3D.js.map