theokit 0.48.14 → 0.50.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 (337) hide show
  1. package/README.md +1 -0
  2. package/dist/{actions-virtual-module-YZRZMHAX.js → actions-virtual-module-DSIVNGK7.js} +14 -8
  3. package/dist/{actions-virtual-module-YZRZMHAX.js.map → actions-virtual-module-DSIVNGK7.js.map} +1 -1
  4. package/dist/{actions-virtual-module-E4PISKMB.js → actions-virtual-module-RXL2RJTW.js} +23 -12
  5. package/dist/actions-virtual-module-RXL2RJTW.js.map +1 -0
  6. package/dist/adapters/agent-mount.d.ts +127 -0
  7. package/dist/adapters/agent-mount.js +25 -0
  8. package/dist/adapters/security-headers.d.ts +132 -0
  9. package/dist/adapters/security-headers.js +64 -0
  10. package/dist/adapters/security-headers.js.map +1 -0
  11. package/dist/adapters/web-shim.d.ts +100 -13
  12. package/dist/adapters/web-shim.js +158 -54
  13. package/dist/adapters/web-shim.js.map +1 -1
  14. package/dist/agent-7IPEVCAY.js +15 -0
  15. package/dist/agent-scan-BZa-pagG.d.ts +16 -0
  16. package/dist/{app-typed-client-I4X2UJWW.js → app-typed-client-UTBMJZOE.js} +15 -9
  17. package/dist/app-typed-client-UTBMJZOE.js.map +1 -0
  18. package/dist/{app-typed-client-HLP26EYM.js → app-typed-client-XGDZKH73.js} +24 -13
  19. package/dist/app-typed-client-XGDZKH73.js.map +1 -0
  20. package/dist/aws-lambda-VKMYUMP2.js +261 -0
  21. package/dist/aws-lambda-VKMYUMP2.js.map +1 -0
  22. package/dist/{body-parser-web-4Z2QTPDU.js → body-parser-web-ON5CUTEL.js} +5 -2
  23. package/dist/body-parser-web-ON5CUTEL.js.map +1 -0
  24. package/dist/{body-parser-web-TIOTXPDW.js → body-parser-web-RV2SSAI3.js} +5 -2
  25. package/dist/body-parser-web-RV2SSAI3.js.map +1 -0
  26. package/dist/{build-F2Q5QTSC.js → build-VZODSYIQ.js} +72 -26
  27. package/dist/build-VZODSYIQ.js.map +1 -0
  28. package/dist/{bun-A5B2MJMO.js → bun-L7PP6ID5.js} +105 -13
  29. package/dist/bun-L7PP6ID5.js.map +1 -0
  30. package/dist/{check-45NKUVSQ.js → check-GIPZBFTX.js} +2 -2
  31. package/dist/{chunk-WYHYOYRH.js → chunk-2COPDKIG.js} +468 -203
  32. package/dist/chunk-2COPDKIG.js.map +1 -0
  33. package/dist/chunk-3PBAN2YE.js +146 -0
  34. package/dist/chunk-3PBAN2YE.js.map +1 -0
  35. package/dist/{chunk-HBU2GIMZ.js → chunk-3QPVEJ7D.js} +15 -9
  36. package/dist/chunk-3QPVEJ7D.js.map +1 -0
  37. package/dist/{chunk-IEES3CHD.js → chunk-47MM2JUK.js} +8 -2
  38. package/dist/chunk-47MM2JUK.js.map +1 -0
  39. package/dist/chunk-4X6H2BXP.js +108 -0
  40. package/dist/chunk-4X6H2BXP.js.map +1 -0
  41. package/dist/{chunk-A7JBF5FO.js → chunk-5K4TDLRG.js} +8 -5
  42. package/dist/chunk-5K4TDLRG.js.map +1 -0
  43. package/dist/chunk-5YPXXSYY.js +181 -0
  44. package/dist/chunk-5YPXXSYY.js.map +1 -0
  45. package/dist/{chunk-YGAXV5HR.js → chunk-6J4JWHDJ.js} +191 -112
  46. package/dist/chunk-6J4JWHDJ.js.map +1 -0
  47. package/dist/{chunk-FTFN4MYN.js → chunk-7AEBH52I.js} +639 -516
  48. package/dist/chunk-7AEBH52I.js.map +1 -0
  49. package/dist/chunk-7UZZHCRN.js +21 -0
  50. package/dist/chunk-7UZZHCRN.js.map +1 -0
  51. package/dist/{chunk-MTEWLGVY.js → chunk-BPYMC7SU.js} +4 -48
  52. package/dist/chunk-BPYMC7SU.js.map +1 -0
  53. package/dist/chunk-BU6RJPPJ.js +421 -0
  54. package/dist/chunk-BU6RJPPJ.js.map +1 -0
  55. package/dist/{chunk-FB2HBNIC.js → chunk-BX6EUYHU.js} +6 -2
  56. package/dist/chunk-BX6EUYHU.js.map +1 -0
  57. package/dist/chunk-CHTAWXC2.js +18 -0
  58. package/dist/chunk-CHTAWXC2.js.map +1 -0
  59. package/dist/chunk-D4VP2QPR.js +16 -0
  60. package/dist/chunk-D4VP2QPR.js.map +1 -0
  61. package/dist/{chunk-YXG2SGQ3.js → chunk-DHAD2O3S.js} +6 -6
  62. package/dist/chunk-DHAD2O3S.js.map +1 -0
  63. package/dist/chunk-DOI4G4X3.js +428 -0
  64. package/dist/chunk-DOI4G4X3.js.map +1 -0
  65. package/dist/chunk-E43VJ3E5.js +188 -0
  66. package/dist/chunk-E43VJ3E5.js.map +1 -0
  67. package/dist/{chunk-47CINLWF.js → chunk-EDWEYQRG.js} +2 -2
  68. package/dist/chunk-EVZKNA2W.js +110 -0
  69. package/dist/chunk-EVZKNA2W.js.map +1 -0
  70. package/dist/chunk-FD4ZDTQ6.js +181 -0
  71. package/dist/chunk-FD4ZDTQ6.js.map +1 -0
  72. package/dist/chunk-FDOOBTXJ.js +17 -0
  73. package/dist/chunk-FDOOBTXJ.js.map +1 -0
  74. package/dist/chunk-FH3SQR6P.js +275 -0
  75. package/dist/chunk-FH3SQR6P.js.map +1 -0
  76. package/dist/{chunk-T5C46IIU.js → chunk-FMTRNQQ7.js} +28 -269
  77. package/dist/chunk-FMTRNQQ7.js.map +1 -0
  78. package/dist/chunk-H53KNS6Q.js +513 -0
  79. package/dist/chunk-H53KNS6Q.js.map +1 -0
  80. package/dist/chunk-HJHGTFEJ.js +23 -0
  81. package/dist/chunk-HJHGTFEJ.js.map +1 -0
  82. package/dist/{chunk-LXAESF4Y.js → chunk-HK4AZBKX.js} +7 -4
  83. package/dist/chunk-HK4AZBKX.js.map +1 -0
  84. package/dist/chunk-IRQGAC4L.js +52 -0
  85. package/dist/chunk-IRQGAC4L.js.map +1 -0
  86. package/dist/{chunk-FNTLKHZ7.js → chunk-JDN5SAAD.js} +7 -4
  87. package/dist/chunk-JDN5SAAD.js.map +1 -0
  88. package/dist/{chunk-XALU5LCU.js → chunk-JKF25N73.js} +555 -147
  89. package/dist/chunk-JKF25N73.js.map +1 -0
  90. package/dist/{chunk-BHOTGS7N.js → chunk-KI4DOTN4.js} +25 -2
  91. package/dist/chunk-KI4DOTN4.js.map +1 -0
  92. package/dist/chunk-KOS567NB.js +790 -0
  93. package/dist/chunk-KOS567NB.js.map +1 -0
  94. package/dist/{chunk-OOBYPCZC.js → chunk-KTS6G26H.js} +304 -195
  95. package/dist/chunk-KTS6G26H.js.map +1 -0
  96. package/dist/{chunk-ZB7D62OA.js → chunk-KUZVRJ7M.js} +3 -3
  97. package/dist/chunk-L4VFNFDL.js +248 -0
  98. package/dist/chunk-L4VFNFDL.js.map +1 -0
  99. package/dist/chunk-M2WC5MF7.js +127 -0
  100. package/dist/chunk-M2WC5MF7.js.map +1 -0
  101. package/dist/chunk-N42ZWWOW.js +273 -0
  102. package/dist/chunk-N42ZWWOW.js.map +1 -0
  103. package/dist/chunk-OGLS76RN.js +43 -0
  104. package/dist/chunk-OGLS76RN.js.map +1 -0
  105. package/dist/{chunk-7LVM22VG.js → chunk-OQCRCXCP.js} +6 -6
  106. package/dist/chunk-OQCRCXCP.js.map +1 -0
  107. package/dist/{chunk-OLGPYOLO.js → chunk-P6OS7652.js} +5 -2
  108. package/dist/chunk-P6OS7652.js.map +1 -0
  109. package/dist/{chunk-O3JIAU3V.js → chunk-PF3YM6NY.js} +157 -103
  110. package/dist/chunk-PF3YM6NY.js.map +1 -0
  111. package/dist/{chunk-NTWNO24W.js → chunk-PLUHPNGA.js} +266 -110
  112. package/dist/chunk-PLUHPNGA.js.map +1 -0
  113. package/dist/chunk-Q5L5EGWZ.js +26 -0
  114. package/dist/chunk-Q5L5EGWZ.js.map +1 -0
  115. package/dist/{chunk-AATSV4UV.js → chunk-QTHVHNJJ.js} +6 -36
  116. package/dist/chunk-QTHVHNJJ.js.map +1 -0
  117. package/dist/{chunk-KD5G3YXI.js → chunk-RARK7JBR.js} +39 -10
  118. package/dist/chunk-RARK7JBR.js.map +1 -0
  119. package/dist/chunk-RJJF457I.js +111 -0
  120. package/dist/chunk-RJJF457I.js.map +1 -0
  121. package/dist/chunk-RPET332G.js +84 -0
  122. package/dist/chunk-RPET332G.js.map +1 -0
  123. package/dist/{chunk-646CA6RV.js → chunk-RQW5YMH7.js} +12 -4
  124. package/dist/chunk-RQW5YMH7.js.map +1 -0
  125. package/dist/chunk-U5PWXS3J.js +39 -0
  126. package/dist/chunk-U5PWXS3J.js.map +1 -0
  127. package/dist/{chunk-RWNSW4FM.js → chunk-UMNXCU3K.js} +12 -6
  128. package/dist/{chunk-RWNSW4FM.js.map → chunk-UMNXCU3K.js.map} +1 -1
  129. package/dist/{chunk-DS5MCU2X.js → chunk-URCXSUI3.js} +9 -9
  130. package/dist/chunk-VI7ZANB3.js +193 -0
  131. package/dist/chunk-VI7ZANB3.js.map +1 -0
  132. package/dist/chunk-VQPHPQ5L.js +14 -0
  133. package/dist/chunk-VQPHPQ5L.js.map +1 -0
  134. package/dist/chunk-WNJTJRM6.js +147 -0
  135. package/dist/chunk-WNJTJRM6.js.map +1 -0
  136. package/dist/{chunk-BMHS4WAN.js → chunk-XS7EX55U.js} +156 -42
  137. package/dist/chunk-XS7EX55U.js.map +1 -0
  138. package/dist/chunk-YN4W7LCX.js +31 -0
  139. package/dist/chunk-YN4W7LCX.js.map +1 -0
  140. package/dist/chunk-YSJOZEI6.js +1 -0
  141. package/dist/{chunk-JA2ZAT5Q.js → chunk-Z4PJMZLM.js} +2 -2
  142. package/dist/chunk-Z4PJMZLM.js.map +1 -0
  143. package/dist/{chunk-WSXNGF7X.js → chunk-ZNZISJDZ.js} +6 -2
  144. package/dist/chunk-ZNZISJDZ.js.map +1 -0
  145. package/dist/chunk-ZWN3AODA.js +11 -0
  146. package/dist/chunk-ZWN3AODA.js.map +1 -0
  147. package/dist/cli/index.js +25 -10
  148. package/dist/cli/index.js.map +1 -1
  149. package/dist/client/core.d.ts +1 -1
  150. package/dist/client/core.js +2 -0
  151. package/dist/client/core.js.map +1 -1
  152. package/dist/client/index.d.ts +44 -10
  153. package/dist/client/index.js +35 -0
  154. package/dist/client/index.js.map +1 -1
  155. package/dist/cloudflare-SIG42OIW.js +335 -0
  156. package/dist/cloudflare-SIG42OIW.js.map +1 -0
  157. package/dist/config-support-WQHQIJTA.js +104 -0
  158. package/dist/config-support-WQHQIJTA.js.map +1 -0
  159. package/dist/{csrf-BBrEZSBW.d.ts → csrf-Dgot9qSM.d.ts} +1 -1
  160. package/dist/deno-deploy-LQAYOOPW.js +196 -0
  161. package/dist/deno-deploy-LQAYOOPW.js.map +1 -0
  162. package/dist/{dev-CDFPXISP.js → dev-3UQVD2W6.js} +29 -18
  163. package/dist/dev-3UQVD2W6.js.map +1 -0
  164. package/dist/{dev-emit-GWD6IXV7.js → dev-emit-BFNMDCPB.js} +5 -5
  165. package/dist/{dev-emit-NBT6JD7R.js → dev-emit-MVAJAFGX.js} +5 -3
  166. package/dist/dev-emit-MVAJAFGX.js.map +1 -0
  167. package/dist/engine-singleton-X4R7AZBJ.js +315 -0
  168. package/dist/engine-singleton-X4R7AZBJ.js.map +1 -0
  169. package/dist/{generate-Y3GWM57K.js → generate-EN6EDITF.js} +43 -4
  170. package/dist/generate-EN6EDITF.js.map +1 -0
  171. package/dist/index-DctfHtv-.d.ts +1058 -0
  172. package/dist/index.d.ts +8 -4
  173. package/dist/index.js +25 -13
  174. package/dist/index.js.map +1 -1
  175. package/dist/{info-QXZW722N.js → info-Y55RWS42.js} +8 -6
  176. package/dist/{info-QXZW722N.js.map → info-Y55RWS42.js.map} +1 -1
  177. package/dist/{internal-api-FBK2YXSI.js → internal-api-4X6NDS2F.js} +23 -12
  178. package/dist/{internal-api-ZCJWJ5EC.js → internal-api-XQHU5JKY.js} +31 -16
  179. package/dist/internal-api-XQHU5JKY.js.map +1 -0
  180. package/dist/load-config-4ATXQUN3.js +16 -0
  181. package/dist/match-DmGgxjIU.d.ts +44 -0
  182. package/dist/{mcp-KTYP4ZON.js → mcp-IQRHFP3Y.js} +7 -7
  183. package/dist/netlify-C2IRCZKI.js +245 -0
  184. package/dist/netlify-C2IRCZKI.js.map +1 -0
  185. package/dist/node-OSVPYQ3D.js +10 -0
  186. package/dist/nonce-BXt7Qu_C.d.ts +31 -0
  187. package/dist/observability-bootstrap-LERYDHKY.js +16 -0
  188. package/dist/{openapi-OUXNB2F2.js → openapi-VFPEZSRI.js} +13 -11
  189. package/dist/{openapi-OUXNB2F2.js.map → openapi-VFPEZSRI.js.map} +1 -1
  190. package/dist/{plugin-runner-DHVr1cC5.d.ts → plugin-runner-BVMOSxvb.d.ts} +1 -1
  191. package/dist/{plugin-types-4VN1GMqV.d.ts → plugin-types-BUVfUQ0V.d.ts} +1 -1
  192. package/dist/preview-BT47VMIB.js +23 -0
  193. package/dist/preview-BT47VMIB.js.map +1 -0
  194. package/dist/provider-resolver-Dx6QuWrw.d.ts +128 -0
  195. package/dist/registry-KBZDCFVQ.js +23 -0
  196. package/dist/route-config-Cm_ZMA1C.d.ts +72 -0
  197. package/dist/route-policy-BxOycCDq.d.ts +65 -0
  198. package/dist/router/element-scroll-restoration.d.ts +28 -0
  199. package/dist/router/element-scroll-restoration.js +96 -0
  200. package/dist/router/element-scroll-restoration.js.map +1 -0
  201. package/dist/{routes-NJR4ISCT.js → routes-BPLU3ISV.js} +11 -9
  202. package/dist/{routes-NJR4ISCT.js.map → routes-BPLU3ISV.js.map} +1 -1
  203. package/dist/{scan-7MJC6PYU.js → scan-YJEE4KQK.js} +2 -2
  204. package/dist/{schema-DNIT7JQX.js → schema-SOAD43RQ.js} +7 -5
  205. package/dist/schemas-4AXHQMV3.js +25 -0
  206. package/dist/schemas-4AXHQMV3.js.map +1 -0
  207. package/dist/security-headers-Ccj7ncNx.d.ts +129 -0
  208. package/dist/server/agent/index.d.ts +2 -105
  209. package/dist/server/agent/index.js +1 -1
  210. package/dist/server/auth/index.d.ts +2 -21
  211. package/dist/server/auth/index.js +3 -2
  212. package/dist/server/cron/index.js +4 -3
  213. package/dist/server/define/index.d.ts +43 -57
  214. package/dist/server/define/index.js +10 -1
  215. package/dist/server/http/index.d.ts +7 -5
  216. package/dist/server/http/index.js +57 -12
  217. package/dist/server/index.d.ts +47 -439
  218. package/dist/server/index.js +120 -201
  219. package/dist/server/index.js.map +1 -1
  220. package/dist/server/jobs/index.js +4 -3
  221. package/dist/server/observability/index.d.ts +109 -35
  222. package/dist/server/observability/index.js +11 -7
  223. package/dist/server/plugins/index.d.ts +3 -3
  224. package/dist/server/scan/index.d.ts +47 -12
  225. package/dist/server/scan/index.js +13 -4
  226. package/dist/server/security/index.d.ts +61 -103
  227. package/dist/server/security/index.js +15 -6
  228. package/dist/server/webhook/index.d.ts +90 -3
  229. package/dist/server/webhook/index.js +12 -2
  230. package/dist/server-boundary-2WFT546S.js +149 -0
  231. package/dist/server-boundary-2WFT546S.js.map +1 -0
  232. package/dist/server-boundary-A67OPRKO.js +134 -0
  233. package/dist/server-boundary-A67OPRKO.js.map +1 -0
  234. package/dist/{services-typed-client-P4JERLBL.js → services-typed-client-XGT5SUUN.js} +2 -2
  235. package/dist/{start-25OV2CAK.js → start-3K3C4Z2X.js} +224 -161
  236. package/dist/start-3K3C4Z2X.js.map +1 -0
  237. package/dist/{static-RTO637XW.js → static-SVDWIOXJ.js} +24 -13
  238. package/dist/static-SVDWIOXJ.js.map +1 -0
  239. package/dist/{theo-cloud-UZ3GINRU.js → theo-cloud-3ET4G5T6.js} +9 -2
  240. package/dist/theo-cloud-3ET4G5T6.js.map +1 -0
  241. package/dist/vercel-BMCQKCWE.js +277 -0
  242. package/dist/vercel-BMCQKCWE.js.map +1 -0
  243. package/dist/vite-plugin/index.js +25 -13
  244. package/dist/vite-plugin-USXUIV3H.js +43 -0
  245. package/dist/vite-plugin-USXUIV3H.js.map +1 -0
  246. package/package.json +19 -6
  247. package/dist/actions-virtual-module-E4PISKMB.js.map +0 -1
  248. package/dist/agent-XAQCUQNB.js +0 -15
  249. package/dist/app-typed-client-HLP26EYM.js.map +0 -1
  250. package/dist/app-typed-client-I4X2UJWW.js.map +0 -1
  251. package/dist/aws-lambda-KES4MFJV.js +0 -172
  252. package/dist/aws-lambda-KES4MFJV.js.map +0 -1
  253. package/dist/body-parser-web-4Z2QTPDU.js.map +0 -1
  254. package/dist/body-parser-web-TIOTXPDW.js.map +0 -1
  255. package/dist/build-F2Q5QTSC.js.map +0 -1
  256. package/dist/bun-A5B2MJMO.js.map +0 -1
  257. package/dist/chunk-646CA6RV.js.map +0 -1
  258. package/dist/chunk-7LVM22VG.js.map +0 -1
  259. package/dist/chunk-A7JBF5FO.js.map +0 -1
  260. package/dist/chunk-AATSV4UV.js.map +0 -1
  261. package/dist/chunk-AM3QABW5.js +0 -161
  262. package/dist/chunk-AM3QABW5.js.map +0 -1
  263. package/dist/chunk-AXKUA57G.js +0 -94
  264. package/dist/chunk-AXKUA57G.js.map +0 -1
  265. package/dist/chunk-BHOTGS7N.js.map +0 -1
  266. package/dist/chunk-BMHS4WAN.js.map +0 -1
  267. package/dist/chunk-CMYSHZFT.js +0 -422
  268. package/dist/chunk-CMYSHZFT.js.map +0 -1
  269. package/dist/chunk-DQIPV7L5.js +0 -118
  270. package/dist/chunk-DQIPV7L5.js.map +0 -1
  271. package/dist/chunk-FB2HBNIC.js.map +0 -1
  272. package/dist/chunk-FNTLKHZ7.js.map +0 -1
  273. package/dist/chunk-FTFN4MYN.js.map +0 -1
  274. package/dist/chunk-HBU2GIMZ.js.map +0 -1
  275. package/dist/chunk-IEES3CHD.js.map +0 -1
  276. package/dist/chunk-JA2ZAT5Q.js.map +0 -1
  277. package/dist/chunk-KD5G3YXI.js.map +0 -1
  278. package/dist/chunk-KTKTHIUF.js +0 -405
  279. package/dist/chunk-KTKTHIUF.js.map +0 -1
  280. package/dist/chunk-LNVMHQ2Z.js +0 -54
  281. package/dist/chunk-LNVMHQ2Z.js.map +0 -1
  282. package/dist/chunk-LXAESF4Y.js.map +0 -1
  283. package/dist/chunk-MTEWLGVY.js.map +0 -1
  284. package/dist/chunk-NTWNO24W.js.map +0 -1
  285. package/dist/chunk-O3JIAU3V.js.map +0 -1
  286. package/dist/chunk-OLGPYOLO.js.map +0 -1
  287. package/dist/chunk-OOBYPCZC.js.map +0 -1
  288. package/dist/chunk-T5C46IIU.js.map +0 -1
  289. package/dist/chunk-U267AOWS.js +0 -28
  290. package/dist/chunk-U267AOWS.js.map +0 -1
  291. package/dist/chunk-UW2TEAGR.js +0 -77
  292. package/dist/chunk-UW2TEAGR.js.map +0 -1
  293. package/dist/chunk-WPJOTQA5.js +0 -1
  294. package/dist/chunk-WSXNGF7X.js.map +0 -1
  295. package/dist/chunk-WYHYOYRH.js.map +0 -1
  296. package/dist/chunk-XALU5LCU.js.map +0 -1
  297. package/dist/chunk-XR74JD4M.js +0 -457
  298. package/dist/chunk-XR74JD4M.js.map +0 -1
  299. package/dist/chunk-YGAXV5HR.js.map +0 -1
  300. package/dist/chunk-YXG2SGQ3.js.map +0 -1
  301. package/dist/cloudflare-IN2WB7FZ.js +0 -122
  302. package/dist/cloudflare-IN2WB7FZ.js.map +0 -1
  303. package/dist/deno-deploy-LYXQEJ6A.js +0 -107
  304. package/dist/deno-deploy-LYXQEJ6A.js.map +0 -1
  305. package/dist/dev-CDFPXISP.js.map +0 -1
  306. package/dist/dev-emit-NBT6JD7R.js.map +0 -1
  307. package/dist/generate-Y3GWM57K.js.map +0 -1
  308. package/dist/index-D_PxPXgQ.d.ts +0 -575
  309. package/dist/load-config-FIWNKOJO.js +0 -14
  310. package/dist/match-CfbEFRG4.d.ts +0 -26
  311. package/dist/netlify-DLEOCFAD.js +0 -150
  312. package/dist/netlify-DLEOCFAD.js.map +0 -1
  313. package/dist/node-QXYSUWQ4.js +0 -10
  314. package/dist/registry-S7OMF3OS.js +0 -23
  315. package/dist/start-25OV2CAK.js.map +0 -1
  316. package/dist/static-RTO637XW.js.map +0 -1
  317. package/dist/theo-cloud-UZ3GINRU.js.map +0 -1
  318. package/dist/vercel-6D6EZUVD.js +0 -133
  319. package/dist/vercel-6D6EZUVD.js.map +0 -1
  320. package/dist/vite-plugin-RJFKLF2U.js +0 -36
  321. /package/dist/{chunk-WPJOTQA5.js.map → adapters/agent-mount.js.map} +0 -0
  322. /package/dist/{agent-XAQCUQNB.js.map → agent-7IPEVCAY.js.map} +0 -0
  323. /package/dist/{check-45NKUVSQ.js.map → check-GIPZBFTX.js.map} +0 -0
  324. /package/dist/{chunk-47CINLWF.js.map → chunk-EDWEYQRG.js.map} +0 -0
  325. /package/dist/{chunk-ZB7D62OA.js.map → chunk-KUZVRJ7M.js.map} +0 -0
  326. /package/dist/{chunk-DS5MCU2X.js.map → chunk-URCXSUI3.js.map} +0 -0
  327. /package/dist/{internal-api-ZCJWJ5EC.js.map → chunk-YSJOZEI6.js.map} +0 -0
  328. /package/dist/{dev-emit-GWD6IXV7.js.map → dev-emit-BFNMDCPB.js.map} +0 -0
  329. /package/dist/{internal-api-FBK2YXSI.js.map → internal-api-4X6NDS2F.js.map} +0 -0
  330. /package/dist/{load-config-FIWNKOJO.js.map → load-config-4ATXQUN3.js.map} +0 -0
  331. /package/dist/{mcp-KTYP4ZON.js.map → mcp-IQRHFP3Y.js.map} +0 -0
  332. /package/dist/{node-QXYSUWQ4.js.map → node-OSVPYQ3D.js.map} +0 -0
  333. /package/dist/{scan-7MJC6PYU.js.map → observability-bootstrap-LERYDHKY.js.map} +0 -0
  334. /package/dist/{registry-S7OMF3OS.js.map → registry-KBZDCFVQ.js.map} +0 -0
  335. /package/dist/{schema-DNIT7JQX.js.map → scan-YJEE4KQK.js.map} +0 -0
  336. /package/dist/{vite-plugin-RJFKLF2U.js.map → schema-SOAD43RQ.js.map} +0 -0
  337. /package/dist/{services-typed-client-P4JERLBL.js.map → services-typed-client-XGT5SUUN.js.map} +0 -0
@@ -1,7 +1,13 @@
1
+ import {
2
+ resolveTheoRootDir
3
+ } from "./chunk-VQPHPQ5L.js";
1
4
  import {
2
5
  buildServicesProxyConfig,
3
6
  servicesConfigSchema
4
7
  } from "./chunk-SSYDEKWF.js";
8
+ import {
9
+ dispatchControllerRequest
10
+ } from "./chunk-RJJF457I.js";
5
11
  import {
6
12
  broadcastToDevtools
7
13
  } from "./chunk-OIGJOYX6.js";
@@ -9,38 +15,53 @@ import {
9
15
  RUN_ID_HEADER,
10
16
  SSE_BASE_HEADERS,
11
17
  SSE_DONE_FRAME,
12
- dispatchControllerRequest,
18
+ admitAgentRequest,
19
+ agentAccessDenied,
20
+ cacheSchema,
21
+ closePauseSpan,
22
+ createObservabilityPluginFromConfig,
13
23
  encodeSse,
14
24
  formatSseFrame,
15
25
  getApprovalRegistry,
16
26
  getRunEventCache,
27
+ loggingSchema,
17
28
  makeThreadStartRun,
18
29
  mintRunId,
19
30
  mountAgent,
20
- parseAgentRequestBody
21
- } from "./chunk-KTKTHIUF.js";
31
+ observabilitySchema,
32
+ parseAgentRequestBody,
33
+ rateLimitSchema,
34
+ readAgentPolicy,
35
+ securitySchema,
36
+ storageSchema,
37
+ uploadSchema
38
+ } from "./chunk-KOS567NB.js";
39
+ import {
40
+ loadEnv
41
+ } from "./chunk-4X6H2BXP.js";
22
42
  import {
23
- loadEnv,
24
43
  resolveTransformer
25
- } from "./chunk-XR74JD4M.js";
44
+ } from "./chunk-OGLS76RN.js";
26
45
  import {
27
46
  BATCH_PATH,
28
- TRACE_HEADER,
29
47
  createCorsHandler,
48
+ createServerContext,
49
+ createWebRequestSource,
30
50
  executeAction,
31
51
  executeRoute,
32
- extractTraceId,
33
52
  handleBatchRequest,
34
53
  incomingMessageToHandlerRequest,
35
- incomingMessageToWebRequest,
36
- sendError
37
- } from "./chunk-XALU5LCU.js";
54
+ sendError,
55
+ writeWebResponseToServerResponse
56
+ } from "./chunk-JKF25N73.js";
38
57
  import {
39
58
  findSuggestion
40
59
  } from "./chunk-NTDN54XO.js";
41
60
  import {
61
+ TRACE_HEADER,
62
+ extractTraceId,
42
63
  logRequest
43
- } from "./chunk-KD5G3YXI.js";
64
+ } from "./chunk-DOI4G4X3.js";
44
65
  import {
45
66
  createPluginRunnerFromConfig
46
67
  } from "./chunk-VSLTKX5L.js";
@@ -49,24 +70,26 @@ import {
49
70
  } from "./chunk-TNI4MARH.js";
50
71
  import {
51
72
  createViteLoader
52
- } from "./chunk-7LVM22VG.js";
73
+ } from "./chunk-OQCRCXCP.js";
53
74
  import {
54
75
  matchRoute,
55
- scanAgents,
56
76
  scanServerActions,
57
77
  scanServerRoutes,
58
78
  scanWebSocketRoutes
59
- } from "./chunk-YGAXV5HR.js";
79
+ } from "./chunk-6J4JWHDJ.js";
80
+ import {
81
+ scanAgents
82
+ } from "./chunk-L4VFNFDL.js";
60
83
  import {
61
84
  CSP_REPORT_PATH,
62
85
  CsrfReadinessStore,
63
86
  applySecurityHeaders,
64
87
  handleCspReport,
65
88
  handleCsrfReadiness
66
- } from "./chunk-MTEWLGVY.js";
89
+ } from "./chunk-BPYMC7SU.js";
67
90
  import {
68
91
  validateCsrfRequest
69
- } from "./chunk-OLGPYOLO.js";
92
+ } from "./chunk-P6OS7652.js";
70
93
  import {
71
94
  extractAppResources,
72
95
  handleMcpJsonRpc,
@@ -74,17 +97,20 @@ import {
74
97
  } from "./chunk-YOIVCCZT.js";
75
98
  import {
76
99
  resolveProvider
77
- } from "./chunk-AXKUA57G.js";
100
+ } from "./chunk-3PBAN2YE.js";
78
101
  import {
79
102
  generateNonce
80
- } from "./chunk-JA2ZAT5Q.js";
103
+ } from "./chunk-Z4PJMZLM.js";
81
104
  import {
82
105
  importUserModule
83
106
  } from "./chunk-52PDWL5S.js";
107
+ import {
108
+ subjectFromContext
109
+ } from "./chunk-YN4W7LCX.js";
84
110
 
85
111
  // src/vite-plugin/index.ts
86
- import { existsSync as existsSync9 } from "fs";
87
- import { resolve as resolve9, dirname as dirname4 } from "path";
112
+ import { existsSync as existsSync8 } from "fs";
113
+ import { resolve as resolve10, dirname as dirname4 } from "path";
88
114
  import { fileURLToPath } from "url";
89
115
 
90
116
  // src/vite-plugin/config-hook.ts
@@ -129,42 +155,56 @@ function runConfigHook(ctx) {
129
155
  },
130
156
  resolve: {
131
157
  alias: [
132
- // Order matters: most-specific first so `theokit/X` doesn't
133
- // get matched by the bare `theokit` alias.
134
- { find: "theokit/server", replacement: resolve(ctx.theoSrcDir, `server/index${ext}`) },
135
- { find: "theokit/client", replacement: resolve(ctx.theoSrcDir, `client/index${ext}`) },
158
+ // Order still matters — first match wins — but the entries below are
159
+ // EXACT (#377). A Vite alias whose `find` is a string matches by prefix,
160
+ // and every replacement here points at a FILE, so the old string form
161
+ // rewrote `theokit/client/core` into `…/client/index.ts/core` and the
162
+ // build died with ENOTDIR. It did that for every subpath nobody had
163
+ // listed, which made the failure open-ended rather than a typo.
164
+ { find: /^theokit\/server$/u, replacement: resolve(ctx.theoSrcDir, `server/index${ext}`) },
165
+ { find: /^theokit\/client$/u, replacement: resolve(ctx.theoSrcDir, `client/index${ext}`) },
136
166
  {
137
167
  // T2.1 (M5 lonely folders) moved the source from
138
168
  // `react-query/index.ts` into `client/react-query.ts` (sibling of
139
169
  // `client/index.ts`). The package.json export `./react-query`
140
170
  // still points at the build artifact `./dist/react-query/index.{js,d.ts}`,
141
171
  // but the dev-time source alias must follow the new location.
142
- find: "theokit/react-query",
172
+ find: /^theokit\/react-query$/u,
143
173
  replacement: resolve(ctx.theoSrcDir, `client/react-query${ext}`)
144
174
  },
145
175
  {
146
- find: "theokit/vite-plugin",
176
+ find: /^theokit\/vite-plugin$/u,
147
177
  replacement: resolve(ctx.theoSrcDir, `vite-plugin/index${ext}`)
148
178
  },
149
179
  {
150
- find: "theokit/adapters/web-shim",
180
+ find: /^theokit\/adapters\/web-shim$/u,
151
181
  replacement: resolve(ctx.theoSrcDir, `adapters/web-shim${ext}`)
152
182
  },
153
183
  {
154
- find: "theokit/adapters/ws-shim",
184
+ find: /^theokit\/adapters\/ws-shim$/u,
155
185
  replacement: resolve(ctx.theoSrcDir, `adapters/ws-shim${ext}`)
156
186
  },
157
187
  // T1.2 — devtools entry (DEV only; tree-shaken in build).
158
188
  // Source layout: src/devtools/dom/entry.tsx (has /dom/ segment)
159
189
  // Dist layout: dist/devtools/entry.js (tsup flattens /dom/)
160
190
  {
161
- find: "theokit/devtools/entry",
191
+ find: /^theokit\/devtools\/entry$/u,
162
192
  replacement: resolve(
163
193
  ctx.theoSrcDir,
164
194
  ext === ".ts" ? "devtools/dom/entry.tsx" : "devtools/entry.js"
165
195
  )
166
196
  },
167
- { find: "theokit", replacement: resolve(ctx.theoSrcDir, `index${ext}`) }
197
+ // Everything else under the package, by one rule rather than a list that
198
+ // has to grow with the exports map. The source layout mirrors the
199
+ // subpath, so `theokit/cache` is `<src>/cache` and Vite's own extension
200
+ // resolution finds the file. The two entries above that do NOT mirror it
201
+ // — react-query moved to a sibling, devtools' source carries a `/dom/`
202
+ // segment the dist flattens — are matched before this and keep their
203
+ // mapping.
204
+ { find: /^theokit\/(.+)$/u, replacement: resolve(ctx.theoSrcDir, "$1") },
205
+ // Exact, so a package merely NAMED like ours — `theokit-anything` — is
206
+ // left alone. The prefix form ate those too.
207
+ { find: /^theokit$/u, replacement: resolve(ctx.theoSrcDir, `index${ext}`) }
168
208
  ]
169
209
  }
170
210
  };
@@ -196,177 +236,13 @@ ${issueLines}
196
236
  };
197
237
 
198
238
  // src/config/schema.ts
199
- import { z as z8 } from "zod";
239
+ import { z } from "zod";
200
240
 
201
241
  // src/core/contracts/theo-ui-theme.ts
202
242
  var THEME_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
203
243
 
204
- // src/config/schemas/rate-limit.ts
205
- import { z } from "zod";
206
- var baseRateLimitSchema = z.object({
207
- windowMs: z.number().min(1),
208
- max: z.number().int().min(1)
209
- });
210
- var rateLimitSchema = z.union([
211
- baseRateLimitSchema,
212
- z.object({
213
- default: baseRateLimitSchema.optional(),
214
- routes: z.record(z.string(), baseRateLimitSchema).optional(),
215
- keyBy: z.union([
216
- z.enum(["ip", "session", "user"]),
217
- z.function({ input: z.tuple([z.unknown()]), output: z.string() })
218
- ]).optional(),
219
- cookieName: z.string().min(1).optional(),
220
- /**
221
- * How many reverse proxies sit in front of the app, for `keyBy: 'ip'`. `false` (default)
222
- * trusts none; `true` means one; a number names a longer chain.
223
- *
224
- * Required for correct limiting behind Caddy/nginx/a load balancer — without it every visitor
225
- * keys on the proxy address and shares a single bucket. Off by default because
226
- * `x-forwarded-for` is client-writable.
227
- */
228
- trustProxy: z.union([z.boolean(), z.number().int().min(0)]).optional()
229
- })
230
- ]);
231
-
232
- // src/config/schemas/upload.ts
233
- import { z as z2 } from "zod";
234
- var uploadSchema = z2.object({
235
- maxFileSize: z2.number().min(1).default(10 * 1024 * 1024),
236
- // 10MB
237
- maxFiles: z2.number().int().min(1).default(10),
238
- maxFieldSize: z2.number().min(1).default(1 * 1024 * 1024)
239
- // 1MB
240
- });
241
-
242
- // src/config/schemas/logging.ts
243
- import { z as z3 } from "zod";
244
- var loggingSchema = z3.object({
245
- level: z3.enum(["debug", "info", "warn", "error", "silent"]).default("info")
246
- });
247
-
248
- // src/config/schemas/cache.ts
249
- import { z as z4 } from "zod";
250
- var routeRuleSchema = z4.object({
251
- maxAge: z4.number().nonnegative().optional(),
252
- swr: z4.number().nonnegative().optional(),
253
- tags: z4.array(z4.string()).optional()
254
- });
255
- var cacheSchema = z4.object({
256
- enabled: z4.boolean().default(true),
257
- /** 'memory' uses InMemoryCacheAdapter; otherwise pass a custom adapter instance. */
258
- storage: z4.union([z4.literal("memory"), z4.custom()]).default("memory"),
259
- maxEntries: z4.number().int().positive().default(1e3),
260
- defaults: z4.object({
261
- maxAge: z4.number().nonnegative().default(1),
262
- swr: z4.number().nonnegative().optional(),
263
- cacheErrors: z4.boolean().default(false)
264
- }).default({ maxAge: 1, cacheErrors: false }),
265
- keyDerivation: z4.object({
266
- excludeQuery: z4.array(z4.string()).optional(),
267
- sortQuery: z4.boolean().default(true),
268
- lowercaseHost: z4.boolean().default(true)
269
- }).default({ sortQuery: true, lowercaseHost: true }),
270
- routeRules: z4.record(z4.string(), routeRuleSchema).optional()
271
- });
272
-
273
- // src/config/schemas/security.ts
274
- import { z as z6 } from "zod";
275
-
276
- // src/config/schemas/header-safe.ts
277
- import { z as z5 } from "zod";
278
- var headerSafeString = z5.string().refine((s) => !/[\r\n]/.test(s), { message: "Header value must not contain CR/LF" });
279
-
280
- // src/config/schemas/security.ts
281
- var securityHeadersSchema = z6.object({
282
- csp: z6.union([headerSafeString, z6.literal(false)]).optional(),
283
- // T6.1 — default flipped from 'report-only' to 'enforce' for 0.3.0.
284
- // Users who want the old behaviour set `cspMode: 'report-only'`
285
- // explicitly.
286
- cspMode: z6.enum(["enforce", "report-only", "off"]).default("enforce"),
287
- hsts: z6.union([headerSafeString, z6.literal(false)]).optional(),
288
- frameOptions: z6.enum(["DENY", "SAMEORIGIN"]).default("DENY"),
289
- contentTypeOptions: z6.literal("nosniff").default("nosniff"),
290
- referrerPolicy: headerSafeString.default("strict-origin-when-cross-origin"),
291
- /**
292
- * T1.1 — Permissions-Policy directive string. EC-3-refined: rejects CR/LF.
293
- * Pass `false` to suppress the header.
294
- */
295
- permissionsPolicy: z6.union([headerSafeString, z6.literal(false)]).optional()
296
- });
297
- var disallowedConfigSchema = z6.object({
298
- routes: z6.array(z6.union([z6.string(), z6.instanceof(RegExp)])),
299
- behavior: z6.enum(["warn", "raise"]).default("raise")
300
- });
301
- var corsSchema = z6.object({
302
- origins: z6.union([
303
- z6.literal("*"),
304
- headerSafeString,
305
- z6.instanceof(RegExp),
306
- z6.array(z6.union([headerSafeString, z6.instanceof(RegExp)])),
307
- z6.function({ input: z6.tuple([z6.string()]), output: z6.boolean() })
308
- ]),
309
- methods: z6.array(z6.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"])).optional(),
310
- allowedHeaders: z6.array(headerSafeString).optional(),
311
- exposedHeaders: z6.array(headerSafeString).optional(),
312
- credentials: z6.boolean().default(false),
313
- maxAge: z6.number().int().min(0).max(86400).default(600)
314
- }).refine((c) => !(c.origins === "*" && c.credentials), {
315
- message: 'CORS spec forbids origins:"*" with credentials:true \u2014 browsers ignore the wildcard'
316
- });
317
- var securitySchema = z6.object({
318
- // T6.1 — default flipped from 'warn' to 'strict' for 0.3.0. Apps that
319
- // grep their warn-mode logs from 0.2.x already know which endpoints
320
- // break; opt back into 'warn' globally OR use disallowedRoutes for
321
- // surgical migration.
322
- csrf: z6.enum(["off", "warn", "strict"]).default("strict"),
323
- headers: securityHeadersSchema.optional(),
324
- /** T5.1 — per-route escalation (Rails disallowed_warnings pattern). */
325
- disallowed: disallowedConfigSchema.optional(),
326
- /** T1.2 — Cross-Origin Resource Sharing. Single global config; runs first in pipeline. */
327
- cors: corsSchema.optional()
328
- });
329
-
330
- // src/config/schemas/storage.ts
331
- import { z as z7 } from "zod";
332
- var tlsConfigSchema = z7.object({
333
- rejectUnauthorized: z7.boolean().optional(),
334
- caCert: z7.string().optional(),
335
- clientCert: z7.string().optional(),
336
- clientKey: z7.string().optional()
337
- });
338
- var serverConfigSchema = z7.object({
339
- host: z7.string().min(1),
340
- port: z7.number().int().positive().max(65535).optional(),
341
- user: z7.string().min(1),
342
- /** Password may be the empty string (some providers permit it). */
343
- password: z7.string(),
344
- tls: tlsConfigSchema.optional()
345
- });
346
- var postgresPoolConfigSchema = z7.object({
347
- min: z7.number().int().nonnegative().optional(),
348
- max: z7.number().int().positive().optional(),
349
- connectionTimeoutMillis: z7.number().int().positive().optional(),
350
- idleTimeoutMillis: z7.number().int().nonnegative().optional()
351
- });
352
- var postgresDatabaseConfigSchema = z7.object({
353
- /** References a key in `storage.servers`. Resolved at `usePostgres()` call time. */
354
- server: z7.string().min(1),
355
- database: z7.string().min(1),
356
- pool: postgresPoolConfigSchema.optional()
357
- });
358
- var redisServerConfigSchema = serverConfigSchema.extend({
359
- db: z7.number().int().nonnegative().optional(),
360
- maxRetriesPerRequest: z7.number().int().nonnegative().optional()
361
- });
362
- var storageSchema = z7.object({
363
- servers: z7.record(z7.string(), serverConfigSchema).optional(),
364
- databases: z7.record(z7.string(), postgresDatabaseConfigSchema).optional(),
365
- redis: z7.record(z7.string(), redisServerConfigSchema).optional()
366
- });
367
-
368
244
  // src/config/schema.ts
369
- var theoConfigSchema = z8.object({
245
+ var theoConfigSchema = z.object({
370
246
  /**
371
247
  * Plan v1.2 T2.1 — project identifier propagated into
372
248
  * `.theokit/services.json` v2 `project` field. DNS-1123 compatible (drives
@@ -374,27 +250,27 @@ var theoConfigSchema = z8.object({
374
250
  * emits services.json v1 with the legacy `services-bundle` fallback
375
251
  * (ADR D10) and logs a deprecation warning.
376
252
  */
377
- name: z8.string().max(63).refine(
253
+ name: z.string().max(63).refine(
378
254
  // DNS-1123 equivalent expressed as explicit single-char anchors so
379
255
  // security/detect-unsafe-regex stays clean (no backtracking).
380
256
  (value) => value.length > 0 && /^[a-z0-9-]+$/u.test(value) && !value.startsWith("-") && !value.endsWith("-"),
381
257
  "name must match DNS-1123 (lowercase alphanumeric+hyphens, 1-63 chars, no leading/trailing hyphen)"
382
258
  ).optional(),
383
- appDir: z8.string().default("app"),
384
- serverDir: z8.string().default("server"),
259
+ appDir: z.string().default("app"),
260
+ serverDir: z.string().default("server"),
385
261
  /**
386
262
  * Directory (relative to the project root) holding `agents/<name>.ts` definitions, scanned by
387
263
  * dev/build/terminal/mcp. Defaults to `"agents"` — apps that keep the canonical layout are
388
264
  * unaffected. Set to e.g. `"core/agents"` to organize agents under a domain root (#95 follow-up).
389
265
  */
390
- agentsDir: z8.string().default("agents"),
266
+ agentsDir: z.string().default("agents"),
391
267
  /**
392
268
  * T2.2 / EC-4 — Build output directory. Must be a relative path inside
393
269
  * the project root. Refused absolute or parent-relative paths to prevent
394
270
  * `cleanOutDir` from wiping arbitrary locations (defense-in-depth on
395
271
  * top of cleanOutDir's runtime EC-3 guard).
396
272
  */
397
- distDir: z8.string().default(".theokit").refine(
273
+ distDir: z.string().default(".theokit").refine(
398
274
  (d) => !/^([A-Za-z]:)?[/\\]/.test(d) && !d.startsWith(".."),
399
275
  'distDir must be a relative path inside the project root (e.g., ".theokit")'
400
276
  ),
@@ -413,73 +289,79 @@ var theoConfigSchema = z8.object({
413
289
  * * `idleTimeoutMs` — auto-evict idle agents (default 30 min). 0 disables
414
290
  * idle eviction (LRU only).
415
291
  */
416
- agents: z8.object({
417
- maxRegistries: z8.number().int().positive().default(100),
418
- registry: z8.object({
292
+ agents: z.object({
293
+ maxRegistries: z.number().int().positive().default(100),
294
+ registry: z.object({
419
295
  /** LRU cap — MUST be ≥ max-concurrent-active-conversations. */
420
- maxAgents: z8.number().int().positive().max(1e4).default(100),
296
+ maxAgents: z.number().int().positive().max(1e4).default(100),
421
297
  /** Idle eviction window in ms. 0 disables idle eviction (LRU only). */
422
- idleTimeoutMs: z8.number().int().nonnegative().default(30 * 6e4)
298
+ idleTimeoutMs: z.number().int().nonnegative().default(30 * 6e4)
423
299
  }).optional()
424
300
  }).optional(),
425
- port: z8.number().int().min(1).max(65535).default(3e3),
301
+ port: z.number().int().min(1).max(65535).default(3e3),
426
302
  /** Listen on all addresses (0.0.0.0) for LAN/mobile testing. */
427
- host: z8.union([z8.string(), z8.boolean()]).default("localhost"),
303
+ host: z.union([z.string(), z.boolean()]).default("localhost"),
428
304
  /** Automatically open browser on `theokit dev`. */
429
- open: z8.union([z8.boolean(), z8.string()]).default(false),
305
+ open: z.union([z.boolean(), z.string()]).default(false),
430
306
  /** Exit if port is already in use instead of trying next available. */
431
- strictPort: z8.boolean().default(false),
307
+ strictPort: z.boolean().default(false),
432
308
  /** Forward browser console/errors to terminal — useful for AI agent dev. */
433
- forwardConsole: z8.union([
434
- z8.boolean(),
435
- z8.object({
436
- unhandledErrors: z8.boolean().optional(),
437
- logLevels: z8.array(z8.enum(["error", "warn", "info", "log", "debug"])).optional()
309
+ forwardConsole: z.union([
310
+ z.boolean(),
311
+ z.object({
312
+ unhandledErrors: z.boolean().optional(),
313
+ logLevels: z.array(z.enum(["error", "warn", "info", "log", "debug"])).optional()
438
314
  })
439
315
  ]).default(false),
440
316
  /** Pre-transform files on startup for faster first page load. */
441
- warmup: z8.object({
442
- clientFiles: z8.array(z8.string()).optional(),
443
- ssrFiles: z8.array(z8.string()).optional()
317
+ warmup: z.object({
318
+ clientFiles: z.array(z.string()).optional(),
319
+ ssrFiles: z.array(z.string()).optional()
444
320
  }).optional(),
445
- ssr: z8.boolean().default(false),
321
+ ssr: z.boolean().default(false),
446
322
  /** When true (and ssr === true), use renderToPipeableStream with progressive
447
323
  * shell flush instead of single-shot renderToString. Opt-in for streaming
448
324
  * SSR; default false preserves the current behavior. */
449
- ssrStreaming: z8.boolean().default(false),
325
+ ssrStreaming: z.boolean().default(false),
450
326
  rateLimit: rateLimitSchema.optional(),
451
327
  upload: uploadSchema.optional(),
452
328
  logging: loggingSchema.optional(),
453
329
  security: securitySchema.optional(),
454
- serialization: z8.enum(["json", "superjson"]).default("json"),
330
+ serialization: z.enum(["json", "superjson"]).default("json"),
455
331
  // Plugins are validated structurally at runtime by createPluginRunnerFromConfig.
456
332
  // Zod only checks the shape minimally (must be array). Type-level safety is
457
333
  // provided through defineConfig at the user surface.
458
- plugins: z8.array(z8.unknown()).optional(),
334
+ //
335
+ // #425 — an entry MAY also be a module SPECIFIER (a string), resolved to that module's default
336
+ // export by `config/resolve-plugin-specifiers.ts`. A constructed plugin closes over state and
337
+ // therefore has no literal, so it is the string form — and only the string form — that a
338
+ // generated deploy entry can carry. Both shapes are accepted here for the same reason they are
339
+ // accepted at runtime: one declaration has to serve the local server and the deployed one.
340
+ plugins: z.array(z.unknown()).optional(),
459
341
  /** Enable client-side batching of theoFetch calls and the
460
342
  * /api/__theo_batch__ server endpoint. */
461
- batching: z8.union([z8.boolean(), z8.object({ max: z8.number().int().positive().optional() })]).optional(),
343
+ batching: z.union([z.boolean(), z.object({ max: z.number().int().positive().optional() })]).optional(),
462
344
  /** T4.1 — Audit log. When `logger` is provided, framework events
463
345
  * (csrf.warn, rate-limit.exceeded, session.rotated, csp.violation) are
464
346
  * emitted to it. Default: noop. */
465
- audit: z8.object({
466
- logger: z8.unknown().optional()
347
+ audit: z.object({
348
+ logger: z.unknown().optional()
467
349
  }).optional(),
468
350
  /** TheoUI auto-wire (T2.1). `false` = opt-out; object = explicit theme/fonts;
469
351
  * undefined = enabled when @theokit/ui is detected in node_modules. */
470
- ui: z8.union([
471
- z8.literal(false),
472
- z8.object({
352
+ ui: z.union([
353
+ z.literal(false),
354
+ z.object({
473
355
  // Any theme @theokit/ui knows — built-in or from `defineTheme()`. This was a closed
474
356
  // enum of `violet-forge | noir | paper`, two of which never existed in @theokit/ui, so
475
357
  // the only accepted value was the default and every real theme was rejected. The pattern
476
358
  // mirrors what @theokit/ui's ThemeProvider enforces, and it is load-bearing: the value is
477
359
  // interpolated into the generated entry and into a CSS selector.
478
- theme: z8.string().regex(
360
+ theme: z.string().regex(
479
361
  THEME_NAME_PATTERN,
480
362
  "must start with a letter and contain only lowercase letters, digits and hyphens"
481
363
  ).optional(),
482
- fonts: z8.enum(["bundled", "cdn"]).optional()
364
+ fonts: z.enum(["bundled", "cdn"]).optional()
483
365
  })
484
366
  ]).optional(),
485
367
  /**
@@ -488,6 +370,12 @@ var theoConfigSchema = z8.object({
488
370
  * Pass `cache: {}` to opt in with defaults.
489
371
  */
490
372
  cache: cacheSchema.optional(),
373
+ /**
374
+ * Observability (#353). Default `undefined` keeps telemetry off. Present and
375
+ * not `enabled: false` opts in; `provider` overrides the environment-derived
376
+ * adapter, which is the priority `adapter-registry.ts` has always documented.
377
+ */
378
+ observability: observabilitySchema.optional(),
491
379
  /**
492
380
  * Devtools overlay (Phase 0.4.0+ —
493
381
  *
@@ -498,11 +386,11 @@ var theoConfigSchema = z8.object({
498
386
  * Tree-shaken to noop in prod via the dual-export pattern in
499
387
  * `packages/theo/src/devtools/index.ts` (EC-17 positive prod check).
500
388
  */
501
- devtools: z8.union([
502
- z8.literal(false),
503
- z8.object({
504
- position: z8.enum(["top-left", "top-right", "bottom-left", "bottom-right"]).optional(),
505
- theme: z8.enum(["light", "dark", "system"]).optional()
389
+ devtools: z.union([
390
+ z.literal(false),
391
+ z.object({
392
+ position: z.enum(["top-left", "top-right", "bottom-left", "bottom-right"]).optional(),
393
+ theme: z.enum(["light", "dark", "system"]).optional()
506
394
  })
507
395
  ]).optional(),
508
396
  /**
@@ -511,7 +399,7 @@ var theoConfigSchema = z8.object({
511
399
  * (EC-201 / ADR D2). If `config.adapters` includes a target NOT
512
400
  * matching `--target`, `theokit build` emits a cross-reference note.
513
401
  */
514
- adapters: z8.array(z8.string()).optional(),
402
+ adapters: z.array(z.string()).optional(),
515
403
  /**
516
404
  * Extra package names to pre-bundle via Vite's `optimizeDeps.include`.
517
405
  *
@@ -526,14 +414,14 @@ var theoConfigSchema = z8.object({
526
414
  * Example:
527
415
  * viteOptimizeDeps: ['mermaid']
528
416
  */
529
- viteOptimizeDeps: z8.array(z8.string()).optional(),
417
+ viteOptimizeDeps: z.array(z.string()).optional(),
530
418
  /**
531
419
  * Jobs backend (ADR D3 + T2.1). When configured, every request gets
532
420
  * `ctx.queue.enqueue` auto-wired via the outbox lifecycle. Pass a
533
421
  * `JobBackend` instance (InMemoryJobBackend, PostgresJobBackend, etc.).
534
422
  */
535
- jobs: z8.object({
536
- backend: z8.custom((v) => typeof v === "object" && v !== null)
423
+ jobs: z.object({
424
+ backend: z.custom((v) => typeof v === "object" && v !== null)
537
425
  }).optional(),
538
426
  /**
539
427
  * StorageManager configuration (T1.1 / ADR-0007).
@@ -568,17 +456,17 @@ var theoConfigSchema = z8.object({
568
456
  * The env var `THEOKIT_OPENAPI_SERVERS` (CSV of URLs) overrides
569
457
  * `servers[].url` at emit time without rebuilding the config.
570
458
  */
571
- openapi: z8.object({
572
- servers: z8.array(
573
- z8.object({
574
- url: z8.url(),
575
- description: z8.string().optional()
459
+ openapi: z.object({
460
+ servers: z.array(
461
+ z.object({
462
+ url: z.url(),
463
+ description: z.string().optional()
576
464
  })
577
465
  ).default([{ url: "http://localhost:3000", description: "Local development" }]),
578
- specVersion: z8.enum(["3.1.0", "3.0.3"]).default("3.1.0"),
579
- title: z8.string().default("TheoKit App"),
580
- version: z8.string().default("0.0.0"),
581
- outDir: z8.string().default(".theokit")
466
+ specVersion: z.enum(["3.1.0", "3.0.3"]).default("3.1.0"),
467
+ title: z.string().default("TheoKit App"),
468
+ version: z.string().default("0.0.0"),
469
+ outDir: z.string().default(".theokit")
582
470
  }).optional(),
583
471
  /**
584
472
  * G5 T1.3 — error envelope transformer hook (blueprint ADR D3).
@@ -595,7 +483,7 @@ var theoConfigSchema = z8.object({
595
483
  * with a function-typed runtime guard preserves the call-site type
596
484
  * without trading off Zod runtime validation.
597
485
  */
598
- formatError: z8.custom((val) => typeof val === "function", {
486
+ formatError: z.custom((val) => typeof val === "function", {
599
487
  message: "formatError must be a function"
600
488
  }).optional()
601
489
  }).refine((cfg) => !Object.values(cfg.services).some((s) => s.port === cfg.port), {
@@ -674,6 +562,46 @@ async function loadConfig(dir) {
674
562
  return result.data;
675
563
  }
676
564
 
565
+ // src/config/resolve-plugin-specifiers.ts
566
+ import { isAbsolute, resolve as resolve3 } from "path";
567
+ import { pathToFileURL } from "url";
568
+ var UnresolvablePluginSpecifierError = class extends Error {
569
+ constructor(index, specifier, reason) {
570
+ super(`plugins[${index}] (${specifier}) could not be loaded: ${reason}`);
571
+ this.name = "UnresolvablePluginSpecifierError";
572
+ }
573
+ };
574
+ async function resolvePluginSpecifiers(plugins, cwd) {
575
+ const resolved = [];
576
+ for (const [index, entry] of plugins.entries()) {
577
+ resolved.push(typeof entry === "string" ? await importPlugin(entry, index, cwd) : entry);
578
+ }
579
+ return resolved;
580
+ }
581
+ async function importPlugin(specifier, index, cwd) {
582
+ const target = isAbsolute(specifier) ? specifier : resolve3(cwd, specifier);
583
+ let mod;
584
+ try {
585
+ mod = await import(
586
+ /* @vite-ignore */
587
+ pathToFileURL(target).href
588
+ );
589
+ } catch (err) {
590
+ throw new UnresolvablePluginSpecifierError(index, specifier, messageOf(err));
591
+ }
592
+ if (mod.default === void 0) {
593
+ throw new UnresolvablePluginSpecifierError(
594
+ index,
595
+ specifier,
596
+ "the module has no default export; a plugin module must `export default` its plugin"
597
+ );
598
+ }
599
+ return mod.default;
600
+ }
601
+ function messageOf(err) {
602
+ return err instanceof Error ? err.message : String(err);
603
+ }
604
+
677
605
  // src/vite-plugin/theoui-detect.ts
678
606
  import { existsSync as existsSync3, readFileSync } from "fs";
679
607
  import { dirname, join } from "path";
@@ -773,7 +701,14 @@ var DEFAULT_RESOLVED = {
773
701
  async function resolvePluginConfig(projectRoot) {
774
702
  try {
775
703
  const userConfig = await loadConfig(projectRoot);
776
- const pluginRunner = await createPluginRunnerFromConfig(userConfig.plugins);
704
+ const observabilityPlugin = createObservabilityPluginFromConfig(
705
+ userConfig.observability,
706
+ process.env
707
+ );
708
+ const declaredPlugins = await resolvePluginSpecifiers(userConfig.plugins ?? [], projectRoot);
709
+ const pluginRunner = await createPluginRunnerFromConfig(
710
+ observabilityPlugin === void 0 ? declaredPlugins : [observabilityPlugin, ...declaredPlugins]
711
+ );
777
712
  const transformer = resolveTransformer(userConfig.serialization);
778
713
  let resolvedBatching;
779
714
  if (userConfig.batching === true) {
@@ -807,7 +742,7 @@ async function resolvePluginConfig(projectRoot) {
807
742
  }
808
743
 
809
744
  // src/vite-plugin/configure-server-hook.ts
810
- import { resolve as resolve6, basename } from "path";
745
+ import { resolve as resolve8, basename } from "path";
811
746
 
812
747
  // src/devtools/server-side/route-manifest.ts
813
748
  function buildPath(parents, segment) {
@@ -845,7 +780,7 @@ function broadcastRouteManifest(tree) {
845
780
 
846
781
  // src/router/scan.ts
847
782
  import { readdirSync, statSync, existsSync as existsSync4 } from "fs";
848
- import { join as join2, resolve as resolve3 } from "path";
783
+ import { join as join2, resolve as resolve4 } from "path";
849
784
 
850
785
  // src/router/types.ts
851
786
  var ROUTE_FILE_NAMES = ["page", "layout", "error", "loading", "not-found"];
@@ -886,7 +821,7 @@ function attachRouteFiles(node, dir) {
886
821
  for (const ext of ROUTE_FILE_EXTENSIONS) {
887
822
  const filename = `${name}${ext}`;
888
823
  if (existsSync4(join2(dir, filename))) {
889
- setRouteFile(node, key, resolve3(dir, filename));
824
+ setRouteFile(node, key, resolve4(dir, filename));
890
825
  break;
891
826
  }
892
827
  }
@@ -935,7 +870,13 @@ function scanChild(parentDir, dirName, routePath) {
935
870
  function scanDir(dir, segment, routePath) {
936
871
  const node = { segment, path: routePath, children: [] };
937
872
  attachRouteFiles(node, dir);
938
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
873
+ const entries = readdirSync(dir, { withFileTypes: true });
874
+ entries.sort((a, b) => {
875
+ if (a.name < b.name) return -1;
876
+ if (a.name > b.name) return 1;
877
+ return 0;
878
+ });
879
+ for (const entry of entries) {
939
880
  if (!entry.isDirectory()) continue;
940
881
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
941
882
  const child = scanChild(dir, entry.name, routePath);
@@ -1089,6 +1030,11 @@ function handleAgentCard(mod, name, route, baseUrl) {
1089
1030
 
1090
1031
  // src/server/agent/approve-agent.ts
1091
1032
  var APPROVE_SEGMENT = "/approve/";
1033
+ var APPROVE_PATH = /^\/api\/agents\/([^/]+)\/approve\/([^/]+)$/;
1034
+ function parseApprovalAgentName(urlPath) {
1035
+ const match = APPROVE_PATH.exec(urlPath);
1036
+ return match ? decodeURIComponent(match[1]) : null;
1037
+ }
1092
1038
  function parseApprovalId(urlPath) {
1093
1039
  const at = urlPath.indexOf(APPROVE_SEGMENT);
1094
1040
  if (at === -1) return null;
@@ -1121,7 +1067,17 @@ function parseApprovalBody(body) {
1121
1067
  }
1122
1068
  return decision;
1123
1069
  }
1124
- async function handleAgentApproval(request, urlPath, registry, csrfMode = "strict") {
1070
+ async function refuseIfNotOwner(registry, approvalId, resolveSubject, params) {
1071
+ const owner = registry.ownerOf(approvalId);
1072
+ if (owner === void 0) return void 0;
1073
+ const subject = resolveSubject === void 0 ? null : await resolveSubject();
1074
+ if (subject?.id === owner) return void 0;
1075
+ return agentAccessDenied(
1076
+ { allowed: false, reason: "the approval belongs to another subject" },
1077
+ params
1078
+ );
1079
+ }
1080
+ async function handleAgentApproval(request, urlPath, registry, csrfMode = "strict", access = {}) {
1125
1081
  if (csrfMode !== "off") {
1126
1082
  const csrf = validateCsrfRequest(request);
1127
1083
  if (!csrf.valid && csrfMode === "strict") {
@@ -1132,6 +1088,15 @@ async function handleAgentApproval(request, urlPath, registry, csrfMode = "stric
1132
1088
  if (approvalId === null) {
1133
1089
  return jsonError(400, "BAD_REQUEST", "Approval path must be /api/agents/<name>/approve/<id>.");
1134
1090
  }
1091
+ const params = {
1092
+ agent: parseApprovalAgentName(urlPath) ?? "unknown",
1093
+ endpoint: "approve",
1094
+ approvalId
1095
+ };
1096
+ const decision = await admitAgentRequest(access.policy, access.resolveSubject, params);
1097
+ if (!decision.allowed) return agentAccessDenied(decision, params);
1098
+ const notOwner = await refuseIfNotOwner(registry, approvalId, access.resolveSubject, params);
1099
+ if (notOwner !== void 0) return notOwner;
1135
1100
  let body = null;
1136
1101
  try {
1137
1102
  body = await request.json();
@@ -1145,25 +1110,13 @@ async function handleAgentApproval(request, urlPath, registry, csrfMode = "stric
1145
1110
  if (!resolved) {
1146
1111
  return jsonError(404, "NOT_PENDING", `No pending approval for id '${approvalId}'.`);
1147
1112
  }
1113
+ closePauseSpan(approvalId, { resumeObserved: true });
1148
1114
  return new Response(JSON.stringify({ resolved: true }), {
1149
1115
  status: 200,
1150
1116
  headers: { "content-type": "application/json" }
1151
1117
  });
1152
1118
  }
1153
1119
 
1154
- // src/server/agent/list-approvals-handler.ts
1155
- var LIST_PATH = /^\/api\/agents\/([^/]+)\/approvals$/;
1156
- function isListApprovalsPath(urlPath) {
1157
- const match = LIST_PATH.exec(urlPath);
1158
- return match ? decodeURIComponent(match[1]) : null;
1159
- }
1160
- function handleListApprovals(registry) {
1161
- return new Response(JSON.stringify({ approvals: registry.list() }), {
1162
- status: 200,
1163
- headers: { "content-type": "application/json; charset=utf-8" }
1164
- });
1165
- }
1166
-
1167
1120
  // src/server/agent/handle-agent-run-reconnect.ts
1168
1121
  var RUN_STREAM_PATH = /^\/api\/agents\/([^/]+)\/runs\/([^/]+)\/stream$/;
1169
1122
  function isAgentRunStreamPath(urlPath) {
@@ -1328,7 +1281,7 @@ function jsonError2(status, code, message) {
1328
1281
  });
1329
1282
  }
1330
1283
  async function handleThreadMessage(args) {
1331
- const { mod, apiKey, sessionId, request, source, csrfMode = "strict" } = args;
1284
+ const { mod, apiKey, sessionId, request, source, agentName, csrfMode = "strict" } = args;
1332
1285
  if (csrfMode === "strict") {
1333
1286
  const csrf = validateCsrfRequest(request);
1334
1287
  if (!csrf.valid) return jsonError2(403, "CSRF_FAILED", `CSRF check failed: ${csrf.reason}`);
@@ -1346,7 +1299,9 @@ async function handleThreadMessage(args) {
1346
1299
  {
1347
1300
  registry: getThreadRunRegistry(),
1348
1301
  cache: getRunEventCache(),
1349
- startRun: makeThreadStartRun(mod, apiKey, source)
1302
+ // usetheokit/theokit#381 — the request goes with it, so the run's spans join the trace of
1303
+ // the caller that queued it instead of opening one of their own.
1304
+ startRun: makeThreadStartRun(mod, apiKey, source, agentName, request)
1350
1305
  },
1351
1306
  sessionId,
1352
1307
  input.message
@@ -1424,6 +1379,19 @@ function waitThenAttachStream(sessionId, request, registry, cache, idleWaitMs) {
1424
1379
  return new Response(stream, { headers: { ...SSE_BASE_HEADERS } });
1425
1380
  }
1426
1381
 
1382
+ // src/server/agent/list-approvals-handler.ts
1383
+ var LIST_PATH = /^\/api\/agents\/([^/]+)\/approvals$/;
1384
+ function isListApprovalsPath(urlPath) {
1385
+ const match = LIST_PATH.exec(urlPath);
1386
+ return match ? decodeURIComponent(match[1]) : null;
1387
+ }
1388
+ function handleListApprovals(registry) {
1389
+ return new Response(JSON.stringify({ approvals: registry.list() }), {
1390
+ status: 200,
1391
+ headers: { "content-type": "application/json; charset=utf-8" }
1392
+ });
1393
+ }
1394
+
1427
1395
  // src/server/agent/serve-aux-routes.ts
1428
1396
  function jsonError3(status, code, message) {
1429
1397
  return new Response(JSON.stringify({ error: { code, message } }), {
@@ -1431,73 +1399,135 @@ function jsonError3(status, code, message) {
1431
1399
  headers: { "content-type": "application/json; charset=utf-8" }
1432
1400
  });
1433
1401
  }
1434
- async function serveAgentAuxRoute(request, urlPath, deps) {
1435
- const method = request.method.toUpperCase();
1436
- const cardName = isAgentCardPath(urlPath);
1437
- if (cardName !== null) {
1438
- if (method !== "GET") return null;
1439
- const agent = deps.agents.find((a) => a.name === cardName);
1440
- if (!agent) return null;
1441
- const mod = await deps.loadModule(agent.filePath);
1442
- return handleAgentCard(mod, agent.name, agent.agentPath, deps.baseUrl);
1443
- }
1444
- if (isListApprovalsPath(urlPath)) {
1445
- if (method !== "GET") return null;
1446
- return handleListApprovals(getApprovalRegistry());
1447
- }
1448
- const runStream = isAgentRunStreamPath(urlPath);
1449
- if (runStream !== null) {
1450
- if (method !== "GET") return null;
1451
- if (!deps.agents.some((a) => a.name === runStream.name)) return null;
1452
- return handleAgentRunReconnect(runStream.runId, request, getRunEventCache());
1453
- }
1454
- const threadResponse = await serveThreadRoute(request, method, urlPath, deps);
1455
- if (threadResponse !== null) return threadResponse;
1456
- const mcpName = isMcpPath(urlPath);
1457
- if (mcpName !== null) {
1458
- return serveMcpRoute(request, method, mcpName, deps);
1402
+ function routeFor(deps, name, build) {
1403
+ if (name === null) return null;
1404
+ const agent = deps.agents.find((a) => a.name === name);
1405
+ return agent === void 0 ? null : build(agent);
1406
+ }
1407
+ function matchGetAuxRoute(verb, urlPath, deps) {
1408
+ if (verb !== "GET") return null;
1409
+ const card = routeFor(
1410
+ deps,
1411
+ isAgentCardPath(urlPath),
1412
+ (agent) => ({ kind: "card", agent })
1413
+ );
1414
+ if (card !== null) return card;
1415
+ const approvals = routeFor(
1416
+ deps,
1417
+ isListApprovalsPath(urlPath),
1418
+ (agent) => ({ kind: "approvals", agent })
1419
+ );
1420
+ if (approvals !== null) return approvals;
1421
+ const run = isAgentRunStreamPath(urlPath);
1422
+ if (run !== null) {
1423
+ return routeFor(
1424
+ deps,
1425
+ run.name,
1426
+ (agent) => ({ kind: "run-stream", agent, runId: run.runId })
1427
+ );
1459
1428
  }
1460
- return null;
1461
- }
1462
- async function serveThreadRoute(request, method, urlPath, deps) {
1463
1429
  const stream = isThreadStreamPath(urlPath);
1464
- if (stream !== null) {
1465
- if (method !== "GET") return null;
1466
- if (!deps.agents.some((a) => a.name === stream.name)) return null;
1467
- return handleThreadStream(stream.sessionId, request);
1468
- }
1430
+ if (stream === null) return null;
1431
+ return routeFor(
1432
+ deps,
1433
+ stream.name,
1434
+ (agent) => ({ kind: "thread-stream", agent, sessionId: stream.sessionId })
1435
+ );
1436
+ }
1437
+ async function matchPostAuxRoute(verb, urlPath, deps) {
1438
+ if (verb !== "POST") return null;
1469
1439
  const msg = isThreadMessagePath(urlPath);
1470
1440
  if (msg !== null) {
1471
- if (method !== "POST") return null;
1472
- const agent = deps.agents.find((a) => a.name === msg.name);
1473
- if (!agent) return null;
1474
- if (deps.resolveApiKey === void 0) {
1475
- return jsonError3(
1476
- 501,
1477
- "NOT_CONFIGURED",
1478
- "Thread follow-up requires a provider API key (resolveApiKey was not provided to serveAgentAuxRoute)."
1479
- );
1480
- }
1481
- const mod = await deps.loadModule(agent.filePath);
1482
- return handleThreadMessage({
1483
- mod,
1484
- // Passed unresolved: `makeThreadStartRun` calls it once the module is compiled and the
1485
- // model is known (theokit#328).
1486
- apiKey: deps.resolveApiKey,
1487
- sessionId: msg.sessionId,
1488
- request,
1489
- source: `agent "${msg.name}"`,
1490
- csrfMode: deps.csrfMode ?? "strict"
1441
+ return routeFor(
1442
+ deps,
1443
+ msg.name,
1444
+ (agent2) => ({ kind: "thread-message", agent: agent2, sessionId: msg.sessionId })
1445
+ );
1446
+ }
1447
+ const agent = routeFor(deps, isMcpPath(urlPath), (found) => found);
1448
+ if (agent === null) return null;
1449
+ const mod = await deps.loadModule(agent.filePath);
1450
+ return isMcpExposed(mod) ? { kind: "mcp", agent, mod } : null;
1451
+ }
1452
+ async function matchAgentAuxRoute(method, urlPath, deps) {
1453
+ const verb = method.toUpperCase();
1454
+ return matchGetAuxRoute(verb, urlPath, deps) ?? await matchPostAuxRoute(verb, urlPath, deps);
1455
+ }
1456
+ async function admitAux(deps, agent, params, body) {
1457
+ const mod = await deps.loadModule(agent.filePath);
1458
+ const decision = await admitAgentRequest(
1459
+ readAgentPolicy(mod, agent.filePath),
1460
+ deps.resolveSubject,
1461
+ params,
1462
+ body
1463
+ );
1464
+ return decision.allowed ? null : agentAccessDenied(decision, params);
1465
+ }
1466
+ async function serveMatchedAuxRoute(route, request, deps) {
1467
+ if (route.kind === "card") {
1468
+ const mod = await deps.loadModule(route.agent.filePath);
1469
+ return handleAgentCard(mod, route.agent.name, route.agent.agentPath, deps.baseUrl);
1470
+ }
1471
+ if (route.kind === "approvals") {
1472
+ const refusal = await admitAux(deps, route.agent, {
1473
+ agent: route.agent.name,
1474
+ endpoint: "approvals"
1491
1475
  });
1476
+ return refusal ?? handleListApprovals(getApprovalRegistry());
1492
1477
  }
1493
- return null;
1478
+ if (route.kind === "run-stream") {
1479
+ return handleAgentRunReconnect(route.runId, request, getRunEventCache());
1480
+ }
1481
+ if (route.kind === "mcp") return serveMcpRoute(route, request, deps);
1482
+ return serveThreadRoute(route, request, deps);
1494
1483
  }
1495
- async function serveMcpRoute(request, method, mcpName, deps) {
1496
- if (method !== "POST") return null;
1497
- const agent = deps.agents.find((a) => a.name === mcpName);
1498
- if (!agent) return null;
1484
+ async function serveThreadRoute(route, request, deps) {
1485
+ const { agent, sessionId } = route;
1486
+ if (route.kind === "thread-stream") {
1487
+ const refusal2 = await admitAux(deps, agent, {
1488
+ agent: agent.name,
1489
+ endpoint: "thread-stream",
1490
+ sessionId
1491
+ });
1492
+ return refusal2 ?? handleThreadStream(sessionId, request);
1493
+ }
1494
+ const refusal = await admitAux(deps, agent, {
1495
+ agent: agent.name,
1496
+ endpoint: "thread-message",
1497
+ sessionId
1498
+ });
1499
+ if (refusal !== null) return refusal;
1500
+ if (deps.resolveApiKey === void 0) {
1501
+ return jsonError3(
1502
+ 501,
1503
+ "NOT_CONFIGURED",
1504
+ "Thread follow-up requires a provider API key (resolveApiKey was not provided to serveMatchedAuxRoute)."
1505
+ );
1506
+ }
1499
1507
  const mod = await deps.loadModule(agent.filePath);
1500
- if (!isMcpExposed(mod)) return null;
1508
+ return handleThreadMessage({
1509
+ mod,
1510
+ // Passed unresolved: `makeThreadStartRun` calls it once the module is compiled and the
1511
+ // model is known (theokit#328).
1512
+ apiKey: deps.resolveApiKey,
1513
+ sessionId,
1514
+ request,
1515
+ source: `agent "${agent.name}"`,
1516
+ // usetheokit/theokit#406 — the label above reads well in an `AgentDefinitionError` and is not
1517
+ // a name; the spans get the name, so the same agent is one series whichever route started it.
1518
+ agentName: agent.name,
1519
+ csrfMode: deps.csrfMode ?? "strict"
1520
+ });
1521
+ }
1522
+ async function serveMcpRoute(route, request, deps) {
1523
+ const { agent, mod } = route;
1524
+ const mcpParams = { agent: agent.name, endpoint: "mcp" };
1525
+ const mcpDecision = await admitAgentRequest(
1526
+ readAgentPolicy(mod, agent.filePath),
1527
+ deps.resolveSubject,
1528
+ mcpParams
1529
+ );
1530
+ if (!mcpDecision.allowed) return agentAccessDenied(mcpDecision, mcpParams);
1501
1531
  const csrfMode = deps.csrfMode ?? "strict";
1502
1532
  if (csrfMode === "strict") {
1503
1533
  const csrf = validateCsrfRequest(request);
@@ -1514,38 +1544,53 @@ function isMcpExposed(mod) {
1514
1544
  return mod?.mcp === true;
1515
1545
  }
1516
1546
 
1517
- // src/server/http/node-web-adapter.ts
1518
- async function writeWebResponseToServerResponse(response, res) {
1519
- const setCookies = response.headers.getSetCookie();
1520
- if (setCookies.length > 0) {
1521
- res.setHeader("Set-Cookie", setCookies);
1522
- }
1523
- const otherHeaders = {};
1524
- for (const [key, value] of response.headers.entries()) {
1525
- if (key.toLowerCase() === "set-cookie") continue;
1526
- otherHeaders[key] = value;
1527
- }
1528
- res.writeHead(response.status, response.statusText, otherHeaders);
1529
- if (response.body === null) {
1530
- res.end();
1547
+ // src/server/http/plugin-lifecycle.ts
1548
+ function messageOf2(err, fallback) {
1549
+ return err instanceof Error ? err.message : fallback;
1550
+ }
1551
+ async function serveThroughPluginLifecycle(target, serve) {
1552
+ const { res, requestId, pluginRunner, failureMessage } = target;
1553
+ let request;
1554
+ try {
1555
+ request = target.source.toRequest();
1556
+ } catch (err) {
1557
+ sendError(res, "INTERNAL", messageOf2(err, failureMessage), 500, void 0, requestId);
1531
1558
  return;
1532
1559
  }
1533
- const reader = response.body.getReader();
1560
+ const pluginCtx = { request, response: res, ctx: {}, requestId };
1561
+ if (pluginRunner) {
1562
+ pluginRunner.applyDecorations(pluginCtx.ctx);
1563
+ const onRequest = await pluginRunner.runOnRequest(pluginCtx);
1564
+ if (onRequest.shortCircuited) return;
1565
+ }
1534
1566
  try {
1535
- for (; ; ) {
1536
- const { done, value } = await reader.read();
1537
- if (done) break;
1538
- res.write(value);
1539
- }
1540
- res.end();
1541
- } finally {
1542
- reader.releaseLock();
1567
+ await serve(request, pluginCtx);
1568
+ } catch (err) {
1569
+ if (pluginRunner) await pluginRunner.runOnError(pluginCtx, err);
1570
+ sendError(res, "INTERNAL", messageOf2(err, failureMessage), 500, void 0, requestId);
1543
1571
  }
1572
+ if (pluginRunner) await pluginRunner.runOnResponse(pluginCtx);
1573
+ }
1574
+
1575
+ // src/server/http/resolve-agent-subject.ts
1576
+ function createAgentSubjectResolver(sources) {
1577
+ let pending;
1578
+ return () => {
1579
+ pending ??= resolve5(sources);
1580
+ return pending;
1581
+ };
1582
+ }
1583
+ async function resolve5(sources) {
1584
+ const { req, res, loadModule, serverDir, pluginRunner } = sources;
1585
+ const produced = serverDir === void 0 ? {} : await createServerContext(req, res, loadModule, serverDir);
1586
+ const ctx = produced ?? {};
1587
+ pluginRunner?.applyDecorations(ctx);
1588
+ return subjectFromContext(ctx);
1544
1589
  }
1545
1590
 
1546
1591
  // src/vite-plugin/agent-middleware.ts
1547
1592
  var PREFIX2 = "/api/agents/";
1548
- async function serveApprove(req, res, urlPath, csrfMode, log) {
1593
+ async function serveApprove(req, res, urlPath, deps, log) {
1549
1594
  const method = (req.method ?? "POST").toUpperCase();
1550
1595
  if (method !== "POST") {
1551
1596
  sendError(
@@ -1565,24 +1610,36 @@ async function serveApprove(req, res, urlPath, csrfMode, log) {
1565
1610
  });
1566
1611
  return;
1567
1612
  }
1568
- try {
1569
- const response = await handleAgentApproval(
1570
- incomingMessageToWebRequest(req),
1571
- urlPath,
1572
- getApprovalRegistry(),
1573
- csrfMode
1574
- );
1575
- await writeWebResponseToServerResponse(response, res);
1576
- } catch (err) {
1577
- sendError(
1613
+ await serveThroughPluginLifecycle(
1614
+ {
1615
+ source: createWebRequestSource(req),
1578
1616
  res,
1579
- "INTERNAL",
1580
- err instanceof Error ? err.message : "Approve handler failed",
1581
- 500,
1582
- void 0,
1583
- log.requestId
1584
- );
1585
- }
1617
+ requestId: log.requestId,
1618
+ pluginRunner: deps.pluginRunner,
1619
+ failureMessage: "Approve handler failed"
1620
+ },
1621
+ async (request) => {
1622
+ const agent = scanAgents(deps.projectRoot, deps.agentsDir).find(
1623
+ (a) => a.name === parseApprovalAgentName(urlPath)
1624
+ );
1625
+ const resolveSubject = createAgentSubjectResolver({
1626
+ req,
1627
+ res,
1628
+ loadModule: deps.loadModule,
1629
+ serverDir: deps.serverDir,
1630
+ pluginRunner: deps.pluginRunner
1631
+ });
1632
+ const policy = agent === void 0 ? void 0 : readAgentPolicy(await deps.loadModule(agent.filePath), agent.filePath);
1633
+ const response = await handleAgentApproval(
1634
+ request,
1635
+ urlPath,
1636
+ getApprovalRegistry(),
1637
+ deps.csrfMode,
1638
+ { policy, resolveSubject }
1639
+ );
1640
+ await writeWebResponseToServerResponse(response, res);
1641
+ }
1642
+ );
1586
1643
  logRequest({
1587
1644
  method,
1588
1645
  url: req.url ?? "",
@@ -1594,54 +1651,69 @@ async function serveApprove(req, res, urlPath, csrfMode, log) {
1594
1651
  async function serveAux(req, res, next, urlPath, deps) {
1595
1652
  const requestId = randomUUID2();
1596
1653
  const start = Date.now();
1597
- try {
1598
- const request = incomingMessageToWebRequest(req);
1599
- const response = await serveAgentAuxRoute(request, urlPath, {
1600
- agents: scanAgents(deps.projectRoot, deps.agentsDir),
1601
- loadModule: deps.loadModule,
1602
- baseUrl: `http://${req.headers.host ?? "localhost"}`,
1603
- csrfMode: deps.csrfMode,
1604
- // M39 — the thread follow-up route drives the agent; resolve the key on demand.
1605
- // theokit#328 — the thread route drives an agent, so its key follows the model too.
1606
- resolveApiKey: (model) => resolveProvider(model).apiKey
1607
- });
1608
- if (response === null) {
1609
- next();
1610
- return;
1611
- }
1612
- res.setHeader("x-request-id", requestId);
1613
- await writeWebResponseToServerResponse(response, res);
1614
- } catch (err) {
1615
- res.setHeader("x-request-id", requestId);
1616
- sendError(
1654
+ const auxDeps = {
1655
+ agents: scanAgents(deps.projectRoot, deps.agentsDir),
1656
+ loadModule: deps.loadModule,
1657
+ baseUrl: `http://${req.headers.host ?? "localhost"}`,
1658
+ csrfMode: deps.csrfMode,
1659
+ // M39 — the thread follow-up route drives the agent; resolve the key on demand.
1660
+ // theokit#328 — the thread route drives an agent, so its key follows the model too.
1661
+ resolveApiKey: (model) => resolveProvider(model).apiKey,
1662
+ // usetheokit/theokit#365 — parity with `theokit start`; lazy for the same reason.
1663
+ resolveSubject: createAgentSubjectResolver({
1664
+ req,
1617
1665
  res,
1618
- "INTERNAL",
1619
- err instanceof Error ? err.message : "Agent aux handler failed",
1620
- 500,
1621
- void 0,
1622
- requestId
1623
- );
1666
+ loadModule: deps.loadModule,
1667
+ serverDir: deps.serverDir,
1668
+ pluginRunner: deps.pluginRunner
1669
+ })
1670
+ };
1671
+ const method = (req.method ?? "GET").toUpperCase();
1672
+ const route = await matchAgentAuxRoute(method, urlPath, auxDeps);
1673
+ if (route === null) {
1674
+ next();
1675
+ return;
1624
1676
  }
1677
+ res.setHeader("x-request-id", requestId);
1678
+ await serveThroughPluginLifecycle(
1679
+ {
1680
+ source: createWebRequestSource(req),
1681
+ res,
1682
+ requestId,
1683
+ pluginRunner: deps.pluginRunner,
1684
+ failureMessage: "Agent aux handler failed"
1685
+ },
1686
+ async (request) => {
1687
+ await writeWebResponseToServerResponse(
1688
+ await serveMatchedAuxRoute(route, request, auxDeps),
1689
+ res
1690
+ );
1691
+ }
1692
+ );
1625
1693
  logRequest({
1626
- method: (req.method ?? "GET").toUpperCase(),
1694
+ method,
1627
1695
  url: req.url ?? "",
1628
1696
  status: res.statusCode,
1629
1697
  duration: Date.now() - start,
1630
1698
  requestId
1631
1699
  });
1632
1700
  }
1633
- function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir = "agents", pluginRunner) {
1701
+ function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir = "agents", deps = {}) {
1702
+ const { pluginRunner, serverDir } = deps;
1634
1703
  const loadModule = createViteLoader(vite);
1704
+ const cardDeps = () => ({
1705
+ projectRoot,
1706
+ loadModule,
1707
+ agentsDir,
1708
+ csrfMode,
1709
+ serverDir,
1710
+ pluginRunner
1711
+ });
1635
1712
  return (req, res, next) => {
1636
1713
  void (async () => {
1637
1714
  const url = req.url ?? "";
1638
1715
  if (isAgentCardPath(url.split("?")[0]) !== null) {
1639
- await serveAux(req, res, next, url.split("?")[0], {
1640
- projectRoot,
1641
- loadModule,
1642
- agentsDir,
1643
- csrfMode
1644
- });
1716
+ await serveAux(req, res, next, url.split("?")[0], cardDeps());
1645
1717
  return;
1646
1718
  }
1647
1719
  if (!url.startsWith(PREFIX2)) {
@@ -1653,16 +1725,12 @@ function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir
1653
1725
  res.setHeader("x-request-id", requestId);
1654
1726
  const urlPath = url.split("?")[0];
1655
1727
  if (isApprovalPath(urlPath)) {
1656
- await serveApprove(req, res, urlPath, csrfMode, { requestId, start });
1657
- return;
1658
- }
1659
- if (isListApprovalsPath(urlPath) !== null || isMcpPath(urlPath) !== null) {
1660
- await serveAux(req, res, next, urlPath, { projectRoot, loadModule, agentsDir, csrfMode });
1728
+ await serveApprove(req, res, urlPath, cardDeps(), { requestId, start });
1661
1729
  return;
1662
1730
  }
1663
1731
  const agent = scanAgents(projectRoot, agentsDir).find((a) => a.agentPath === urlPath);
1664
1732
  if (!agent) {
1665
- next();
1733
+ await serveAux(req, res, next, urlPath, cardDeps());
1666
1734
  return;
1667
1735
  }
1668
1736
  const method = (req.method ?? "POST").toUpperCase();
@@ -1689,7 +1757,8 @@ function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir
1689
1757
  loadModule,
1690
1758
  csrfMode,
1691
1759
  projectRoot,
1692
- pluginRunner
1760
+ pluginRunner,
1761
+ serverDir
1693
1762
  });
1694
1763
  })();
1695
1764
  };
@@ -1706,65 +1775,44 @@ async function serveAgentTurn(t) {
1706
1775
  loadModule,
1707
1776
  csrfMode,
1708
1777
  projectRoot,
1709
- pluginRunner
1778
+ pluginRunner,
1779
+ serverDir
1710
1780
  } = t;
1711
- let pluginCtx;
1712
- let request;
1713
- try {
1714
- request = incomingMessageToWebRequest(req);
1715
- pluginCtx = { request, response: res, ctx: {}, requestId };
1716
- } catch (err) {
1717
- sendError(
1781
+ const resolveSubject = createAgentSubjectResolver({
1782
+ req,
1783
+ res,
1784
+ loadModule,
1785
+ serverDir,
1786
+ pluginRunner
1787
+ });
1788
+ await serveThroughPluginLifecycle(
1789
+ {
1790
+ source: createWebRequestSource(req),
1718
1791
  res,
1719
- "INTERNAL",
1720
- err instanceof Error ? err.message : "Agent handler failed",
1721
- 500,
1722
- void 0,
1723
- requestId
1724
- );
1725
- logRequest({ method, url, status: res.statusCode, duration: Date.now() - start, requestId });
1726
- return;
1727
- }
1728
- if (pluginRunner) {
1729
- pluginRunner.applyDecorations(pluginCtx.ctx);
1730
- const onRequest = await pluginRunner.runOnRequest(pluginCtx);
1731
- if (onRequest.shortCircuited) {
1732
- logRequest({
1733
- method,
1734
- url,
1735
- status: res.statusCode,
1736
- duration: Date.now() - start,
1737
- requestId
1792
+ requestId,
1793
+ pluginRunner,
1794
+ failureMessage: "Agent handler failed"
1795
+ },
1796
+ async (request) => {
1797
+ const mod = await loadModule(agent.filePath);
1798
+ const apiKey = (model) => resolveProvider(model).apiKey;
1799
+ const response = await mountAgent(mod, request, apiKey, {
1800
+ source: agent.filePath,
1801
+ csrfMode,
1802
+ projectRoot,
1803
+ // usetheokit/theokit#365 — the policy comes off `mod`; the caller owes the identity.
1804
+ // usetheokit/theokit#406 — and the same name labels the run's spans.
1805
+ agentName: agent.name,
1806
+ resolveSubject
1738
1807
  });
1739
- return;
1808
+ await writeWebResponseToServerResponse(response, res);
1740
1809
  }
1741
- }
1742
- try {
1743
- const mod = await loadModule(agent.filePath);
1744
- const apiKey = (model) => resolveProvider(model).apiKey;
1745
- const response = await mountAgent(mod, request, apiKey, {
1746
- source: agent.filePath,
1747
- csrfMode,
1748
- projectRoot
1749
- });
1750
- await writeWebResponseToServerResponse(response, res);
1751
- } catch (err) {
1752
- if (pluginRunner) await pluginRunner.runOnError(pluginCtx, err);
1753
- sendError(
1754
- res,
1755
- "INTERNAL",
1756
- err instanceof Error ? err.message : "Agent handler failed",
1757
- 500,
1758
- void 0,
1759
- requestId
1760
- );
1761
- }
1762
- if (pluginRunner) await pluginRunner.runOnResponse(pluginCtx);
1810
+ );
1763
1811
  logRequest({ method, url, status: res.statusCode, duration: Date.now() - start, requestId });
1764
1812
  }
1765
1813
 
1766
1814
  // src/vite-plugin/api-middleware.ts
1767
- import { resolve as resolve4 } from "path";
1815
+ import { resolve as resolve6 } from "path";
1768
1816
  function shouldBypassApiMiddleware(url, prefixes) {
1769
1817
  if (!url.startsWith("/api/")) return true;
1770
1818
  if (prefixes.length === 0) return false;
@@ -1812,10 +1860,10 @@ async function handleBatchIfMatch(req, res, ctx) {
1812
1860
  async function handleBatchInline(req, res, batching, requestId) {
1813
1861
  try {
1814
1862
  const chunks = [];
1815
- await new Promise((resolve10, reject) => {
1863
+ await new Promise((resolve11, reject) => {
1816
1864
  req.on("data", (c) => chunks.push(c));
1817
1865
  req.on("end", () => {
1818
- resolve10();
1866
+ resolve11();
1819
1867
  });
1820
1868
  req.on("error", reject);
1821
1869
  });
@@ -1871,7 +1919,7 @@ async function runPluginsBeforeRouteMatch(pluginRunner, reqCtx) {
1871
1919
  }
1872
1920
  async function tryControllerFallthrough(ctx) {
1873
1921
  const handled = await dispatchControllerRequest({
1874
- controllersDir: resolve4(ctx.serverDir, "controllers"),
1922
+ controllersDir: resolve6(ctx.serverDir, "controllers"),
1875
1923
  loadModule: ctx.loadModule,
1876
1924
  req: ctx.req,
1877
1925
  res: ctx.res,
@@ -1880,6 +1928,14 @@ async function tryControllerFallthrough(ctx) {
1880
1928
  requestId: ctx.requestId,
1881
1929
  // M47 — serve @Expose-bound agent routes via the ONE runtime (mountAgent). CSRF is already enforced
1882
1930
  // once at the controller-dispatch boundary (G5), so mountAgent runs with csrfMode 'off' (no double gate).
1931
+ //
1932
+ // usetheokit/theokit#365 gated the CONVENTION endpoints (`agents/<name>.ts`) and deliberately
1933
+ // left this one to the decorator stack: an `@Expose` route is a controller method, so its
1934
+ // access decision is the controller's `@Guard` chain, which the dispatcher already runs before
1935
+ // it gets here. Passing a policy as well would give this one surface two authorization
1936
+ // mechanisms and no rule for which wins. What is NOT solved by that: an `@Expose`d agent shares
1937
+ // the conversation store with the convention endpoints, so a guard that admits a caller admits
1938
+ // them to whatever `sessionId` the body names — see the advisory.
1883
1939
  serveAgent: (agent, request) => mountAgent(agent, request, (model) => resolveProvider(model).apiKey, {
1884
1940
  source: "expose",
1885
1941
  csrfMode: "off"
@@ -2007,7 +2063,7 @@ function createApiMiddleware(vite, serverDir, rateLimitConfigOrOptions) {
2007
2063
 
2008
2064
  // src/vite-plugin/ssr-dev-middleware.ts
2009
2065
  import { readFileSync as readFileSync2 } from "fs";
2010
- import { resolve as resolve5 } from "path";
2066
+ import { resolve as resolve7 } from "path";
2011
2067
 
2012
2068
  // src/core/contracts/find-root-div.ts
2013
2069
  function maskHtmlComments(html) {
@@ -2098,7 +2154,7 @@ function setupSsrDevMiddleware(server, opts) {
2098
2154
  return;
2099
2155
  }
2100
2156
  try {
2101
- const indexPath = resolve5(opts.projectRoot, "index.html");
2157
+ const indexPath = resolve7(opts.projectRoot, "index.html");
2102
2158
  let template = readFileSync2(indexPath, "utf-8");
2103
2159
  const nonce = generateNonce();
2104
2160
  template = await server.transformIndexHtml(url, template);
@@ -2217,7 +2273,12 @@ async function runConfigureServer(server, ctx) {
2217
2273
  })
2218
2274
  );
2219
2275
  server.middlewares.use(
2220
- createAgentMiddleware(server, ctx.projectRoot, ctx.csrfMode, ctx.agentsDir, ctx.pluginRunner)
2276
+ createAgentMiddleware(server, ctx.projectRoot, ctx.csrfMode, ctx.agentsDir, {
2277
+ pluginRunner: ctx.pluginRunner,
2278
+ // usetheokit/theokit#365 — the same backend root the route middleware scans, so an agent's
2279
+ // declared policy is judged against the identity `server/context.ts` establishes.
2280
+ serverDir
2281
+ })
2221
2282
  );
2222
2283
  const servicesProxyPrefixes = ctx.services && Object.keys(ctx.services).length > 0 ? Object.values(ctx.services).map((s) => s.proxy) : [];
2223
2284
  const csrfReadinessStore = ctx.csrfReadinessStoreOverride ?? new CsrfReadinessStore();
@@ -2236,7 +2297,7 @@ async function runConfigureServer(server, ctx) {
2236
2297
  csrfReadinessStore
2237
2298
  })
2238
2299
  );
2239
- const configPath = resolve6(ctx.projectRoot, "theo.config.ts");
2300
+ const configPath = resolve8(ctx.projectRoot, "theo.config.ts");
2240
2301
  server.watcher.on("change", (file) => {
2241
2302
  if (file === configPath) {
2242
2303
  console.warn(
@@ -2264,9 +2325,9 @@ async function runConfigureServer(server, ctx) {
2264
2325
  server.watcher.on("unlink", handleRouteChange);
2265
2326
  if (ctx.resolvedOpenApi !== void 0) {
2266
2327
  const openApiCfg = ctx.resolvedOpenApi;
2267
- const { reEmitOpenApi } = await import("./dev-emit-NBT6JD7R.js");
2328
+ const { reEmitOpenApi } = await import("./dev-emit-MVAJAFGX.js");
2268
2329
  const openApiServerDir = ctx.serverDir;
2269
- const openApiDistDir = resolve6(ctx.projectRoot, ctx.resolvedDistDir);
2330
+ const openApiDistDir = resolve8(ctx.projectRoot, ctx.resolvedDistDir);
2270
2331
  const isRouteFileForOpenApi = (file) => file.startsWith(openApiServerDir) && /\.(ts|tsx|js|mjs)$/.test(file);
2271
2332
  void reEmitOpenApi(openApiServerDir, openApiDistDir, openApiCfg);
2272
2333
  server.watcher.on("change", (file) => {
@@ -2316,7 +2377,7 @@ async function integrateStudio(importStudio = () => import(
2316
2377
  // src/vite-plugin/integrate-ui.ts
2317
2378
  import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
2318
2379
  import { dirname as dirname3, join as join4 } from "path";
2319
- import { pathToFileURL } from "url";
2380
+ import { pathToFileURL as pathToFileURL2 } from "url";
2320
2381
 
2321
2382
  // src/vite-plugin/auto-detect.ts
2322
2383
  import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
@@ -2448,7 +2509,7 @@ function resolveConsumerImport(name, cwd) {
2448
2509
  entry ??= pkg.module ?? pkg.main;
2449
2510
  if (!entry) return null;
2450
2511
  const cleaned = entry.replace(/^\.\//, "");
2451
- return pathToFileURL(join4(pkgDir, cleaned)).href;
2512
+ return pathToFileURL2(join4(pkgDir, cleaned)).href;
2452
2513
  } catch {
2453
2514
  return null;
2454
2515
  }
@@ -2521,7 +2582,7 @@ async function integrateUseTheoUI(cwd, opts) {
2521
2582
  return [];
2522
2583
  }
2523
2584
  try {
2524
- uiMod = await import(pathToFileURL(uiPluginPath).href);
2585
+ uiMod = await import(pathToFileURL2(uiPluginPath).href);
2525
2586
  } catch (err) {
2526
2587
  console.warn(
2527
2588
  `[theokit] @theokit/ui/vite-plugin dynamic import failed (${err.message}). Skipping auto-config.`
@@ -2571,19 +2632,9 @@ async function integrateUseTheoUI(cwd, opts) {
2571
2632
  return [...tailwindPlugins, ...uiPlugins];
2572
2633
  }
2573
2634
 
2574
- // src/vite-plugin/resolve-theo-root.ts
2575
- import { existsSync as existsSync7 } from "fs";
2576
- import { resolve as resolve7 } from "path";
2577
- function resolveTheoRootDir(currentDir) {
2578
- if (existsSync7(resolve7(currentDir, "client"))) {
2579
- return currentDir;
2580
- }
2581
- return resolve7(currentDir, "..");
2582
- }
2583
-
2584
2635
  // src/vite-plugin/transform-html-hook.ts
2585
- import { existsSync as existsSync8 } from "fs";
2586
- import { resolve as resolve8 } from "path";
2636
+ import { existsSync as existsSync7 } from "fs";
2637
+ import { resolve as resolve9 } from "path";
2587
2638
 
2588
2639
  // src/vite-plugin/inject-devtools.ts
2589
2640
  var DEVTOOLS_VIRTUAL_ID = "/@theo/devtools/entry.js";
@@ -2683,7 +2734,7 @@ function runTransformIndexHtml(html, ctx) {
2683
2734
  next = devtools.html;
2684
2735
  const styles = injectStylesheets(next, {
2685
2736
  isDev: ctx.isDevMode.value,
2686
- hasPackage: (name) => existsSync8(resolve8(ctx.projectRoot, "node_modules", ...name.split("/")))
2737
+ hasPackage: (name) => existsSync7(resolve9(ctx.projectRoot, "node_modules", ...name.split("/")))
2687
2738
  });
2688
2739
  next = styles.html;
2689
2740
  return next;
@@ -2786,6 +2837,46 @@ function generateSingleShotEntry(options) {
2786
2837
  `}`
2787
2838
  ].join("\n");
2788
2839
  }
2840
+ function streamingDocumentHelpers() {
2841
+ return [
2842
+ `function __theoHydrationScript(hydrationData, nonce) {`,
2843
+ // `<` is escaped rather than the whole payload: loader data is developer
2844
+ // data, and the only sequence that can break out of a script element is
2845
+ // `</script`. Mirrors what the non-streaming path does in request-handler.ts.
2846
+ ` const json = JSON.stringify(hydrationData).replace(/</g, '\\u003c')`,
2847
+ ` const attr = nonce ? ' nonce="' + nonce + '"' : ''`,
2848
+ ` return '<script' + attr + '>window.__staticRouterHydrationData=' + json + '<' + '/script>'`,
2849
+ `}`,
2850
+ ``,
2851
+ `function __theoDocumentStream(appStream, hydrationData, options) {`,
2852
+ ` const encoder = new TextEncoder()`,
2853
+ ` const head = options.htmlHead ?? ''`,
2854
+ ` const tail = options.htmlTail ?? ''`,
2855
+ ` return new ReadableStream({`,
2856
+ ` async start(controller) {`,
2857
+ // Its own chunk: the reader gets <head> before React has rendered anything.
2858
+ ` if (head) controller.enqueue(encoder.encode(head))`,
2859
+ ` const reader = appStream.getReader()`,
2860
+ ` try {`,
2861
+ ` for (;;) {`,
2862
+ ` const { done, value } = await reader.read()`,
2863
+ ` if (done) break`,
2864
+ ` controller.enqueue(value)`,
2865
+ ` }`,
2866
+ ` } finally {`,
2867
+ ` reader.releaseLock()`,
2868
+ ` }`,
2869
+ // The hydration script trails the app markup and precedes the tail, so it
2870
+ // still runs before the client entry the tail loads.
2871
+ ` controller.enqueue(`,
2872
+ ` encoder.encode(__theoHydrationScript(hydrationData, options.nonce) + tail),`,
2873
+ ` )`,
2874
+ ` controller.close()`,
2875
+ ` },`,
2876
+ ` })`,
2877
+ `}`
2878
+ ];
2879
+ }
2789
2880
  function streamingWebRenderer(appTree) {
2790
2881
  return [
2791
2882
  `// T2.3 \u2014 Web Standards streaming entry for edge runtimes (Cloudflare,`,
@@ -2805,13 +2896,16 @@ function streamingWebRenderer(appTree) {
2805
2896
  // Streaming still applies to genuine data-fetching Suspense, which is where it earns its keep.
2806
2897
  // A failed import is swallowed on purpose: React.lazy will retry and suspend as before, which
2807
2898
  // is strictly no worse than not having preloaded at all.
2808
- ` const __theoMatches = matchRoutes(routes, url.split('?')[0]) ?? []`,
2899
+ // `url` is a URL here, not the string the other renderers receive as a parameter —
2900
+ // so the match key is `.pathname`, never `.split('?')`. Hoisting the declaration
2901
+ // without changing the accessor trades the TDZ for a TypeError (#344).
2902
+ ` const url = new URL(request.url)`,
2903
+ ` const __theoMatches = matchRoutes(routes, url.pathname) ?? []`,
2809
2904
  ` await Promise.all(`,
2810
2905
  ` __theoPreloadPathsFor(__theoMatches).map((p) => __theoPreloadMap[p]().catch(() => null)),`,
2811
2906
  ` )`,
2812
2907
  ``,
2813
2908
  ` const handler = createStaticHandler(routes)`,
2814
- ` const url = new URL(request.url)`,
2815
2909
  ` const context = await handler.query(request)`,
2816
2910
  ``,
2817
2911
  ` if (context instanceof Response) {`,
@@ -2821,12 +2915,14 @@ function streamingWebRenderer(appTree) {
2821
2915
  ` const router = createStaticRouter(handler.dataRoutes, context)`,
2822
2916
  ` const app = ${appTree}`,
2823
2917
  ``,
2918
+ hydrationDataExtractSnippet(),
2919
+ ``,
2824
2920
  ` const stream = await renderToReadableStream(app, {`,
2825
2921
  ` signal: request.signal,`,
2826
2922
  ` nonce: options.nonce,`,
2827
2923
  ` onError(err) { console.error('[SSR Web Stream Error]', err) },`,
2828
2924
  ` })`,
2829
- ` return new Response(stream, {`,
2925
+ ` return new Response(__theoDocumentStream(stream, hydrationData, options), {`,
2830
2926
  ` status: 200,`,
2831
2927
  ` headers: {`,
2832
2928
  ` 'Content-Type': 'text/html; charset=utf-8',`,
@@ -2870,15 +2966,29 @@ function streamingNodeRenderer(appTree) {
2870
2966
  ` const router = createStaticRouter(handler.dataRoutes, context)`,
2871
2967
  ` const app = ${appTree}`,
2872
2968
  ``,
2969
+ hydrationDataExtractSnippet(),
2970
+ ``,
2971
+ ` const { PassThrough } = await import('node:stream')`,
2873
2972
  ` return new Promise((resolve, reject) => {`,
2874
2973
  ` let didError = false`,
2974
+ // React's `pipe(dest)` ends `dest` when the source ends, which would close the
2975
+ // response before the hydration script could be written. Piping into a
2976
+ // PassThrough keeps the response open for the tail.
2977
+ ` const passthrough = new PassThrough()`,
2978
+ ` passthrough.on('data', (chunk) => { response.write(chunk) })`,
2979
+ ` passthrough.on('end', () => {`,
2980
+ ` response.end(__theoHydrationScript(hydrationData, options.nonce) + (options.htmlTail ?? ''))`,
2981
+ ` })`,
2982
+ ` passthrough.on('error', reject)`,
2875
2983
  ` const stream = renderToPipeableStream(app, {`,
2876
2984
  ` nonce: options.nonce,`,
2877
2985
  ` onShellReady() {`,
2878
2986
  ` response.statusCode = didError ? 500 : 200`,
2879
2987
  ` response.setHeader('Content-Type', 'text/html; charset=utf-8')`,
2880
2988
  ` response.setHeader('Transfer-Encoding', 'chunked')`,
2881
- ` stream.pipe(response)`,
2989
+ // The head goes out on its own write, before any React byte.
2990
+ ` if (options.htmlHead) response.write(options.htmlHead)`,
2991
+ ` stream.pipe(passthrough)`,
2882
2992
  ` resolve({ streaming: true })`,
2883
2993
  ` },`,
2884
2994
  ` onShellError(err) { reject(err) },`,
@@ -2962,6 +3072,8 @@ function generateStreamingEntry(options) {
2962
3072
  `import { routes, __theoPreloadMap, __theoPreloadPathsFor } from '/@theo/route-manifest'`,
2963
3073
  theoUiImport,
2964
3074
  ``,
3075
+ ...streamingDocumentHelpers(),
3076
+ ``,
2965
3077
  ...streamingWebRenderer(appTree),
2966
3078
  ``,
2967
3079
  ...streamingNodeRenderer(appTree),
@@ -3071,7 +3183,6 @@ function walkRouteTree(node, parents, acc) {
3071
3183
  routePath
3072
3184
  });
3073
3185
  }
3074
- if (node.layout !== void 0) acc.layoutState.found = true;
3075
3186
  pushIf(acc.staticImports, node.layout, safeVarName(seg, "Layout"));
3076
3187
  pushIf(acc.staticImports, node.error, safeVarName(seg, "Error"));
3077
3188
  pushIf(acc.staticImports, node.loading, safeVarName(seg, "Loading"));
@@ -3086,18 +3197,20 @@ function generateRouteManifest(tree, options = {}) {
3086
3197
  const lazyPages_ = options.lazyPages !== false;
3087
3198
  const acc = {
3088
3199
  staticImports: [],
3089
- lazyPages: [],
3090
- layoutState: { found: false }
3200
+ lazyPages: []
3091
3201
  };
3092
3202
  walkRouteTree(tree, [], acc);
3093
3203
  const staticImports = acc.staticImports;
3094
3204
  const lazyPages = acc.lazyPages;
3095
- const layoutState = acc.layoutState;
3096
3205
  const lines = [`import React, { Suspense } from 'react'`];
3097
- if (layoutState.found) {
3098
- lines.push(`import { Outlet } from 'react-router'`);
3099
- }
3100
- lines.push("");
3206
+ lines.push(
3207
+ `import { Outlet, ScrollRestoration } from 'react-router'`,
3208
+ // #421 — react-router restores the DOCUMENT. The layout this framework scaffolds scrolls an
3209
+ // inner element, so the restoration that was mounted and running restored nothing. Both are
3210
+ // emitted: one owns the document, the other owns the elements the app marked.
3211
+ `import { ElementScrollRestoration } from 'theokit/router/element-scroll-restoration'`,
3212
+ ""
3213
+ );
3101
3214
  for (const imp of staticImports) {
3102
3215
  lines.push(`import ${imp.varName} from '${imp.importPath}'`);
3103
3216
  }
@@ -3151,16 +3264,20 @@ function generateRouteManifest(tree, options = {}) {
3151
3264
  function genRouteConfig(node, isRoot) {
3152
3265
  const seg = node.segment || "root";
3153
3266
  const childrenArray = buildChildrenArray(node, seg);
3267
+ const withScrollRestoration = (element) => `React.createElement(React.Fragment, null, React.createElement(ScrollRestoration), React.createElement(ElementScrollRestoration), ${element})`;
3154
3268
  if (node.layout) {
3155
3269
  const layoutVar = safeVarName(seg, "Layout");
3156
3270
  const pathPart = isRoot ? `path: '/'` : `path: '${segmentPath(node)}'`;
3157
- return `{ ${pathPart}, element: React.createElement(${layoutVar}, { children: React.createElement(Outlet) }), children: ${childrenArray} }`;
3271
+ const layoutElement = `React.createElement(${layoutVar}, { children: React.createElement(Outlet) })`;
3272
+ const element = isRoot ? withScrollRestoration(layoutElement) : layoutElement;
3273
+ return `{ ${pathPart}, element: ${element}, children: ${childrenArray} }`;
3158
3274
  }
3159
3275
  if (isRoot) {
3276
+ const rootElement = withScrollRestoration(`React.createElement(Outlet)`);
3160
3277
  if (node.children.length === 0 && !node.page && !node.notFound && !node.error) {
3161
- return `{ path: '/', children: [] }`;
3278
+ return `{ path: '/', element: ${rootElement}, children: [] }`;
3162
3279
  }
3163
- return `{ path: '/', children: ${childrenArray} }`;
3280
+ return `{ path: '/', element: ${rootElement}, children: ${childrenArray} }`;
3164
3281
  }
3165
3282
  if (node.page && node.children.length === 0 && !node.error && !node.notFound) {
3166
3283
  const pageVar = safeVarName(seg, "Page");
@@ -3328,8 +3445,8 @@ function findConsumerConfig(projectRoot, basename2) {
3328
3445
  let dir = projectRoot;
3329
3446
  for (let level = 0; level < 3; level++) {
3330
3447
  for (const ext of extensions) {
3331
- const candidate = resolve9(dir, `${basename2}${ext}`);
3332
- if (existsSync9(candidate)) return candidate;
3448
+ const candidate = resolve10(dir, `${basename2}${ext}`);
3449
+ if (existsSync8(candidate)) return candidate;
3333
3450
  }
3334
3451
  const parent = dirname4(dir);
3335
3452
  if (parent === dir) break;
@@ -3340,7 +3457,7 @@ function findConsumerConfig(projectRoot, basename2) {
3340
3457
  async function theoPluginAsync(rootOrOptions) {
3341
3458
  const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions ?? {};
3342
3459
  const projectRoot = options.root ?? process.cwd();
3343
- const serverDirAbs = resolve9(projectRoot, options.serverDir ?? "server");
3460
+ const serverDirAbs = resolve10(projectRoot, options.serverDir ?? "server");
3344
3461
  const agentsDirName = options.agentsDir ?? "agents";
3345
3462
  const consumerTailwindConfig = findConsumerConfig(projectRoot, "tailwind.config");
3346
3463
  const consumerPostcssConfig = findConsumerConfig(projectRoot, "postcss.config");
@@ -3359,23 +3476,23 @@ async function theoPluginAsync(rootOrOptions) {
3359
3476
  })
3360
3477
  );
3361
3478
  }
3362
- const { appTypedClientPlugin } = await import("./app-typed-client-HLP26EYM.js");
3479
+ const { appTypedClientPlugin } = await import("./app-typed-client-XGDZKH73.js");
3363
3480
  const appClientPlugin = appTypedClientPlugin({
3364
3481
  cwd: projectRoot,
3365
3482
  serverDir: serverDirAbs,
3366
- distDir: resolve9(projectRoot, ".theokit")
3483
+ distDir: resolve10(projectRoot, ".theokit")
3367
3484
  });
3368
- const { actionsVirtualModule } = await import("./actions-virtual-module-E4PISKMB.js");
3485
+ const { actionsVirtualModule } = await import("./actions-virtual-module-RXL2RJTW.js");
3369
3486
  const actionsPlugin = actionsVirtualModule({
3370
3487
  serverDir: serverDirAbs,
3371
- distDir: resolve9(projectRoot, ".theokit")
3488
+ distDir: resolve10(projectRoot, ".theokit")
3372
3489
  });
3373
3490
  const { agentsTypedClientPlugin } = await import("./agents-typed-client-INR2E7B3.js");
3374
- const { generateManifest } = await import("./internal-api-ZCJWJ5EC.js");
3491
+ const { generateManifest } = await import("./internal-api-XQHU5JKY.js");
3375
3492
  const agentsClientPlugin = agentsTypedClientPlugin({
3376
3493
  projectRoot,
3377
3494
  agentsDir: agentsDirName,
3378
- distDir: resolve9(projectRoot, ".theokit"),
3495
+ distDir: resolve10(projectRoot, ".theokit"),
3379
3496
  // Agents live at <projectRoot>/<agentsDir>; generateManifest scans them via the server dir's
3380
3497
  // parent (projectRoot for the canonical layout) + the agents dir name (#95 follow-up).
3381
3498
  scanManifest: () => generateManifest(serverDirAbs, projectRoot, agentsDirName)
@@ -3388,11 +3505,17 @@ async function theoPluginAsync(rootOrOptions) {
3388
3505
  const controllerTransformPlugin = controllerSwcTransformPlugin({
3389
3506
  serverDir: serverDirAbs
3390
3507
  });
3508
+ const { serverOnlyImportBoundary } = await import("./server-boundary-2WFT546S.js");
3509
+ const serverBoundaryPlugin = serverOnlyImportBoundary({
3510
+ projectRoot,
3511
+ serverDir: serverDirAbs
3512
+ });
3391
3513
  return [
3392
3514
  theoPlugin(rootOrOptions),
3393
3515
  ...uiPlugins,
3394
3516
  ...studioPlugins,
3395
3517
  ...servicesPlugins,
3518
+ serverBoundaryPlugin,
3396
3519
  // #122 — swc-compile controllers/** (enforce:'pre'; order-independent).
3397
3520
  controllerTransformPlugin,
3398
3521
  appClientPlugin,
@@ -3403,10 +3526,10 @@ async function theoPluginAsync(rootOrOptions) {
3403
3526
  }
3404
3527
  function buildOptimizeDepsInclude(projectRoot, viteOptimizeDeps) {
3405
3528
  const include = [];
3406
- if (existsSync9(resolve9(projectRoot, "node_modules", "@theokit", "ui"))) {
3529
+ if (existsSync8(resolve10(projectRoot, "node_modules", "@theokit", "ui"))) {
3407
3530
  include.push("@theokit/ui");
3408
3531
  }
3409
- if (existsSync9(resolve9(projectRoot, "node_modules", "lucide-react"))) {
3532
+ if (existsSync8(resolve10(projectRoot, "node_modules", "lucide-react"))) {
3410
3533
  include.push("lucide-react");
3411
3534
  }
3412
3535
  include.push("devalue");
@@ -3432,8 +3555,8 @@ var VIRTUAL_MODULE_IDS = {
3432
3555
  function theoPlugin(rootOrOptions) {
3433
3556
  const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions ?? {};
3434
3557
  const projectRoot = options.root ?? process.cwd();
3435
- const appDir = resolve9(projectRoot, options.appDir ?? "app");
3436
- const serverDir = resolve9(projectRoot, options.serverDir ?? "server");
3558
+ const appDir = resolve10(projectRoot, options.appDir ?? "app");
3559
+ const serverDir = resolve10(projectRoot, options.serverDir ?? "server");
3437
3560
  const agentsDir = options.agentsDir ?? "agents";
3438
3561
  const ssrEnabled = options.ssr ?? false;
3439
3562
  const currentDir = dirname4(fileURLToPath(import.meta.url));
@@ -3565,4 +3688,4 @@ export {
3565
3688
  theoPluginAsync,
3566
3689
  theoPlugin
3567
3690
  };
3568
- //# sourceMappingURL=chunk-FTFN4MYN.js.map
3691
+ //# sourceMappingURL=chunk-7AEBH52I.js.map