theokit 0.43.12 → 0.44.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/dist/{actions-virtual-module-RSFRPJQZ.js → actions-virtual-module-67K4POQ2.js} +20 -20
  2. package/dist/actions-virtual-module-67K4POQ2.js.map +1 -0
  3. package/dist/{actions-virtual-module-HG66SZ7T.js → actions-virtual-module-IK2SDIZ3.js} +4 -3
  4. package/dist/{actions-virtual-module-HG66SZ7T.js.map → actions-virtual-module-IK2SDIZ3.js.map} +1 -1
  5. package/dist/adapters/web-shim.js +1 -1
  6. package/dist/adapters/web-shim.js.map +1 -1
  7. package/dist/adapters/ws-shim.js +1 -1
  8. package/dist/adapters/ws-shim.js.map +1 -1
  9. package/dist/{agent-OXRRKB55.js → agent-OCCL5RUY.js} +2 -2
  10. package/dist/{agents-typed-client-ZP7BKJB3.js → agents-typed-client-TNHCUU7Q.js} +2 -2
  11. package/dist/agents-typed-client-TNHCUU7Q.js.map +1 -0
  12. package/dist/{app-typed-client-GDF2OMJ2.js → app-typed-client-4OH3JREB.js} +47 -8
  13. package/dist/app-typed-client-4OH3JREB.js.map +1 -0
  14. package/dist/{app-typed-client-USLAMN7X.js → app-typed-client-N5WUE2CP.js} +62 -24
  15. package/dist/app-typed-client-N5WUE2CP.js.map +1 -0
  16. package/dist/{body-parser-web-NNEJGX6Y.js → body-parser-web-4Z2QTPDU.js} +2 -2
  17. package/dist/body-parser-web-4Z2QTPDU.js.map +1 -0
  18. package/dist/boot/index.js +4 -4
  19. package/dist/boot/index.js.map +1 -1
  20. package/dist/{broadcast-4SX7R5XE.js → broadcast-H64DJRBE.js} +3 -3
  21. package/dist/broadcast-H64DJRBE.js.map +1 -0
  22. package/dist/{build-MQHIJROR.js → build-25RSFP22.js} +13 -4
  23. package/dist/build-25RSFP22.js.map +1 -0
  24. package/dist/{build-request-body-preview-FVBQ7LCE.js → build-request-body-preview-CKWWBF2M.js} +2 -2
  25. package/dist/build-request-body-preview-CKWWBF2M.js.map +1 -0
  26. package/dist/{chunk-26ECIX74.js → chunk-2ADKT37V.js} +5 -5
  27. package/dist/chunk-2ADKT37V.js.map +1 -0
  28. package/dist/{chunk-JIL74SFK.js → chunk-37ZO643S.js} +9 -9
  29. package/dist/chunk-37ZO643S.js.map +1 -0
  30. package/dist/{chunk-ESC54TAK.js → chunk-3DGIANAN.js} +1 -1
  31. package/dist/chunk-3DGIANAN.js.map +1 -0
  32. package/dist/{chunk-6FK7FKY6.js → chunk-47FFT43U.js} +1 -1
  33. package/dist/chunk-47FFT43U.js.map +1 -0
  34. package/dist/{chunk-ZJQ4O76G.js → chunk-4FWBKX6G.js} +1 -1
  35. package/dist/chunk-4FWBKX6G.js.map +1 -0
  36. package/dist/{chunk-NM4WF3XD.js → chunk-4PBJ266F.js} +1 -1
  37. package/dist/chunk-4PBJ266F.js.map +1 -0
  38. package/dist/{chunk-7MQOHNHE.js → chunk-52PDWL5S.js} +1 -1
  39. package/dist/chunk-52PDWL5S.js.map +1 -0
  40. package/dist/{chunk-JQJN6LFK.js → chunk-62EU2BVZ.js} +2 -2
  41. package/dist/chunk-62EU2BVZ.js.map +1 -0
  42. package/dist/{chunk-SJIRP73B.js → chunk-646CA6RV.js} +2 -2
  43. package/dist/chunk-646CA6RV.js.map +1 -0
  44. package/dist/{chunk-ASDXVRJD.js → chunk-6KDXP472.js} +4 -4
  45. package/dist/chunk-6KDXP472.js.map +1 -0
  46. package/dist/chunk-6LNIGF5P.js +46 -0
  47. package/dist/chunk-6LNIGF5P.js.map +1 -0
  48. package/dist/chunk-7IHWXDJJ.js +1 -0
  49. package/dist/chunk-7IHWXDJJ.js.map +1 -0
  50. package/dist/{chunk-JQSKBMXP.js → chunk-7LVM22VG.js} +1 -1
  51. package/dist/chunk-7LVM22VG.js.map +1 -0
  52. package/dist/{chunk-UVXB2ER7.js → chunk-7SABX4DJ.js} +1 -1
  53. package/dist/chunk-7SABX4DJ.js.map +1 -0
  54. package/dist/{chunk-X32XEJXR.js → chunk-ACKBVBUI.js} +1 -1
  55. package/dist/chunk-ACKBVBUI.js.map +1 -0
  56. package/dist/{chunk-UUFYP2UM.js → chunk-AM3QABW5.js} +3 -3
  57. package/dist/chunk-AM3QABW5.js.map +1 -0
  58. package/dist/{chunk-FH3DYBAN.js → chunk-ANS4ELRH.js} +1 -1
  59. package/dist/chunk-ANS4ELRH.js.map +1 -0
  60. package/dist/{chunk-UD3LFGDL.js → chunk-AVQU5CQF.js} +1 -1
  61. package/dist/chunk-AVQU5CQF.js.map +1 -0
  62. package/dist/{chunk-CJNMJUHE.js → chunk-B7ONQ4QJ.js} +2 -2
  63. package/dist/{chunk-WSJKACWB.js → chunk-C34PMLSN.js} +1 -1
  64. package/dist/chunk-C34PMLSN.js.map +1 -0
  65. package/dist/{chunk-2WH6SD3C.js → chunk-DSOBIXXR.js} +4 -4
  66. package/dist/{chunk-DJFMAWH5.js → chunk-EIRQM55C.js} +6 -5
  67. package/dist/chunk-EIRQM55C.js.map +1 -0
  68. package/dist/{chunk-ZEGYW52B.js → chunk-FB2HBNIC.js} +1 -1
  69. package/dist/chunk-FB2HBNIC.js.map +1 -0
  70. package/dist/chunk-FXZZS7YW.js +605 -0
  71. package/dist/chunk-FXZZS7YW.js.map +1 -0
  72. package/dist/{chunk-HGUZWG2C.js → chunk-FZG3JYB3.js} +8 -47
  73. package/dist/chunk-FZG3JYB3.js.map +1 -0
  74. package/dist/{chunk-V3LJN2GS.js → chunk-GAPBPRPP.js} +1 -1
  75. package/dist/chunk-GAPBPRPP.js.map +1 -0
  76. package/dist/chunk-GUBN5UTT.js +1 -0
  77. package/dist/chunk-GUBN5UTT.js.map +1 -0
  78. package/dist/{chunk-6OXCZMW3.js → chunk-HEK4SET7.js} +5 -5
  79. package/dist/chunk-HEK4SET7.js.map +1 -0
  80. package/dist/{chunk-N2D5AVRR.js → chunk-HRCNHWLP.js} +7 -109
  81. package/dist/chunk-HRCNHWLP.js.map +1 -0
  82. package/dist/{chunk-C3ZZ56YZ.js → chunk-JA2ZAT5Q.js} +1 -1
  83. package/dist/chunk-JA2ZAT5Q.js.map +1 -0
  84. package/dist/{chunk-L2S2R3TI.js → chunk-KBGGQK4I.js} +25 -8
  85. package/dist/chunk-KBGGQK4I.js.map +1 -0
  86. package/dist/{chunk-VPISAMXU.js → chunk-KD5G3YXI.js} +4 -4
  87. package/dist/chunk-KD5G3YXI.js.map +1 -0
  88. package/dist/{chunk-VMEWD57H.js → chunk-KPKLIUUL.js} +1 -1
  89. package/dist/chunk-KPKLIUUL.js.map +1 -0
  90. package/dist/{chunk-4HAU7AJM.js → chunk-L4Y6RJ4E.js} +3 -3
  91. package/dist/chunk-L4Y6RJ4E.js.map +1 -0
  92. package/dist/{chunk-OVHW23YC.js → chunk-L5Z6IY5U.js} +5 -5
  93. package/dist/chunk-L5Z6IY5U.js.map +1 -0
  94. package/dist/{chunk-JBCHWRKF.js → chunk-MTEWLGVY.js} +2 -2
  95. package/dist/chunk-MTEWLGVY.js.map +1 -0
  96. package/dist/{chunk-XZ6B2Y2R.js → chunk-MWP4YXWJ.js} +1 -1
  97. package/dist/chunk-MWP4YXWJ.js.map +1 -0
  98. package/dist/{chunk-575PAX5L.js → chunk-NGEBYCOZ.js} +62 -38
  99. package/dist/chunk-NGEBYCOZ.js.map +1 -0
  100. package/dist/{chunk-5QW7IQQU.js → chunk-NTDN54XO.js} +1 -1
  101. package/dist/chunk-NTDN54XO.js.map +1 -0
  102. package/dist/{chunk-7BIM27LV.js → chunk-OIGJOYX6.js} +1 -1
  103. package/dist/chunk-OIGJOYX6.js.map +1 -0
  104. package/dist/{chunk-TSLSIRBR.js → chunk-OLGPYOLO.js} +2 -2
  105. package/dist/chunk-OLGPYOLO.js.map +1 -0
  106. package/dist/{chunk-IE6C4KZX.js → chunk-Q5OT7LZG.js} +11 -496
  107. package/dist/chunk-Q5OT7LZG.js.map +1 -0
  108. package/dist/{chunk-6NEXVBPY.js → chunk-RWNSW4FM.js} +1 -1
  109. package/dist/chunk-RWNSW4FM.js.map +1 -0
  110. package/dist/{chunk-E25FBYJP.js → chunk-SAFGDIPQ.js} +1 -1
  111. package/dist/chunk-SAFGDIPQ.js.map +1 -0
  112. package/dist/{chunk-OP7QCTR5.js → chunk-SEELKQUM.js} +2 -2
  113. package/dist/chunk-SEELKQUM.js.map +1 -0
  114. package/dist/{chunk-4B2ZMX45.js → chunk-SSYDEKWF.js} +1 -1
  115. package/dist/chunk-SSYDEKWF.js.map +1 -0
  116. package/dist/{chunk-DQVBL2G4.js → chunk-SZU6BOMV.js} +75 -53
  117. package/dist/chunk-SZU6BOMV.js.map +1 -0
  118. package/dist/{chunk-65EFIUDD.js → chunk-U267AOWS.js} +1 -1
  119. package/dist/chunk-U267AOWS.js.map +1 -0
  120. package/dist/{chunk-FX72VHAE.js → chunk-U3H53IIN.js} +6 -6
  121. package/dist/chunk-U3H53IIN.js.map +1 -0
  122. package/dist/{chunk-OPLICDUB.js → chunk-UW2TEAGR.js} +1 -1
  123. package/dist/chunk-UW2TEAGR.js.map +1 -0
  124. package/dist/{chunk-IAJ2JVEH.js → chunk-VSLTKX5L.js} +1 -1
  125. package/dist/chunk-VSLTKX5L.js.map +1 -0
  126. package/dist/{chunk-YB5DJJ4U.js → chunk-VZTYCAO6.js} +1 -1
  127. package/dist/chunk-VZTYCAO6.js.map +1 -0
  128. package/dist/chunk-WDGYCBNI.js +65 -0
  129. package/dist/chunk-WDGYCBNI.js.map +1 -0
  130. package/dist/chunk-WPJOTQA5.js +1 -0
  131. package/dist/chunk-WPJOTQA5.js.map +1 -0
  132. package/dist/{chunk-DGUM43GV.js → chunk-XTHN6JBX.js} +1 -1
  133. package/dist/chunk-XTHN6JBX.js.map +1 -0
  134. package/dist/{chunk-HZ6USUHC.js → chunk-YOIVCCZT.js} +1 -1
  135. package/dist/chunk-YOIVCCZT.js.map +1 -0
  136. package/dist/{chunk-OI6DK6ZJ.js → chunk-ZC2UESE4.js} +6 -4
  137. package/dist/{chunk-OI6DK6ZJ.js.map → chunk-ZC2UESE4.js.map} +1 -1
  138. package/dist/cli/index.js +8 -8
  139. package/dist/client/core.d.ts +4 -258
  140. package/dist/client/core.js +13 -9
  141. package/dist/client/core.js.map +1 -1
  142. package/dist/client/index.d.ts +7 -96
  143. package/dist/client/index.js +19 -67
  144. package/dist/client/index.js.map +1 -1
  145. package/dist/{controller-swc-transform-JJRMTSDY.js → controller-swc-transform-T7ZTD55V.js} +2 -2
  146. package/dist/controller-swc-transform-T7ZTD55V.js.map +1 -0
  147. package/dist/{cookies-MJKMGJ7N.js → cookies-SOXUQJXG.js} +3 -3
  148. package/dist/cookies-SOXUQJXG.js.map +1 -0
  149. package/dist/{dev-WQ4LWCAW.js → dev-V6UBM2OL.js} +8 -7
  150. package/dist/{dev-WQ4LWCAW.js.map → dev-V6UBM2OL.js.map} +1 -1
  151. package/dist/{dev-emit-HLGJK3PP.js → dev-emit-F54Y5TIU.js} +5 -5
  152. package/dist/dev-emit-F54Y5TIU.js.map +1 -0
  153. package/dist/devtools/entry.js +61 -53
  154. package/dist/devtools/entry.js.map +1 -1
  155. package/dist/dispatcher-MXKF3CRH.js +8 -0
  156. package/dist/dispatcher-MXKF3CRH.js.map +1 -0
  157. package/dist/index.js +25 -25
  158. package/dist/index.js.map +1 -1
  159. package/dist/{info-75U6GCMD.js → info-ICDTPJDC.js} +3 -3
  160. package/dist/{internal-api-JFORKYLR.js → internal-api-ALXVBL56.js} +10 -8
  161. package/dist/{internal-api-DV3H5NNV.js → internal-api-S7WK2WCY.js} +20 -20
  162. package/dist/internal-api-S7WK2WCY.js.map +1 -0
  163. package/dist/{load-config-XP7NSSA7.js → load-config-ICCNMO74.js} +3 -3
  164. package/dist/{mcp-FF3NTCHB.js → mcp-4JFODA5U.js} +3 -3
  165. package/dist/{openapi-ZPXYRAM2.js → openapi-NIYA2VBG.js} +3 -3
  166. package/dist/react-query/index.js +2 -2
  167. package/dist/react-query/index.js.map +1 -1
  168. package/dist/{routes-ZVDKABXZ.js → routes-2RD4S5PZ.js} +3 -3
  169. package/dist/{schema-FBOTN46F.js → schema-S553QCAU.js} +2 -2
  170. package/dist/server/agent/index.d.ts +3 -72
  171. package/dist/server/agent/index.js +4 -4
  172. package/dist/server/agent/index.js.map +1 -1
  173. package/dist/server/auth/index.js +4 -4
  174. package/dist/server/auth/index.js.map +1 -1
  175. package/dist/server/cost/index.js +2 -2
  176. package/dist/server/cost/index.js.map +1 -1
  177. package/dist/server/cron/index.js +6 -6
  178. package/dist/server/cron/index.js.map +1 -1
  179. package/dist/server/define/index.js +4 -4
  180. package/dist/server/define/index.js.map +1 -1
  181. package/dist/server/http/index.js +11 -11
  182. package/dist/server/http/index.js.map +1 -1
  183. package/dist/server/index.d.ts +2 -2
  184. package/dist/server/index.js +41 -41
  185. package/dist/server/index.js.map +1 -1
  186. package/dist/server/jobs/index.js +7 -7
  187. package/dist/server/jobs/index.js.map +1 -1
  188. package/dist/server/observability/index.d.ts +8 -1
  189. package/dist/server/observability/index.js +5 -5
  190. package/dist/server/observability/index.js.map +1 -1
  191. package/dist/server/plugins/index.js +3 -3
  192. package/dist/server/plugins/index.js.map +1 -1
  193. package/dist/server/rate-limit/index.js +4 -4
  194. package/dist/server/rate-limit/index.js.map +1 -1
  195. package/dist/server/realtime/index.js +2 -2
  196. package/dist/server/realtime/index.js.map +1 -1
  197. package/dist/server/scan/index.js +7 -7
  198. package/dist/server/scan/index.js.map +1 -1
  199. package/dist/server/security/index.js +5 -5
  200. package/dist/server/security/index.js.map +1 -1
  201. package/dist/server/storage/index.js +2 -2
  202. package/dist/server/storage/index.js.map +1 -1
  203. package/dist/server/webhook/index.js +3 -3
  204. package/dist/server/webhook/index.js.map +1 -1
  205. package/dist/server-error-to-envelope-UM7DEVM4.js +8 -0
  206. package/dist/server-error-to-envelope-UM7DEVM4.js.map +1 -0
  207. package/dist/{server-routes-hmr-RI7SYNT2.js → server-routes-hmr-6CRNSEWF.js} +2 -2
  208. package/dist/server-routes-hmr-6CRNSEWF.js.map +1 -0
  209. package/dist/{services-typed-client-AU6DKXAO.js → services-typed-client-IXNOPVZA.js} +3 -3
  210. package/dist/services-typed-client-IXNOPVZA.js.map +1 -0
  211. package/dist/{start-2U3FUCJX.js → start-2LNPPG74.js} +35 -11
  212. package/dist/start-2LNPPG74.js.map +1 -0
  213. package/dist/vite-plugin/index.js +25 -25
  214. package/dist/vite-plugin/index.js.map +1 -1
  215. package/dist/{vite-plugin-D2NTPZNC.js → vite-plugin-X6YO3OUH.js} +8 -7
  216. package/package.json +9 -5
  217. package/dist/actions-virtual-module-RSFRPJQZ.js.map +0 -1
  218. package/dist/agents-typed-client-ZP7BKJB3.js.map +0 -1
  219. package/dist/app-typed-client-GDF2OMJ2.js.map +0 -1
  220. package/dist/app-typed-client-USLAMN7X.js.map +0 -1
  221. package/dist/body-parser-web-NNEJGX6Y.js.map +0 -1
  222. package/dist/build-MQHIJROR.js.map +0 -1
  223. package/dist/build-request-body-preview-FVBQ7LCE.js.map +0 -1
  224. package/dist/chunk-26ECIX74.js.map +0 -1
  225. package/dist/chunk-4B2ZMX45.js.map +0 -1
  226. package/dist/chunk-4HAU7AJM.js.map +0 -1
  227. package/dist/chunk-575PAX5L.js.map +0 -1
  228. package/dist/chunk-5QW7IQQU.js.map +0 -1
  229. package/dist/chunk-65EFIUDD.js.map +0 -1
  230. package/dist/chunk-6FK7FKY6.js.map +0 -1
  231. package/dist/chunk-6NEXVBPY.js.map +0 -1
  232. package/dist/chunk-6OXCZMW3.js.map +0 -1
  233. package/dist/chunk-7BIM27LV.js.map +0 -1
  234. package/dist/chunk-7MQOHNHE.js.map +0 -1
  235. package/dist/chunk-ASDXVRJD.js.map +0 -1
  236. package/dist/chunk-C3ZZ56YZ.js.map +0 -1
  237. package/dist/chunk-DJFMAWH5.js.map +0 -1
  238. package/dist/chunk-DQVBL2G4.js.map +0 -1
  239. package/dist/chunk-E25FBYJP.js.map +0 -1
  240. package/dist/chunk-E3JH6YUM.js +0 -1
  241. package/dist/chunk-ESC54TAK.js.map +0 -1
  242. package/dist/chunk-FH3DYBAN.js.map +0 -1
  243. package/dist/chunk-FX72VHAE.js.map +0 -1
  244. package/dist/chunk-HGUZWG2C.js.map +0 -1
  245. package/dist/chunk-HZ6USUHC.js.map +0 -1
  246. package/dist/chunk-IAJ2JVEH.js.map +0 -1
  247. package/dist/chunk-IE6C4KZX.js.map +0 -1
  248. package/dist/chunk-JBCHWRKF.js.map +0 -1
  249. package/dist/chunk-JHEAWR3L.js +0 -1
  250. package/dist/chunk-JIL74SFK.js.map +0 -1
  251. package/dist/chunk-JQJN6LFK.js.map +0 -1
  252. package/dist/chunk-JQSKBMXP.js.map +0 -1
  253. package/dist/chunk-KPRJS3II.js +0 -505
  254. package/dist/chunk-KPRJS3II.js.map +0 -1
  255. package/dist/chunk-L2S2R3TI.js.map +0 -1
  256. package/dist/chunk-N2D5AVRR.js.map +0 -1
  257. package/dist/chunk-NM4WF3XD.js.map +0 -1
  258. package/dist/chunk-NPMCKOX4.js +0 -1
  259. package/dist/chunk-NPMCKOX4.js.map +0 -1
  260. package/dist/chunk-OP7QCTR5.js.map +0 -1
  261. package/dist/chunk-OPLICDUB.js.map +0 -1
  262. package/dist/chunk-OVHW23YC.js.map +0 -1
  263. package/dist/chunk-SJIRP73B.js.map +0 -1
  264. package/dist/chunk-TSLSIRBR.js.map +0 -1
  265. package/dist/chunk-UD3LFGDL.js.map +0 -1
  266. package/dist/chunk-UUFYP2UM.js.map +0 -1
  267. package/dist/chunk-UVXB2ER7.js.map +0 -1
  268. package/dist/chunk-V3LJN2GS.js.map +0 -1
  269. package/dist/chunk-VMEWD57H.js.map +0 -1
  270. package/dist/chunk-VPISAMXU.js.map +0 -1
  271. package/dist/chunk-WSJKACWB.js.map +0 -1
  272. package/dist/chunk-X32XEJXR.js.map +0 -1
  273. package/dist/chunk-XZ6B2Y2R.js.map +0 -1
  274. package/dist/chunk-YB5DJJ4U.js.map +0 -1
  275. package/dist/chunk-ZEGYW52B.js.map +0 -1
  276. package/dist/chunk-ZJQ4O76G.js.map +0 -1
  277. package/dist/controller-swc-transform-JJRMTSDY.js.map +0 -1
  278. package/dist/cookies-MJKMGJ7N.js.map +0 -1
  279. package/dist/dev-emit-HLGJK3PP.js.map +0 -1
  280. package/dist/dispatcher-DLKIXYNO.js +0 -8
  281. package/dist/dispatcher-DLKIXYNO.js.map +0 -1
  282. package/dist/internal-api-DV3H5NNV.js.map +0 -1
  283. package/dist/internal-api-JFORKYLR.js.map +0 -1
  284. package/dist/load-config-XP7NSSA7.js.map +0 -1
  285. package/dist/schema-FBOTN46F.js.map +0 -1
  286. package/dist/server-error-to-envelope-EOFUIUNB.js +0 -8
  287. package/dist/server-error-to-envelope-EOFUIUNB.js.map +0 -1
  288. package/dist/server-routes-hmr-RI7SYNT2.js.map +0 -1
  289. package/dist/services-typed-client-AU6DKXAO.js.map +0 -1
  290. package/dist/start-2U3FUCJX.js.map +0 -1
  291. package/dist/vite-plugin-D2NTPZNC.js.map +0 -1
  292. /package/dist/{agent-OXRRKB55.js.map → agent-OCCL5RUY.js.map} +0 -0
  293. /package/dist/{chunk-CJNMJUHE.js.map → chunk-B7ONQ4QJ.js.map} +0 -0
  294. /package/dist/{chunk-2WH6SD3C.js.map → chunk-DSOBIXXR.js.map} +0 -0
  295. /package/dist/{info-75U6GCMD.js.map → info-ICDTPJDC.js.map} +0 -0
  296. /package/dist/{broadcast-4SX7R5XE.js.map → internal-api-ALXVBL56.js.map} +0 -0
  297. /package/dist/{chunk-DGUM43GV.js.map → load-config-ICCNMO74.js.map} +0 -0
  298. /package/dist/{mcp-FF3NTCHB.js.map → mcp-4JFODA5U.js.map} +0 -0
  299. /package/dist/{openapi-ZPXYRAM2.js.map → openapi-NIYA2VBG.js.map} +0 -0
  300. /package/dist/{routes-ZVDKABXZ.js.map → routes-2RD4S5PZ.js.map} +0 -0
  301. /package/dist/{chunk-E3JH6YUM.js.map → schema-S553QCAU.js.map} +0 -0
  302. /package/dist/{chunk-JHEAWR3L.js.map → vite-plugin-X6YO3OUH.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/_internal/scan-walker.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scanner: walks directories derived from cwd.\n * No HTTP input ever reaches these fs calls.\n */\nimport { readdirSync } from 'node:fs'\nimport { extname, join, resolve } from 'node:path'\n\n/**\n * Options for walkSourceFiles.\n *\n * Sequential by design — callers (route precedence) depend on insertion\n * order (EC-19 documented decision). Async-callback support is implicit\n * via JavaScript's serial await loop.\n *\n * Tested on macOS + Linux. Windows long-path support not validated (EC-20).\n */\ninterface WalkOptions {\n /** File extensions to include (e.g., new Set(['.ts', '.tsx'])). */\n extensions: ReadonlySet<string>\n /** Skip directories whose name starts with any of these (default: ['_', '.']). */\n skipPrefixes?: readonly string[]\n}\n\n/**\n * Recursively walk `root`, invoking `onFile(absPath)` for every file matching\n * `opts.extensions`. Directories whose name starts with any `skipPrefixes`\n * char are skipped (defaults to `_` and `.`).\n *\n * Replaces 3 near-identical recursive walkers in scan.ts, action-scan.ts,\n * ws-scan.ts (PV-3 — DRY consolidation). Resolves T3.1 of\n * architecture-review-remediation-plan.\n *\n * Symlink loops are NOT tracked — callers must avoid them or pre-resolve\n * via `fs.realpath`. EC-11 documented but not implemented (rare in dev).\n */\nexport function walkSourceFiles(\n root: string,\n opts: WalkOptions,\n onFile: (absPath: string) => void,\n): void {\n const skipPrefixes = opts.skipPrefixes ?? ['_', '.']\n const visit = (dir: string): void => {\n let entries\n try {\n entries = readdirSync(dir, { withFileTypes: true })\n } catch {\n // Silently skip unreadable directories — caller controls discoverability\n return\n }\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n if (entry.isDirectory() && !skipPrefixes.some((p) => entry.name.startsWith(p))) {\n visit(fullPath)\n } else if (entry.isFile() && opts.extensions.has(extname(entry.name))) {\n onFile(resolve(fullPath))\n }\n }\n }\n visit(root)\n}\n"],"mappings":";AAIA,SAAS,mBAAmB;AAC5B,SAAS,SAAS,MAAM,eAAe;AA8BhC,SAAS,gBACd,MACA,MACA,QACM;AACN,QAAM,eAAe,KAAK,gBAAgB,CAAC,KAAK,GAAG;AACnD,QAAM,QAAQ,CAAC,QAAsB;AACnC,QAAI;AACJ,QAAI;AACF,gBAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACpD,QAAQ;AAEN;AAAA,IACF;AACA,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,KAAK,KAAK,MAAM,IAAI;AACrC,UAAI,MAAM,YAAY,KAAK,CAAC,aAAa,KAAK,CAAC,MAAM,MAAM,KAAK,WAAW,CAAC,CAAC,GAAG;AAC9E,cAAM,QAAQ;AAAA,MAChB,WAAW,MAAM,OAAO,KAAK,KAAK,WAAW,IAAI,QAAQ,MAAM,IAAI,CAAC,GAAG;AACrE,eAAO,QAAQ,QAAQ,CAAC;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI;AACZ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/jobs/duplicate-context-key-error.ts","../src/server/jobs/outbox.ts","../src/server/jobs/queue-client.ts"],"sourcesContent":["/**\n * Thrown when a plugin or middleware decorates `ctx.<key>` with a value\n * that the framework would also like to inject (e.g., `ctx.queue` from\n * the jobs backend wiring).\n *\n * Per EC-202 of system-100-percent-functional-plan: silent override is a\n * latent bug class. Fail loud so the conflict surfaces immediately.\n */\nexport class DuplicateContextKeyError extends Error {\n readonly code = 'DUPLICATE_CONTEXT_KEY'\n constructor(\n public readonly key: string,\n opts?: { reason?: string },\n ) {\n super(\n `Duplicate context key \"${key}\". ${opts?.reason ?? 'The framework cannot inject a value for a key already decorated by middleware or a plugin.'}`,\n )\n this.name = 'DuplicateContextKeyError'\n }\n}\n","import type { JobEnqueueInput } from './job-backend.js'\n\n/**\n * Transactional outbox buffer for `ctx.queue.enqueue` (T2.5).\n *\n * Lifecycle (wired in `http/execute.ts` by T2.5 integration step):\n * 1. Request handler invoked → create per-request outbox.\n * 2. Handler calls `ctx.queue.enqueue(...)` → outbox.push(entry).\n * 3a. Response committed (`res.on('finish')` + statusCode < 400) →\n * outbox.flush(backend.enqueue).\n * 3b. Response errors (statusCode >= 400, handler throws, `res.on('close')`\n * without finish) → outbox.discard().\n *\n * Invariants:\n * - Outbox NEVER dispatches before commit. Backend.enqueue is NEVER\n * called on the request hot path.\n * - Handler throws → ZERO jobs dispatched. KEY guarantee from ADR-0003.\n *\n * EC-107: when `backend.enqueue` throws DURING flush (after response\n * committed), we log + continue. The response is already gone; partial\n * dispatch is better than zero. Each failure goes to `onError` (default:\n * `console.warn`).\n */\n\nexport interface OutboxFlushOptions {\n /**\n * Called once per failed entry. Default: `console.warn` with the\n * entry name (NOT input — privacy). Throw nothing back to caller —\n * flush always completes.\n */\n onError?: (entryName: string, errorMessage: string) => void\n}\n\nexport interface Outbox {\n push(entry: JobEnqueueInput): void\n drain(): JobEnqueueInput[]\n discard(): void\n size(): number\n /**\n * Dispatch all buffered entries via `dispatcher`. Returns after all\n * entries attempted. Per-entry failures invoke `opts.onError` (or\n * default warn) and do NOT abort the loop.\n */\n flush(\n dispatcher: (entry: JobEnqueueInput) => Promise<unknown>,\n opts?: OutboxFlushOptions,\n ): Promise<void>\n}\n\nexport function createOutbox(): Outbox {\n let buffer: JobEnqueueInput[] = []\n\n return {\n push(entry) {\n buffer.push(entry)\n },\n drain() {\n const out = buffer\n buffer = []\n return out\n },\n discard() {\n buffer = []\n },\n size() {\n return buffer.length\n },\n async flush(dispatcher, opts) {\n const entries = buffer\n buffer = []\n const onError =\n opts?.onError ??\n ((name, msg) => {\n console.warn(`[theokit:jobs:outbox] flush error for \"${name}\": ${msg}`)\n })\n for (const e of entries) {\n try {\n await dispatcher(e)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n onError(e.name, message)\n }\n }\n },\n }\n}\n","import type { JobBackend, JobEnqueueInput } from './job-backend.js'\nimport type { JobRegistry } from './job-types.js'\nimport type { Outbox } from './outbox.js'\n\n/**\n * Options forwarded to `backend.enqueue` at outbox flush time.\n */\nexport interface EnqueueOptions {\n /** Optional idempotency key for at-most-once dispatch within TTL. */\n idempotencyKey?: string\n /** Optional delay before the job becomes available. */\n delaySeconds?: number\n}\n\n/**\n * Typed queue client. Per ADR-0003, `enqueue` returns `void` and buffers\n * to the per-request outbox. `enqueueWithId` is the log-correlation\n * variant that resolves to `{ jobId }` AFTER the outbox flushes.\n *\n * Type inference: `JobName extends keyof JobRegistry`. Users extend the\n * `JobRegistry` interface via module augmentation (see `job-types.ts`).\n * Without augmentation, all enqueue calls compile-error with \"Type X is\n * not assignable to type never\" — documented in EC-110 as a known onboarding\n * friction.\n */\nexport interface QueueClient {\n /** Buffer a job to the outbox. Returns void (fire-and-forget). */\n enqueue<JobName extends keyof JobRegistry>(\n name: JobName,\n input: JobRegistry[JobName],\n opts?: EnqueueOptions,\n ): void\n /**\n * Buffer a job AND return a Promise that resolves with the jobId\n * AFTER the outbox flushes (i.e., after the response commits). NOT a\n * handle to await the job result — there is no result API.\n */\n enqueueWithId<JobName extends keyof JobRegistry>(\n name: JobName,\n input: JobRegistry[JobName],\n opts?: EnqueueOptions,\n ): Promise<{ jobId: string }>\n}\n\ninterface CreateQueueClientOptions {\n /** W3C traceparent to propagate to enqueued jobs. */\n traceparent?: string\n}\n\n/**\n * Create a per-request queue client wired to a backend + outbox.\n *\n * The backend is referenced only to resolve `enqueueWithId` jobIds at\n * flush time — `enqueue` itself does NOT call backend on the hot path\n * (transactional outbox guarantee per ADR-0003).\n */\nexport function createQueueClient(\n backend: JobBackend,\n outbox: Outbox,\n opts: CreateQueueClientOptions = {},\n): QueueClient {\n const traceparent = opts.traceparent\n\n return {\n enqueue(name, input, enqueueOpts) {\n const entry: JobEnqueueInput = {\n name: name,\n input,\n idempotencyKey: enqueueOpts?.idempotencyKey,\n delaySeconds: enqueueOpts?.delaySeconds,\n traceparent,\n }\n outbox.push(entry)\n },\n\n enqueueWithId(name, input, enqueueOpts) {\n let resolveJobId!: (v: { jobId: string }) => void\n let rejectJobId!: (e: unknown) => void\n const promise = new Promise<{ jobId: string }>((resolve, reject) => {\n resolveJobId = resolve\n rejectJobId = reject\n })\n // Prevent unhandled rejection if the response is discarded\n void promise.catch(() => {\n /* swallow — jobId promise is best-effort log correlation */\n })\n\n // Wrap the entry so the outbox flush resolves the promise.\n const entry: JobEnqueueInput & {\n readonly __resolveJobId?: (v: { jobId: string }) => void\n readonly __rejectJobId?: (e: unknown) => void\n } = {\n name: name,\n input,\n idempotencyKey: enqueueOpts?.idempotencyKey,\n delaySeconds: enqueueOpts?.delaySeconds,\n traceparent,\n __resolveJobId: resolveJobId,\n __rejectJobId: rejectJobId,\n }\n outbox.push(entry)\n return promise\n },\n }\n}\n\n/**\n * Outbox dispatcher that bridges enqueueWithId's hidden promise channel\n * (`__resolveJobId` / `__rejectJobId`) to the backend.enqueue result.\n *\n * Use this when the request lifecycle hooks call `outbox.flush(...)`.\n */\nexport function createOutboxDispatcher(\n backend: JobBackend,\n): (entry: JobEnqueueInput) => Promise<unknown> {\n return async (entry) => {\n const augmented = entry as JobEnqueueInput & {\n __resolveJobId?: (v: { jobId: string }) => void\n __rejectJobId?: (e: unknown) => void\n }\n try {\n const result = await backend.enqueue(entry)\n augmented.__resolveJobId?.(result)\n return result\n } catch (err) {\n augmented.__rejectJobId?.(err)\n throw err\n }\n }\n}\n"],"mappings":";AAQO,IAAM,2BAAN,cAAuC,MAAM;AAAA,EAElD,YACkB,KAChB,MACA;AACA;AAAA,MACE,0BAA0B,GAAG,MAAM,MAAM,UAAU,4FAA4F;AAAA,IACjJ;AALgB;AAMhB,SAAK,OAAO;AAAA,EACd;AAAA,EAPkB;AAAA,EAFT,OAAO;AAUlB;;;AC8BO,SAAS,eAAuB;AACrC,MAAI,SAA4B,CAAC;AAEjC,SAAO;AAAA,IACL,KAAK,OAAO;AACV,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,IACA,QAAQ;AACN,YAAM,MAAM;AACZ,eAAS,CAAC;AACV,aAAO;AAAA,IACT;AAAA,IACA,UAAU;AACR,eAAS,CAAC;AAAA,IACZ;AAAA,IACA,OAAO;AACL,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,MAAM,MAAM,YAAY,MAAM;AAC5B,YAAM,UAAU;AAChB,eAAS,CAAC;AACV,YAAM,UACJ,MAAM,YACL,CAAC,MAAM,QAAQ;AACd,gBAAQ,KAAK,0CAA0C,IAAI,MAAM,GAAG,EAAE;AAAA,MACxE;AACF,iBAAW,KAAK,SAAS;AACvB,YAAI;AACF,gBAAM,WAAW,CAAC;AAAA,QACpB,SAAS,KAAK;AACZ,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,kBAAQ,EAAE,MAAM,OAAO;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC7BO,SAAS,kBACd,SACA,QACA,OAAiC,CAAC,GACrB;AACb,QAAM,cAAc,KAAK;AAEzB,SAAO;AAAA,IACL,QAAQ,MAAM,OAAO,aAAa;AAChC,YAAM,QAAyB;AAAA,QAC7B;AAAA,QACA;AAAA,QACA,gBAAgB,aAAa;AAAA,QAC7B,cAAc,aAAa;AAAA,QAC3B;AAAA,MACF;AACA,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,IAEA,cAAc,MAAM,OAAO,aAAa;AACtC,UAAI;AACJ,UAAI;AACJ,YAAM,UAAU,IAAI,QAA2B,CAAC,SAAS,WAAW;AAClE,uBAAe;AACf,sBAAc;AAAA,MAChB,CAAC;AAED,WAAK,QAAQ,MAAM,MAAM;AAAA,MAEzB,CAAC;AAGD,YAAM,QAGF;AAAA,QACF;AAAA,QACA;AAAA,QACA,gBAAgB,aAAa;AAAA,QAC7B,cAAc,aAAa;AAAA,QAC3B;AAAA,QACA,gBAAgB;AAAA,QAChB,eAAe;AAAA,MACjB;AACA,aAAO,KAAK,KAAK;AACjB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAQO,SAAS,uBACd,SAC8C;AAC9C,SAAO,OAAO,UAAU;AACtB,UAAM,YAAY;AAIlB,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,QAAQ,KAAK;AAC1C,gBAAU,iBAAiB,MAAM;AACjC,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,gBAAU,gBAAgB,GAAG;AAC7B,YAAM;AAAA,IACR;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/observability/trace-context-propagation.ts"],"sourcesContent":["// T5a.1a — Web Standards migration (leaf-first slice). Web Crypto's\n// `crypto.getRandomValues()` is available on globalThis in every supported\n// runtime per ADR-0028 (Node 22+, CF Workers, Bun, Deno, browsers). No\n// node:crypto import needed — Web Crypto returns a typed array filled with\n// CSPRNG bytes, which we hex-encode locally instead of relying on Buffer.\n\n/**\n * W3C Trace Context propagation helpers for non-HTTP carriers (job\n * leases, webhook reply headers, agent SSE frames). Works against any\n * `Headers`-shaped carrier — Web Standards only.\n *\n * The HTTP-side extractor `extractTraceId` in `../http/trace-context.ts`\n * is request-scoped and returns only the trace_id string. This module\n * exposes the full `TraceContext` shape (trace_id + span_id + flags)\n * because downstream jobs/webhooks need to propagate a NEW span_id\n * (child span) while keeping the same trace_id.\n *\n * Format spec (W3C Trace Context Level 2):\n * traceparent: version-trace_id-parent_id-trace_flags\n * - version = '00' (current)\n * - trace_id = 32 hex chars (128-bit)\n * - parent_id = 16 hex chars (64-bit) — \"span_id\" of the producer\n * - trace_flags = 2 hex chars (sampled bit)\n *\n * @see https://www.w3.org/TR/trace-context/\n */\n\nexport interface TraceContext {\n /** 32 hex chars. NEVER the reserved all-zeros value. */\n readonly trace_id: string\n /** 16 hex chars. NEVER the reserved all-zeros value. */\n readonly span_id: string\n /** 2 hex chars. Sampled bit + reserved. */\n readonly flags: string\n}\n\nconst TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/\nconst ALL_ZEROS_TRACE = '00000000000000000000000000000000'\nconst ALL_ZEROS_SPAN = '0000000000000000'\n\n/**\n * Extract a TraceContext from a Web Headers object. Returns `null` for:\n * - missing header\n * - malformed (not matching the version-trace-span-flags regex)\n * - reserved all-zeros trace_id (W3C-invalid)\n * - reserved all-zeros span_id (W3C-invalid)\n *\n * NEVER throws — defensive read.\n */\nexport function extractTraceContext(headers: Headers): TraceContext | null {\n const value = headers.get('traceparent')\n if (!value) return null\n const m = TRACEPARENT_RE.exec(value)\n if (!m) return null\n const trace_id = m[1]\n const span_id = m[2]\n const flags = m[3]\n if (trace_id === ALL_ZEROS_TRACE) return null\n if (span_id === ALL_ZEROS_SPAN) return null\n return { trace_id, span_id, flags }\n}\n\n/**\n * Write a canonical traceparent into a Web Headers object. Always\n * succeeds (defensive write — the caller is responsible for passing\n * a valid TraceContext; passing malformed input is a programming bug).\n */\nexport function injectTraceContext(headers: Headers, ctx: TraceContext): void {\n headers.set('traceparent', `00-${ctx.trace_id}-${ctx.span_id}-${ctx.flags}`)\n}\n\n/**\n * Generate a fresh TraceContext (new trace_id + span_id, flags='01' for\n * sampled). Used when no upstream traceparent exists — e.g., when a\n * cron fires or a webhook arrives without an upstream tracer.\n */\nexport function generateNewTraceContext(): TraceContext {\n return {\n trace_id: randomHex(16), // 16 bytes = 32 hex chars\n span_id: randomHex(8), // 8 bytes = 16 hex chars\n flags: '01',\n }\n}\n\nfunction randomHex(bytes: number): string {\n // crypto.getRandomValues is overwhelmingly unlikely to produce all-zeros,\n // but we guard anyway — the W3C spec rejects all-zeros and tests assert\n // this. Web Crypto API returns a Uint8Array; we hex-encode without Buffer\n // to stay runtime-agnostic (CF Workers / Bun / Deno have no Buffer global).\n for (;;) {\n const buf = new Uint8Array(bytes)\n globalThis.crypto.getRandomValues(buf)\n let hex = ''\n for (const b of buf) hex += b.toString(16).padStart(2, '0')\n if (!/^0+$/.test(hex)) return hex\n }\n}\n"],"mappings":";AAoCA,IAAM,iBAAiB;AACvB,IAAM,kBAAkB;AACxB,IAAM,iBAAiB;AAWhB,SAAS,oBAAoB,SAAuC;AACzE,QAAM,QAAQ,QAAQ,IAAI,aAAa;AACvC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,IAAI,eAAe,KAAK,KAAK;AACnC,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,WAAW,EAAE,CAAC;AACpB,QAAM,UAAU,EAAE,CAAC;AACnB,QAAM,QAAQ,EAAE,CAAC;AACjB,MAAI,aAAa,gBAAiB,QAAO;AACzC,MAAI,YAAY,eAAgB,QAAO;AACvC,SAAO,EAAE,UAAU,SAAS,MAAM;AACpC;AAgBO,SAAS,0BAAwC;AACtD,SAAO;AAAA,IACL,UAAU,UAAU,EAAE;AAAA;AAAA,IACtB,SAAS,UAAU,CAAC;AAAA;AAAA,IACpB,OAAO;AAAA,EACT;AACF;AAEA,SAAS,UAAU,OAAuB;AAKxC,aAAS;AACP,UAAM,MAAM,IAAI,WAAW,KAAK;AAChC,eAAW,OAAO,gBAAgB,GAAG;AACrC,QAAI,MAAM;AACV,eAAW,KAAK,IAAK,QAAO,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC1D,QAAI,CAAC,OAAO,KAAK,GAAG,EAAG,QAAO;AAAA,EAChC;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/schema.ts","../src/config/schemas/rate-limit.ts","../src/config/schemas/upload.ts","../src/config/schemas/logging.ts","../src/config/schemas/cache.ts","../src/config/schemas/security.ts","../src/config/schemas/header-safe.ts","../src/config/schemas/storage.ts"],"sourcesContent":["import { z } from 'zod'\n\nimport { servicesConfigSchema } from '../services/index.js'\n\nimport {\n cacheSchema,\n loggingSchema,\n rateLimitSchema,\n securitySchema,\n storageSchema,\n uploadSchema,\n type FormatErrorContext,\n type FormatErrorHook,\n} from './schemas/index.js'\n\n// Re-export per-concern schemas + types so downstream consumers\n// (`adapters/*`, vite-plugin, generators, tests) keep their existing\n// imports valid. Per plan T2.3 — pure structural split; zero behavior\n// change at the call site.\nexport {\n cacheSchema,\n corsSchema,\n rateLimitSchema,\n securityHeadersSchema,\n securitySchema,\n storageSchema,\n} from './schemas/index.js'\n\nexport type { StorageConfig } from './schemas/index.js'\n\n/**\n * Root `theo.config.ts` schema — composer assembled from the per-concern\n * primitives re-exported above.\n *\n * Embedded blocks that exist ONLY as part of the root config (`agents`,\n * `ui`, `devtools`, `jobs`, `openapi`) stay inline below. They have no\n * external consumers; splitting them would create lonely files (M5\n * smell) without comprehension benefit.\n */\nexport const theoConfigSchema = z\n .object({\n /**\n * Plan v1.2 T2.1 — project identifier propagated into\n * `.theokit/services.json` v2 `project` field. DNS-1123 compatible (drives\n * Gitea repo + ArgoCD App naming on TheoCloud). When omitted, the build\n * emits services.json v1 with the legacy `services-bundle` fallback\n * (ADR D10) and logs a deprecation warning.\n */\n name: z\n .string()\n .max(63)\n .refine(\n // DNS-1123 equivalent expressed as explicit single-char anchors so\n // security/detect-unsafe-regex stays clean (no backtracking).\n (value) =>\n value.length > 0 &&\n /^[a-z0-9-]+$/u.test(value) &&\n !value.startsWith('-') &&\n !value.endsWith('-'),\n 'name must match DNS-1123 (lowercase alphanumeric+hyphens, 1-63 chars, no leading/trailing hyphen)',\n )\n .optional(),\n appDir: z.string().default('app'),\n serverDir: z.string().default('server'),\n /**\n * Directory (relative to the project root) holding `agents/<name>.ts` definitions, scanned by\n * dev/build/terminal/mcp. Defaults to `\"agents\"` — apps that keep the canonical layout are\n * unaffected. Set to e.g. `\"core/agents\"` to organize agents under a domain root (#95 follow-up).\n */\n agentsDir: z.string().default('agents'),\n /**\n * T2.2 / EC-4 — Build output directory. Must be a relative path inside\n * the project root. Refused absolute or parent-relative paths to prevent\n * `cleanOutDir` from wiping arbitrary locations (defense-in-depth on\n * top of cleanOutDir's runtime EC-3 guard).\n */\n distDir: z\n .string()\n .default('.theokit')\n .refine(\n (d) => !/^([A-Za-z]:)?[/\\\\]/.test(d) && !d.startsWith('..'),\n 'distDir must be a relative path inside the project root (e.g., \".theokit\")',\n ),\n /**\n * Agent runtime configuration.\n *\n * - `maxRegistries` (T2.3, legacy): dev-mode cleanup of stale\n * `.theokit/agents/<id>/` dirs by mtime. Now superseded by SDK's\n * native registry GC but kept for backward-compat.\n * - `registry` (Phase 6, Production-Readiness #2): forwarded to\n * `Agent.registry.configure()` lazily on first request.\n * * `maxAgents` — LRU cap. MUST be ≥ max-concurrent-active-conversations\n * (EC-17 DOCUMENT): with maxAgents:1 and 2 concurrent chats, LRU evicts\n * mid-stream → SDK aborts with code:'aborted'. Default 100 covers\n * indie/small-team; tune up for high-traffic.\n * * `idleTimeoutMs` — auto-evict idle agents (default 30 min). 0 disables\n * idle eviction (LRU only).\n */\n agents: z\n .object({\n maxRegistries: z.number().int().positive().default(100),\n registry: z\n .object({\n /** LRU cap — MUST be ≥ max-concurrent-active-conversations. */\n maxAgents: z.number().int().positive().max(10_000).default(100),\n /** Idle eviction window in ms. 0 disables idle eviction (LRU only). */\n idleTimeoutMs: z\n .number()\n .int()\n .nonnegative()\n .default(30 * 60_000),\n })\n .optional(),\n })\n .optional(),\n port: z.number().int().min(1).max(65535).default(3000),\n /** Listen on all addresses (0.0.0.0) for LAN/mobile testing. */\n host: z.union([z.string(), z.boolean()]).default('localhost'),\n /** Automatically open browser on `theokit dev`. */\n open: z.union([z.boolean(), z.string()]).default(false),\n /** Exit if port is already in use instead of trying next available. */\n strictPort: z.boolean().default(false),\n /** Forward browser console/errors to terminal — useful for AI agent dev. */\n forwardConsole: z\n .union([\n z.boolean(),\n z.object({\n unhandledErrors: z.boolean().optional(),\n logLevels: z.array(z.enum(['error', 'warn', 'info', 'log', 'debug'])).optional(),\n }),\n ])\n .default(false),\n /** Pre-transform files on startup for faster first page load. */\n warmup: z\n .object({\n clientFiles: z.array(z.string()).optional(),\n ssrFiles: z.array(z.string()).optional(),\n })\n .optional(),\n ssr: z.boolean().default(false),\n /** When true (and ssr === true), use renderToPipeableStream with progressive\n * shell flush instead of single-shot renderToString. Opt-in for streaming\n * SSR; default false preserves the current behavior. */\n ssrStreaming: z.boolean().default(false),\n rateLimit: rateLimitSchema.optional(),\n upload: uploadSchema.optional(),\n logging: loggingSchema.optional(),\n security: securitySchema.optional(),\n serialization: z.enum(['json', 'superjson']).default('json'),\n // Plugins are validated structurally at runtime by createPluginRunnerFromConfig.\n // Zod only checks the shape minimally (must be array). Type-level safety is\n // provided through defineConfig at the user surface.\n plugins: z.array(z.unknown()).optional(),\n /** Enable client-side batching of theoFetch calls and the\n * /api/__theo_batch__ server endpoint. */\n batching: z\n .union([z.boolean(), z.object({ max: z.number().int().positive().optional() })])\n .optional(),\n /** T4.1 — Audit log. When `logger` is provided, framework events\n * (csrf.warn, rate-limit.exceeded, session.rotated, csp.violation) are\n * emitted to it. Default: noop. */\n audit: z\n .object({\n logger: z.unknown().optional(),\n })\n .optional(),\n /** TheoUI auto-wire (T2.1). `false` = opt-out; object = explicit theme/fonts;\n * undefined = enabled when @theokit/ui is detected in node_modules. */\n ui: z\n .union([\n z.literal(false),\n z.object({\n theme: z.enum(['violet-forge', 'noir', 'paper']).optional(),\n fonts: z.enum(['bundled', 'cdn']).optional(),\n }),\n ])\n .optional(),\n /**\n * Cache subsystem (caching-and-revalidation-plan).\n * Default `undefined` keeps caching disabled (backward compatible).\n * Pass `cache: {}` to opt in with defaults.\n */\n cache: cacheSchema.optional(),\n /**\n * Devtools overlay (Phase 0.4.0+ — see docs/plans/devtools-plan.md).\n *\n * - `undefined` (default): devtools auto-injects in `pnpm dev`, NEVER in `vite build`.\n * - `false`: devtools disabled entirely (Vite plugin skips injection even in dev).\n * - `{ ... }`: devtools enabled with explicit defaults (position, theme).\n *\n * Tree-shaken to noop in prod via the dual-export pattern in\n * `packages/theo/src/devtools/index.ts` (EC-17 positive prod check).\n */\n devtools: z\n .union([\n z.literal(false),\n z.object({\n position: z.enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']).optional(),\n theme: z.enum(['light', 'dark', 'system']).optional(),\n }),\n ])\n .optional(),\n /**\n * Informative list of deploy adapters the app supports. Does NOT\n * trigger per-build translations — only the `--target` CLI flag does\n * (EC-201 / ADR D2). If `config.adapters` includes a target NOT\n * matching `--target`, `theokit build` emits a cross-reference note.\n */\n adapters: z.array(z.string()).optional(),\n /**\n * Extra package names to pre-bundle via Vite's `optimizeDeps.include`.\n *\n * Framework auto-includes `@theokit/ui` and `lucide-react` when present.\n * Apps adding plugin peer-deps that rely on a runtime `import('<pkg>')`\n * (dynamic specifier) — e.g. `@theokit/plugin-canvas` consumers\n * installing `mermaid` for Mermaid SVG rendering — must declare those\n * here so Vite can resolve the literal in dev mode without\n * \"Failed to resolve module specifier\" errors. Production builds use\n * tsup/esbuild bundling and are not affected.\n *\n * Example:\n * viteOptimizeDeps: ['mermaid']\n */\n viteOptimizeDeps: z.array(z.string()).optional(),\n /**\n * Jobs backend (ADR D3 + T2.1). When configured, every request gets\n * `ctx.queue.enqueue` auto-wired via the outbox lifecycle. Pass a\n * `JobBackend` instance (InMemoryJobBackend, PostgresJobBackend, etc.).\n */\n jobs: z\n .object({\n backend: z.custom<unknown>((v) => typeof v === 'object' && v !== null),\n })\n .optional(),\n /**\n * StorageManager configuration (T1.1 / ADR-0007).\n *\n * Declares Postgres servers + databases + Redis servers. Consumed by\n * `getStorageManager().configure()` at boot via `start.ts`.\n *\n * Default `undefined` means manager exists but is not configured — adapters\n * relying on the manager (PostgresJobBackend.fromStorageManager, etc.) will\n * throw with an actionable error on first use.\n */\n storage: storageSchema.optional(),\n /**\n * Wave 2 — Polyglot services orchestration (T1.1 / ADR-0012/0013/0014/0015).\n *\n * Declarative external sidecar processes (Python FastAPI / Node Hono)\n * that boot alongside the TheoKit TS app. Empty `services: {}` is the\n * default and preserves Wave 1 behavior.\n */\n services: servicesConfigSchema,\n /**\n * G2 — OpenAPI emit (build-time only).\n *\n * When present, `theokit build` writes a generated `openapi.json` from\n * every `defineRoute()` body/query/params Zod schema. `undefined` keeps\n * the framework backward-compatible (no emit). Pass `openapi: {}` to\n * opt in with defaults.\n *\n * Defaults: spec 3.1.0 · servers `http://localhost:3000` · title\n * \"TheoKit App\" · version \"0.0.0\" · outDir \".theokit\" (next to dist).\n *\n * The env var `THEOKIT_OPENAPI_SERVERS` (CSV of URLs) overrides\n * `servers[].url` at emit time without rebuilding the config.\n */\n openapi: z\n .object({\n servers: z\n .array(\n z.object({\n url: z.url(),\n description: z.string().optional(),\n }),\n )\n .default([{ url: 'http://localhost:3000', description: 'Local development' }]),\n specVersion: z.enum(['3.1.0', '3.0.3']).default('3.1.0'),\n title: z.string().default('TheoKit App'),\n version: z.string().default('0.0.0'),\n outDir: z.string().default('.theokit'),\n })\n .optional(),\n /**\n * G5 T1.3 — error envelope transformer hook (blueprint ADR D3).\n *\n * When present, runs at framework error-boundary time to enrich the\n * envelope with consumer-defined extensions (`hint`, custom telemetry\n * tags, etc.) BEFORE the envelope is serialized to the client. The\n * function signature is preserved via the explicit `FormatErrorHook`\n * type — TS inference flows from `theo.config.ts` into `@theo/client`\n * codegen and `@theokit/ui` AgentErrorCard consumers.\n *\n * Use `z.custom<FormatErrorHook>(...)` because Zod's built-in\n * `z.function()` discards its TS signature after parse; `z.custom`\n * with a function-typed runtime guard preserves the call-site type\n * without trading off Zod runtime validation.\n */\n formatError: z\n .custom<FormatErrorHook>((val) => typeof val === 'function', {\n message: 'formatError must be a function',\n })\n .optional(),\n })\n // EC-2 fix: cross-config refine — no service may share TheoKit's web port.\n .refine((cfg) => !Object.values(cfg.services).some((s) => s.port === cfg.port), {\n message: 'service.port collides with TheoKit web port — change one of them',\n path: ['services'],\n })\n\nexport type TheoConfig = z.infer<typeof theoConfigSchema>\n\n// Silence unused-import warnings for type-only re-exports — TS strips at compile,\n// but exports above re-introduce them for downstream consumers.\ntype _FormatErrorContext = FormatErrorContext\n","import { z } from 'zod'\n\n/**\n * Base bucket config — legacy shape preserved for backwards compatibility.\n */\nconst baseRateLimitSchema = z.object({\n windowMs: z.number().min(1),\n max: z.number().int().min(1),\n})\n\n/**\n * T2.2 — Per-route + per-user rate limit. The new shape adds `routes`\n * (path map), `keyBy`, and `cookieName`. The legacy flat shape is still\n * accepted via the union — see `createRouteRateLimiter` for normalization.\n */\nexport const rateLimitSchema = z.union([\n baseRateLimitSchema,\n z.object({\n default: baseRateLimitSchema.optional(),\n routes: z.record(z.string(), baseRateLimitSchema).optional(),\n keyBy: z\n .union([\n z.enum(['ip', 'session', 'user']),\n z.function({ input: z.tuple([z.unknown()]), output: z.string() }),\n ])\n .optional(),\n cookieName: z.string().min(1).optional(),\n }),\n])\n","import { z } from 'zod'\n\nexport const uploadSchema = z.object({\n maxFileSize: z\n .number()\n .min(1)\n .default(10 * 1024 * 1024), // 10MB\n maxFiles: z.number().int().min(1).default(10),\n maxFieldSize: z\n .number()\n .min(1)\n .default(1 * 1024 * 1024), // 1MB\n})\n","import { z } from 'zod'\n\nexport const loggingSchema = z.object({\n level: z.enum(['debug', 'info', 'warn', 'error', 'silent']).default('info'),\n})\n","import { z } from 'zod'\n\n/**\n * Cache subsystem config (caching-and-revalidation-plan).\n * Default `cache: undefined` keeps the framework backward-compatible\n * (no engine initialized → no cache primitives available).\n *\n * Setting `cache: {}` opts in with all defaults.\n */\nconst routeRuleSchema = z.object({\n maxAge: z.number().nonnegative().finite().optional(),\n swr: z.number().nonnegative().finite().optional(),\n tags: z.array(z.string()).optional(),\n})\n\nexport const cacheSchema = z.object({\n enabled: z.boolean().default(true),\n /** 'memory' uses InMemoryCacheAdapter; otherwise pass a custom adapter instance. */\n storage: z.union([z.literal('memory'), z.custom<unknown>()]).default('memory'),\n maxEntries: z.number().int().positive().default(1000),\n defaults: z\n .object({\n maxAge: z.number().nonnegative().finite().default(1),\n swr: z.number().nonnegative().finite().optional(),\n cacheErrors: z.boolean().default(false),\n })\n .default({ maxAge: 1, cacheErrors: false }),\n keyDerivation: z\n .object({\n excludeQuery: z.array(z.string()).optional(),\n sortQuery: z.boolean().default(true),\n lowercaseHost: z.boolean().default(true),\n })\n .default({ sortQuery: true, lowercaseHost: true }),\n routeRules: z.record(z.string(), routeRuleSchema).optional(),\n})\n","import { z } from 'zod'\n\nimport { headerSafeString } from './header-safe.js'\n\n/**\n * Phase 5 — CSRF warn-first (EC-1).\n *\n * 0.2.0 default: `warn`. Existing apps keep working but get structured\n * warnings about every state-mutating request that does not carry the\n * `X-Theo-Action: 1` header. 0.3.0 will flip the default to `strict`.\n *\n * Set explicitly to `strict` to opt into the future default early,\n * or `off` to disable CSRF entirely (only valid when you have another\n * defense — bearer auth, no session cookies, etc).\n */\n\n/**\n * Phase 6 — Default security headers (D4 / EC-2).\n *\n * 0.2.0 defaults:\n * - CSP in `report-only` mode (EC-2: don't break existing apps)\n * - X-Frame-Options: DENY · X-Content-Type-Options: nosniff\n * - Referrer-Policy: strict-origin-when-cross-origin\n * - HSTS in production only (no TLS on localhost)\n *\n * Users override individual headers, swap CSP to `enforce`, or disable\n * CSP entirely (`csp: false` / `cspMode: 'off'`).\n */\nexport const securityHeadersSchema = z.object({\n csp: z.union([headerSafeString, z.literal(false)]).optional(),\n // T6.1 — default flipped from 'report-only' to 'enforce' for 0.3.0.\n // Users who want the old behaviour set `cspMode: 'report-only'`\n // explicitly. See docs/migrating/0.2-to-0.3.md.\n cspMode: z.enum(['enforce', 'report-only', 'off']).default('enforce'),\n hsts: z.union([headerSafeString, z.literal(false)]).optional(),\n frameOptions: z.enum(['DENY', 'SAMEORIGIN']).default('DENY'),\n contentTypeOptions: z.literal('nosniff').default('nosniff'),\n referrerPolicy: headerSafeString.default('strict-origin-when-cross-origin'),\n /**\n * T1.1 — Permissions-Policy directive string. EC-3-refined: rejects CR/LF.\n * Pass `false` to suppress the header.\n */\n permissionsPolicy: z.union([headerSafeString, z.literal(false)]).optional(),\n})\n\n/**\n * T5.1 — Disallowed-routes escalation pattern (Rails-inspired).\n *\n * `routes` accepts string (exact match — trailing slash matters) or\n * RegExp entries. Matched routes that would otherwise emit `csrf.warn`\n * dispatch through `disallowedBehavior` instead:\n * - `'warn'` : no-op vs the default warn-mode behavior\n * - `'raise'` : escalate to 403, even when global `csrf` mode is 'warn'\n *\n * Use to roll out strict mode per-route (e.g., flip /api/auth/* first)\n * without committing the entire surface to strict at once.\n */\nconst disallowedConfigSchema = z.object({\n routes: z.array(z.union([z.string(), z.instanceof(RegExp)])),\n behavior: z.enum(['warn', 'raise']).default('raise'),\n})\n\n/**\n * T1.2 — CORS configuration.\n *\n * `origins` accepts a single value (`'*'`, string, RegExp, callback) OR an\n * array of (string | RegExp). The spec-violating `origins: '*'` +\n * `credentials: true` combination is rejected at parse time (browsers\n * ignore wildcards when credentials are sent).\n *\n * EC-3 — `allowedHeaders` and `exposedHeaders` entries go through the\n * header-safe refinement (CR/LF rejected — CWE-113 mitigation).\n */\nexport const corsSchema = z\n .object({\n origins: z.union([\n z.literal('*'),\n headerSafeString,\n z.instanceof(RegExp),\n z.array(z.union([headerSafeString, z.instanceof(RegExp)])),\n z.function({ input: z.tuple([z.string()]), output: z.boolean() }),\n ]),\n methods: z\n .array(z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD']))\n .optional(),\n allowedHeaders: z.array(headerSafeString).optional(),\n exposedHeaders: z.array(headerSafeString).optional(),\n credentials: z.boolean().default(false),\n maxAge: z.number().int().min(0).max(86400).default(600),\n })\n .refine((c) => !(c.origins === '*' && c.credentials), {\n message: 'CORS spec forbids origins:\"*\" with credentials:true — browsers ignore the wildcard',\n })\n\nexport const securitySchema = z.object({\n // T6.1 — default flipped from 'warn' to 'strict' for 0.3.0. Apps that\n // grep their warn-mode logs from 0.2.x already know which endpoints\n // break; opt back into 'warn' globally OR use disallowedRoutes for\n // surgical migration. See docs/migrating/0.2-to-0.3.md.\n csrf: z.enum(['off', 'warn', 'strict']).default('strict'),\n headers: securityHeadersSchema.optional(),\n /** T5.1 — per-route escalation (Rails disallowed_warnings pattern). */\n disallowed: disallowedConfigSchema.optional(),\n /** T1.2 — Cross-Origin Resource Sharing. Single global config; runs first in pipeline. */\n cors: corsSchema.optional(),\n})\n","import { z } from 'zod'\n\n/**\n * EC-3 — CWE-113 HTTP Response Splitting mitigation.\n *\n * Every string that becomes a header value must reject CR/LF. Apps that\n * derive header values from untrusted input (feature flags, tenant config,\n * URL params) would otherwise let attackers inject Set-Cookie / Location\n * headers via `\\r\\n`. Apply this refinement to every header-bound string\n * field: permissionsPolicy, csp, hsts, referrerPolicy, CORS allow/expose.\n */\nexport const headerSafeString = z\n .string()\n .refine((s) => !/[\\r\\n]/.test(s), { message: 'Header value must not contain CR/LF' })\n","import { z } from 'zod'\n\n/**\n * StorageManager schemas (T1.1 / ADR-0007 D4).\n *\n * `theo.config.ts > storage` declares Postgres servers (credentials), the\n * databases on each server (TheoCloud / managed PG / self-host), and Redis\n * servers. The runtime `StorageManager` consumes this block; adapters\n * (PostgresJobBackend, PostgresConversationStorage, etc.) request pools by\n * database name and never see raw credentials at the call site.\n *\n * EC-1 (DOCUMENT in concept doc T4.1): Zod default strip-unknown mode\n * silently drops typo keys (`databasees` instead of `databases`). The\n * concept doc warns users to use exact names; runtime errors are still\n * actionable (`Database \"X\" not configured`).\n *\n * EC-2 (DEFERRED to use-time): `databases.X.server` references a key in\n * `servers`. Cross-field validation is intentionally NOT enforced at parse\n * time — `StorageManager.usePostgres()` throws an actionable error on the\n * first call with the dangling reference, matching Rails / Nitro behavior.\n */\nconst tlsConfigSchema = z.object({\n rejectUnauthorized: z.boolean().optional(),\n caCert: z.string().optional(),\n clientCert: z.string().optional(),\n clientKey: z.string().optional(),\n})\n\nconst serverConfigSchema = z.object({\n host: z.string().min(1),\n port: z.number().int().positive().max(65535).optional(),\n user: z.string().min(1),\n /** Password may be the empty string (some providers permit it). */\n password: z.string(),\n tls: tlsConfigSchema.optional(),\n})\n\nconst postgresPoolConfigSchema = z.object({\n min: z.number().int().nonnegative().optional(),\n max: z.number().int().positive().optional(),\n connectionTimeoutMillis: z.number().int().positive().optional(),\n idleTimeoutMillis: z.number().int().nonnegative().optional(),\n})\n\nconst postgresDatabaseConfigSchema = z.object({\n /** References a key in `storage.servers`. Resolved at `usePostgres()` call time. */\n server: z.string().min(1),\n database: z.string().min(1),\n pool: postgresPoolConfigSchema.optional(),\n})\n\nconst redisServerConfigSchema = serverConfigSchema.extend({\n db: z.number().int().nonnegative().optional(),\n maxRetriesPerRequest: z.number().int().nonnegative().optional(),\n})\n\nexport const storageSchema = z.object({\n servers: z.record(z.string(), serverConfigSchema).optional(),\n databases: z.record(z.string(), postgresDatabaseConfigSchema).optional(),\n redis: z.record(z.string(), redisServerConfigSchema).optional(),\n})\n\nexport type StorageConfig = z.infer<typeof storageSchema>\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/devtools/server-side/redact.ts","../src/devtools/server-side/broadcast.ts"],"sourcesContent":["/**\n * T2.3 — Privacy redaction for devtools broadcasts.\n *\n * Pure helpers. NO side effects.\n *\n * - EC-18: redactQueryString — `?token=`, `?api_key=`, etc → '[REDACTED]'\n * - EC-19: truncateBody — accepts unknown; binary → '[binary body]'\n * - EC-26: serializeSafely — BigInt walker (recursive)\n * - redactHeaders — Authorization, Cookie, Set-Cookie, etc → '[REDACTED]'\n *\n * NEVER use dangerouslySetInnerHTML in any devtools component — see plan EC-20.\n */\n\nconst REDACTED_HEADERS = new Set([\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'x-auth-token',\n 'proxy-authorization',\n])\n\nconst REDACTED_QUERY_KEYS = new Set([\n 'token',\n 'api_key',\n 'password',\n 'secret',\n 'auth',\n 'access_token',\n])\n\nconst REDACTED_VALUE = '[REDACTED]'\nconst REDACTED_QUERY_VALUE = '%5BREDACTED%5D' // URL-encoded form\n\nexport function redactHeaders(\n h: Record<string, string | string[] | undefined>,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [k, v] of Object.entries(h)) {\n if (v === undefined) continue\n if (REDACTED_HEADERS.has(k.toLowerCase())) {\n out[k] = REDACTED_VALUE\n } else {\n out[k] = Array.isArray(v) ? v.join(', ') : v\n }\n }\n return out\n}\n\n/**\n * EC-19: type-safe across string / Buffer / FormData / Blob / undefined.\n * Non-string bodies surface as a placeholder; never crash on .slice().\n */\nexport function truncateBody(\n body: unknown,\n max = 4096,\n): { preview: string; length: number; truncated: boolean } {\n if (body === null || body === undefined) {\n return { preview: '', length: 0, truncated: false }\n }\n if (typeof body !== 'string') {\n return { preview: '[binary body]', length: 0, truncated: true }\n }\n const length = body.length\n if (length <= max) return { preview: body, length, truncated: false }\n return { preview: body.slice(0, max), length, truncated: true }\n}\n\n/**\n * EC-18: scrub sensitive keys from the URL's query string.\n * Case-insensitive match on key names (after URL-decode).\n */\nexport function redactQueryString(path: string): string {\n const qIndex = path.indexOf('?')\n if (qIndex === -1) return path\n const base = path.slice(0, qIndex)\n const query = path.slice(qIndex + 1)\n if (query.length === 0) return path\n const parts = query.split('&').map((pair) => {\n const eqIndex = pair.indexOf('=')\n if (eqIndex === -1) return pair\n const key = pair.slice(0, eqIndex)\n let decodedKey = key\n try {\n decodedKey = decodeURIComponent(key)\n } catch {\n // Malformed encoding — fall back to raw key\n }\n if (REDACTED_QUERY_KEYS.has(decodedKey.toLowerCase())) {\n return `${key}=${REDACTED_QUERY_VALUE}`\n }\n return pair\n })\n return `${base}?${parts.join('&')}`\n}\n\n/**\n * EC-26: BigInt → '<n>n' string. Recursive walk for arrays and plain objects.\n * Returns a NEW value (does not mutate the input).\n *\n * Limitations:\n * - Functions, Symbols, Promises, class instances → returned as-is (broadcaster\n * will likely silently drop them via JSON.stringify default behavior).\n * - Cycles → would loop forever; defensive seen-set caps recursion.\n */\nexport function serializeSafely(value: unknown, seen = new WeakSet()): unknown {\n if (typeof value === 'bigint') return `${value.toString()}n`\n if (value === null || value === undefined) return value\n if (typeof value !== 'object') return value\n if (seen.has(value)) return '[Circular]'\n seen.add(value)\n if (Array.isArray(value)) {\n return value.map((v) => serializeSafely(v, seen))\n }\n // Treat plain objects only — class instances pass through unchanged.\n // `getPrototypeOf` returns `unknown` under strict typing; we only need\n // the identity check against `Object.prototype`.\n const proto: unknown = Object.getPrototypeOf(value)\n if (proto !== null && proto !== Object.prototype) return value\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = serializeSafely(v, seen)\n }\n return out\n}\n","/**\n * T2.1 + T2.3 + T2.4 — Server-side broadcast helper.\n *\n * `globalThis.__theoViteHotServer` is populated by the Vite plugin's\n * `configureServer` hook (T2.4) when dev mode is active. The helper:\n * - no-ops if the global is undefined (production, build, no dev server)\n * - applies redaction (T2.3) before sending — secrets never enter the WS payload\n * - wraps the whole send in try/catch to prevent ws.send failures from\n * leaking out and crashing the request handler\n *\n * NEVER use dangerouslySetInnerHTML in any devtools component — see plan EC-20.\n */\nimport type { RequestRecord, CsrfWarnPayload, ErrorRecord } from '../shared.js'\n\nimport { redactHeaders, redactQueryString, serializeSafely, truncateBody } from './redact.js'\n\ninterface ViteWsLike {\n ws?: {\n send(payload: { type: 'custom'; event: string; data: unknown }): void\n }\n httpServer?: unknown\n}\n\nfunction getViteServer(): ViteWsLike | undefined {\n const g = globalThis as { __theoViteHotServer?: ViteWsLike }\n return g.__theoViteHotServer\n}\n\n/**\n * Send a typed event to the devtools UI over Vite's HMR WebSocket.\n *\n * Default-deny — ALL errors (server gone, redact throws, ws.send fails)\n * result in a silent no-op + console.warn. Never throws to caller.\n */\nexport function broadcastToDevtools(event: string, data: unknown): void {\n try {\n const server = getViteServer()\n if (!server?.ws) return\n // Safe-serialize: convert BigInt; pure pass-through otherwise.\n const safe = serializeSafely(data)\n server.ws.send({ type: 'custom', event, data: safe })\n } catch (err) {\n console.warn('[theo devtools] broadcast failed', err)\n }\n}\n\n/**\n * Convenience: redact a RequestRecord before broadcasting.\n *\n * Applies:\n * - EC-18: redactQueryString on path\n * - redactHeaders on headers\n * - EC-19: truncateBody (binary-safe)\n * - EC-26: serializeSafely (BigInt walk) inside broadcastToDevtools\n */\nexport function broadcastRequest(req: RequestRecord): void {\n const safePath = redactQueryString(req.path)\n const safeHeaders = req.headers ? redactHeaders(req.headers) : undefined\n const bodyInfo = truncateBody(req.bodyPreview)\n const sanitized: RequestRecord = {\n ...req,\n path: safePath,\n headers: safeHeaders,\n bodyPreview: bodyInfo.preview,\n bodyLength: bodyInfo.length,\n bodyTruncated: bodyInfo.truncated,\n }\n broadcastToDevtools('theo:devtools:request', sanitized)\n}\n\nexport function broadcastError(err: ErrorRecord): void {\n broadcastToDevtools('theo:devtools:error', err)\n}\n\nexport function broadcastCsrfWarn(payload: CsrfWarnPayload): void {\n // CSRF payload has no secret-ish fields, but the path may carry tokens.\n const safe: CsrfWarnPayload = { ...payload, path: redactQueryString(payload.path) }\n broadcastToDevtools('theo:devtools:csrf.warn', safe)\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/import-user-module.ts"],"sourcesContent":["/**\n * Helper for loading user-authored TypeScript modules at runtime.\n *\n * Why this exists: theokit framework code (`load-config.ts`, `job-scan.ts`,\n * `cron-scan.ts`, `integrate-ui.ts`, `static.ts`) dynamically imports\n * `.ts` files from user space (`theo.config.ts`, `server/jobs/*.ts`,\n * `static-paths.ts`, etc.). Two execution environments must work:\n *\n * 1. **Production CLI** — `dist/cli/index.js` starts with\n * `import \"tsx/esm\"` which registers a global Node ESM loader hook.\n * Subsequent `await import('foo.ts')` calls are intercepted by the\n * hook, transformed in-place, and returned as ESM namespaces.\n *\n * 2. **Vitest tests** — Vitest runs framework code through Vite's SSR\n * pipeline. Dynamic imports inside framework modules are hijacked\n * by Vite's `loadAndTransform`, which cannot resolve absolute paths\n * outside the Vite project root (e.g., `/tmp/test-fixture/foo.ts`).\n * Even with `server.deps.external` configured to hand the path\n * back to Node, the registered tsx/esm loader hits a `require()`\n * ESM cycle error on Node 22 because the calling stack contains\n * both the loader's own evaluation context AND the importer.\n *\n * `tsImport()` from `tsx/esm/api` is the documented escape hatch for\n * exactly this scenario: it transforms the source file via tsx's\n * standalone pipeline and evaluates the result via a fresh namespace,\n * bypassing both Vite SSR and any registered global hook.\n *\n * Strategy:\n * - Try native `await import()` first (zero overhead in production\n * where tsx hook is registered).\n * - On failure with the well-known cycle/resolution errors, fall back\n * to `tsImport()`. Other errors (genuine syntax errors, missing\n * module, etc.) propagate unchanged.\n *\n * Idempotent and side-effect-free.\n */\nimport { pathToFileURL } from 'node:url'\n\nconst CYCLE_PATTERNS = [\n // Node 22 strict ESM cycle detection when a registered loader hook\n // re-enters its own evaluation context.\n 'require() ES Module',\n 'in a cycle',\n // Vite SSR throws this when it cannot resolve an out-of-root URL.\n 'Failed to load url',\n 'Does the file exist?',\n // Node native ESM resolver throws this for `.ts` files when no\n // tsx loader is registered globally (the common test-worker case).\n 'Cannot find module',\n // ERR_UNKNOWN_FILE_EXTENSION for `.ts` files.\n 'Unknown file extension',\n]\n\nfunction isLoaderInteropError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n const msg = err.message\n return CYCLE_PATTERNS.some((p) => msg.includes(p))\n}\n\n/**\n * Load a user-authored TS/JS module at the given absolute file path.\n * `parentURL` defaults to the URL of this module file.\n *\n * @returns module namespace object (matches `await import(...)` return)\n */\nexport async function importUserModule(\n absoluteFilePath: string,\n parentURL: string = import.meta.url,\n): Promise<Record<string, unknown>> {\n const fileURL = pathToFileURL(absoluteFilePath).href\n try {\n return (await import(fileURL)) as Record<string, unknown>\n } catch (err) {\n if (!isLoaderInteropError(err)) throw err\n // Fallback: tsx programmatic API. Imports are inline, no global hook\n // mutation, no Vite SSR interference. Slower per call (~10-50ms vs\n // microseconds for registered loader) but only used as a last resort.\n const { tsImport } = (await import('tsx/esm/api')) as {\n tsImport: (\n specifier: string,\n options: string | { parentURL: string; tsconfig?: string; namespace?: string },\n ) => Promise<Record<string, unknown>>\n }\n // Bypass tsconfig — tsx's default bundler-style resolver handles\n // `.js → .ts` fallback for relative imports under the user's module.\n // Passing an explicit tsconfig sometimes shadows the default and\n // breaks the `.js → .ts` rewrite chain inside the namespaced loader\n // (verified empirically in cron-scan/job-scan vitest workers).\n return await tsImport(fileURL, parentURL)\n }\n}\n"],"mappings":";AAoCA,SAAS,qBAAqB;AAE9B,IAAM,iBAAiB;AAAA;AAAA;AAAA,EAGrB;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EAEA;AACF;AAEA,SAAS,qBAAqB,KAAuB;AACnD,MAAI,EAAE,eAAe,OAAQ,QAAO;AACpC,QAAM,MAAM,IAAI;AAChB,SAAO,eAAe,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC,CAAC;AACnD;AAQA,eAAsB,iBACpB,kBACA,YAAoB,YAAY,KACE;AAClC,QAAM,UAAU,cAAc,gBAAgB,EAAE;AAChD,MAAI;AACF,WAAQ,MAAM,OAAO;AAAA,EACvB,SAAS,KAAK;AACZ,QAAI,CAAC,qBAAqB,GAAG,EAAG,OAAM;AAItC,UAAM,EAAE,SAAS,IAAK,MAAM,OAAO,aAAa;AAWhD,WAAO,MAAM,SAAS,SAAS,SAAS;AAAA,EAC1C;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/rate-limit/rate-limit-per-route.ts"],"sourcesContent":["// T5a.1d — Web Crypto migration. The last node:crypto consumer in server/.\n// `createHash('sha256')` is sync but Web Crypto's `subtle.digest('SHA-256', ...)`\n// is async. This propagates through hashFragment → deriveKey → the factory's\n// returned checker. createRouteRateLimiter has NO production consumers\n// (verified via grep; api-middleware uses the sibling createRateLimiter from\n// rate-limit.ts), so the cascade only affects test sites. IncomingMessage stays\n// as a type-only import (TS-erased; runtime-clean).\nimport type { IncomingMessage } from 'node:http'\n\nimport { parseCookieHeader } from '../http/cookies.js'\n\nimport { InMemoryStore, type RateLimitStore } from './rate-limit-store.js'\nimport type { RateLimitConfig, RateLimitResult } from './rate-limit.js'\n\n/**\n * T2.2 — Per-route + per-user rate limiting.\n *\n * Layered on top of `rate-limit-store.ts`. The route map allows\n * declarative policies (\"strict /api/login, loose everything else\")\n * driven by config, not handler-decorated. `keyBy` selects what\n * identifier the limiter buckets on.\n *\n * ADR D2: per-route via path matching, NOT per-handler decorator.\n * Operators can tune policies without touching route definitions.\n */\n\nexport type KeyByMode = 'ip' | 'session' | 'user' | ((req: IncomingMessage) => string)\n\nexport interface RouteRateLimitConfig {\n /** Fallback config used when no per-route entry matches. */\n default?: RateLimitConfig\n /** Map of path pattern → config. Exact-string keys (RegExp via API). */\n routes?: Record<string, RateLimitConfig>\n /** Same as `routes` but each entry is a [pattern, config] tuple, RegExp allowed. */\n routePatterns?: readonly [string | RegExp, RateLimitConfig][]\n /** Bucket identifier strategy. Default 'ip'. */\n keyBy?: KeyByMode\n /** Cookie name used by keyBy='session'. Defaults to 'theo_session'. */\n cookieName?: string\n /** Optional shared store (for multi-route correlation). Default per-limiter InMemoryStore. */\n store?: RateLimitStore\n}\n\n/**\n * Normalize a path for matching: strip query string, drop trailing slash\n * unless root. EC-5: `/api/login` and `/api/login/` collapse to the same\n * canonical form so attackers can't bypass strict limits.\n */\nfunction normalizePath(input: string): string {\n const noQuery = input.split('?')[0]\n if (noQuery.length > 1 && noQuery.endsWith('/')) return noQuery.slice(0, -1)\n return noQuery\n}\n\n/**\n * Test whether `path` matches `pattern`. String patterns are compared\n * after trailing-slash normalization (EC-5). RegExp uses `.test` after\n * resetting `lastIndex` (defensive against `/g` flag).\n */\nexport function matchRoutePattern(path: string, pattern: string | RegExp): boolean {\n const canonical = normalizePath(path)\n if (typeof pattern === 'string') {\n return canonical === normalizePath(pattern)\n }\n pattern.lastIndex = 0\n return pattern.test(canonical)\n}\n\n/**\n * Hash a string with SHA-256 and return the first 16 base64url chars.\n * Used by `keyBy='session'` so the raw cookie value never lands in a\n * rate-limit key (which may flow into audit logs).\n *\n * T5a.1d — async via Web Crypto subtle.digest (no node:crypto). The\n * base64url encoding is done manually because btoa+url-safe transform is\n * available everywhere but `digest('base64url')` is Node-only.\n */\nasync function hashFragment(input: string): Promise<string> {\n const buf = await globalThis.crypto.subtle.digest('SHA-256', new TextEncoder().encode(input))\n const bytes = new Uint8Array(buf)\n let bin = ''\n for (const b of bytes) bin += String.fromCharCode(b)\n // eslint-disable-next-line sonarjs/slow-regex -- input is fixed-length 44 chars (SHA-256 base64), trailing '=' padding ≤ 2 chars, no ReDoS surface\n const b64url = btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n return b64url.slice(0, 16)\n}\n\n// T3.2 DRY consolidation: cookie parsing moved to ../http/cookies.ts.\n// The canonical `parseCookieHeader` returns a Map for O(1) lookup; this\n// wrapper preserves the original `readCookie(req, name)` signature so the\n// rest of the file stays untouched.\nfunction readCookie(req: IncomingMessage, name: string): string | undefined {\n return parseCookieHeader(req.headers.cookie ?? undefined).get(name)\n}\n\n/**\n * Build the rate-limit bucket key for the request based on `keyBy`.\n *\n * EC-6: session mode reads the configured `cookieName`. With the wrong\n * cookie name (e.g., default 'theo_session' but app uses 'app_session'),\n * we fall back to IP so anonymous users still get rate-limited rather\n * than sharing an empty bucket.\n */\nexport async function deriveKey(\n req: IncomingMessage,\n keyBy: KeyByMode,\n cookieName: string,\n): Promise<string> {\n if (typeof keyBy === 'function') return keyBy(req)\n // `req.socket` is typed as always-present in Node typings, but in test\n // doubles (object literals without `socket`) it can be missing — the\n // optional chain keeps the fallback path reachable.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- defensive for test doubles\n const ip = req.socket?.remoteAddress ?? 'unknown'\n switch (keyBy) {\n case 'session': {\n const cookie = readCookie(req, cookieName)\n return cookie ? `session:${await hashFragment(cookie)}` : `ip:${ip}`\n }\n case 'user': {\n const userId = (req as unknown as { user?: { id?: string } }).user?.id\n return userId ? `user:${userId}` : `ip:${ip}`\n }\n case 'ip':\n default:\n return `ip:${ip}`\n }\n}\n\n/**\n * Per-route rate limiter factory. Returns a sync checker compatible with\n * the existing api-middleware shape.\n *\n * Backwards-compatibility (ADR D2): a flat `{ windowMs, max }` config is\n * accepted and treated as `default` (no per-route variants).\n */\nexport function createRouteRateLimiter(config: RouteRateLimitConfig | RateLimitConfig) {\n // Detect legacy flat shape\n const isFlat =\n 'windowMs' in config && 'max' in config && !('default' in config) && !('routes' in config)\n const cfg: RouteRateLimitConfig = isFlat ? { default: config } : config\n\n const store = cfg.store ?? new InMemoryStore()\n // CR-005: validate store shape ONCE at construction. The previous\n // implementation ran `instanceof InMemoryStore` on every request and\n // threw at request-time if a non-InMemoryStore was passed — which\n // turned a clear config error into a runtime 500 on the first request.\n if (!(store instanceof InMemoryStore)) {\n throw new Error(\n 'createRouteRateLimiter: async RateLimitStore implementations require a dedicated async middleware path. ' +\n 'Use the InMemoryStore default for the sync façade.',\n )\n }\n const inMemoryStore = store\n const keyBy = cfg.keyBy ?? 'ip'\n const cookieName = cfg.cookieName ?? 'theo_session'\n\n // Build a pre-compiled list of (pattern, config) tuples for matching.\n const patternList: [string | RegExp, RateLimitConfig][] = []\n if (cfg.routes) {\n for (const [pattern, c] of Object.entries(cfg.routes)) patternList.push([pattern, c])\n }\n if (cfg.routePatterns) {\n for (const tuple of cfg.routePatterns) patternList.push(tuple)\n }\n\n return async function checkRouteRateLimit(req: IncomingMessage): Promise<RateLimitResult> {\n const url = req.url ?? ''\n let matched: RateLimitConfig | undefined\n for (const [pattern, c] of patternList) {\n if (matchRoutePattern(url, pattern)) {\n matched = c\n break\n }\n }\n const effective = matched ?? cfg.default\n if (!effective) {\n // No route match + no default → not limited.\n return { limited: false, headers: {} }\n }\n\n // Bucket key includes normalized path so /api/login and /api/login/\n // collapse to the same bucket (EC-5).\n const bucketSuffix = typeof matched === 'undefined' ? '*default*' : normalizePath(url)\n const key = `${await deriveKey(req, keyBy, cookieName)}|${bucketSuffix}`\n const state = inMemoryStore.incrSync(key, effective.windowMs)\n\n if (state.count > effective.max) {\n const retryAfter = Math.ceil((state.resetAt - Date.now()) / 1000)\n return {\n limited: true,\n headers: {\n 'X-RateLimit-Limit': String(effective.max),\n 'X-RateLimit-Remaining': '0',\n 'Retry-After': String(retryAfter),\n },\n }\n }\n return {\n limited: false,\n headers: {\n 'X-RateLimit-Limit': String(effective.max),\n 'X-RateLimit-Remaining': String(Math.max(0, effective.max - state.count)),\n },\n }\n }\n}\n\n/**\n * T5a.2 Phase D slice 1/3 — Web-Standards rate-limiter inputs context.\n *\n * Web `Request` has no equivalent of `req.socket.remoteAddress` (Node\n * runtime concept) or `req.user` (set by upstream middleware). The\n * Web-shaped rate-limiter requires the caller to pass these explicitly:\n *\n * - `clientIp` — resolved per-runtime (Node: `socket.remoteAddress`;\n * CF Workers: `request.headers.get('cf-connecting-ip')`; Vercel:\n * `x-forwarded-for` first hop; Bun/Deno: adapter-specific).\n * - `userId` — resolved by auth middleware (Phase D slice 3/3 ships\n * the Web-shaped session helper).\n *\n * Defaults: `clientIp = 'unknown'`, `userId = undefined` (matches the\n * IncomingMessage path's fallback semantics).\n */\nexport interface DeriveKeyRequestContext {\n clientIp?: string\n userId?: string\n}\n\n/**\n * T5a.2 Phase D slice 1/3 — Web-Standards-shaped key derivation.\n *\n * Mirror of `deriveKey(req: IncomingMessage, keyBy, cookieName)` for the\n * Web `Request` shape. Same `'ip' | 'session' | 'user'` enum cases (the\n * `function` callback case is IncomingMessage-only because the existing\n * `KeyByMode` callback type is Node-shaped; Web callers use the enum\n * cases or call a future `KeyByModeWeb` shape — out of T5a.2 Phase D scope).\n *\n * Uses `getCookieFromRequest` (Phase B slice 6/6) for session-mode cookie\n * lookup. Cookie parsing has the same CR-009 percent-encoding safety.\n */\nexport async function deriveKeyFromRequest(\n request: Request,\n keyBy: Exclude<KeyByMode, (req: IncomingMessage) => string>,\n cookieName: string,\n ctx: DeriveKeyRequestContext = {},\n): Promise<string> {\n const ip = ctx.clientIp ?? 'unknown'\n switch (keyBy) {\n case 'session': {\n // Reuse the Web cookie helper extracted in Phase B slice 6/6 so\n // CR-009 percent-encoding sanity stays consistent across paths.\n const { getCookieFromRequest } = await import('../http/cookies.js')\n const cookie = getCookieFromRequest(request, cookieName)\n return cookie ? `session:${await hashFragment(cookie)}` : `ip:${ip}`\n }\n case 'user': {\n return ctx.userId ? `user:${ctx.userId}` : `ip:${ip}`\n }\n case 'ip':\n default:\n return `ip:${ip}`\n }\n}\n\n/**\n * T5a.2 Phase D slice 1/3 — Web-Standards rate-limiter factory.\n *\n * Mirror of `createRouteRateLimiter(config)` returning a checker that\n * accepts `(request: Request, ctx?: DeriveKeyRequestContext)` instead of\n * `(req: IncomingMessage)`. Same `RouteRateLimitConfig` accepted; same\n * `keyBy` enum cases; same `InMemoryStore` constraint (CR-005 guard).\n *\n * Same returned `RateLimitResult` shape (headers + limited boolean).\n *\n * Web `Request` has no `req.url` path-only property — uses\n * `new URL(request.url).pathname + search` to derive the URL the way the\n * IncomingMessage path's `req.url ?? ''` would.\n */\nexport function createRouteRateLimiterWeb(config: RouteRateLimitConfig | RateLimitConfig) {\n const isFlat =\n 'windowMs' in config && 'max' in config && !('default' in config) && !('routes' in config)\n const cfg: RouteRateLimitConfig = isFlat ? { default: config } : config\n\n const store = cfg.store ?? new InMemoryStore()\n if (!(store instanceof InMemoryStore)) {\n throw new Error(\n 'createRouteRateLimiterWeb: async RateLimitStore implementations require a dedicated async middleware path. ' +\n 'Use the InMemoryStore default for the Web façade.',\n )\n }\n const inMemoryStore = store\n const keyBy = (cfg.keyBy ?? 'ip') as Exclude<KeyByMode, (req: IncomingMessage) => string>\n const cookieName = cfg.cookieName ?? 'theo_session'\n\n const patternList: [string | RegExp, RateLimitConfig][] = []\n if (cfg.routes) {\n for (const [pattern, c] of Object.entries(cfg.routes)) patternList.push([pattern, c])\n }\n if (cfg.routePatterns) {\n for (const tuple of cfg.routePatterns) patternList.push(tuple)\n }\n\n return async function checkRouteRateLimitWeb(\n request: Request,\n ctx: DeriveKeyRequestContext = {},\n ): Promise<RateLimitResult> {\n // Web Request guarantees absolute URL — extract path+query for pattern\n // matching (mirror of IncomingMessage's `req.url ?? ''`).\n const parsed = new URL(request.url)\n const url = `${parsed.pathname}${parsed.search}`\n let matched: RateLimitConfig | undefined\n for (const [pattern, c] of patternList) {\n if (matchRoutePattern(url, pattern)) {\n matched = c\n break\n }\n }\n const effective = matched ?? cfg.default\n if (!effective) {\n return { limited: false, headers: {} }\n }\n\n const bucketSuffix = typeof matched === 'undefined' ? '*default*' : normalizePath(url)\n const key = `${await deriveKeyFromRequest(request, keyBy, cookieName, ctx)}|${bucketSuffix}`\n const state = inMemoryStore.incrSync(key, effective.windowMs)\n\n if (state.count > effective.max) {\n const retryAfter = Math.ceil((state.resetAt - Date.now()) / 1000)\n return {\n limited: true,\n headers: {\n 'X-RateLimit-Limit': String(effective.max),\n 'X-RateLimit-Remaining': '0',\n 'Retry-After': String(retryAfter),\n },\n }\n }\n return {\n limited: false,\n headers: {\n 'X-RateLimit-Limit': String(effective.max),\n 'X-RateLimit-Remaining': String(Math.max(0, effective.max - state.count)),\n },\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/auth/nonce.ts"],"sourcesContent":["/**\n * T4.1 — Per-request CSP nonce generation.\n *\n * Returns a 22–24 character base64-encoded string carrying 16 bytes of\n * cryptographic entropy. Used by the SSR pipeline to nonce the inline\n * hydration data script so the default CSP can drop `'unsafe-inline'`\n * from `script-src` in 0.3.0.\n *\n * Runtime portability: prefers Web Crypto (`globalThis.crypto`) because\n * it is available on every target runtime (Node 19+, Bun, Deno, Vercel\n * Edge, Cloudflare Workers). Falls back to `node:crypto` for older Node\n * builds where `globalThis.crypto` is absent.\n *\n * NOT a security primitive in the cryptographic sense — the nonce is a\n * one-shot, single-request value that defeats trivial XSS injection by\n * making the attacker guess a 128-bit string per request. It is NOT\n * suitable for signing or session tokens.\n */\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n // Prefer Buffer when available (Node, Bun) — its base64 encoder is fast\n // and well-tested. In Edge runtimes that lack Buffer, fall back to the\n // standard btoa(String.fromCharCode(...)) trick.\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64')\n }\n let binary = ''\n for (const b of bytes) {\n binary += String.fromCharCode(b)\n }\n // `btoa` exists in browsers + edge runtimes; if it doesn't, the caller\n // is on a JS runtime we don't support — let the ReferenceError bubble.\n return btoa(binary)\n}\n\n// CR-027 fix: the previous fallback path used `require('node:crypto')`,\n// which throws ReferenceError in strict ESM contexts (Bun, Deno, Vercel\n// Edge) when reached. Web Crypto has been a hard requirement since Node\n// 19; for older Node we now throw a clear error at module load time\n// instead of failing on first SSR request.\nlet cachedWebCrypto: Crypto | null | undefined\n\nfunction getWebCrypto(): Crypto {\n if (cachedWebCrypto === undefined) {\n const candidate = (globalThis as { crypto?: Crypto }).crypto\n cachedWebCrypto =\n candidate && typeof candidate.getRandomValues === 'function' ? candidate : null\n }\n if (!cachedWebCrypto) {\n throw new Error(\n 'generateNonce: Web Crypto unavailable. TheoKit requires Node.js 19+, Bun, Deno, ' +\n 'or any modern Edge runtime where `globalThis.crypto.getRandomValues` is present.',\n )\n }\n return cachedWebCrypto\n}\n\nexport function generateNonce(): string {\n const buf = new Uint8Array(16)\n getWebCrypto().getRandomValues(buf)\n return bytesToBase64(buf)\n}\n"],"mappings":";AAmBA,SAAS,cAAc,OAA2B;AAIhD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ;AAAA,EAC7C;AACA,MAAI,SAAS;AACb,aAAW,KAAK,OAAO;AACrB,cAAU,OAAO,aAAa,CAAC;AAAA,EACjC;AAGA,SAAO,KAAK,MAAM;AACpB;AAOA,IAAI;AAEJ,SAAS,eAAuB;AAC9B,MAAI,oBAAoB,QAAW;AACjC,UAAM,YAAa,WAAmC;AACtD,sBACE,aAAa,OAAO,UAAU,oBAAoB,aAAa,YAAY;AAAA,EAC/E;AACA,MAAI,CAAC,iBAAiB;AACpB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,gBAAwB;AACtC,QAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,eAAa,EAAE,gBAAgB,GAAG;AAClC,SAAO,cAAc,GAAG;AAC1B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/http/controller-dispatch.ts","../src/server/agent/mount-agent.ts","../src/server/agent/build-agent-streamer.ts","../src/server/agent/approval-registry.ts","../src/server/agent/durable-ui-message-stream-response.ts","../src/server/agent/run-event-cache.ts","../src/server/agent/provider-resolver.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Controller files are walked from the developer's `serverDir/controllers`\n * (a build-time config path), never from HTTP input. No injection vector.\n */\nimport { readdirSync, type Dirent } from 'node:fs'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport { join } from 'node:path'\n\nimport { createDecoratorHandler, isControllerClass, type ServeAgent } from '@theokit/http'\n\nimport { dispatchCsrfWarn } from '../security/csrf-warn-dispatch.js'\nimport { enforceCsrf, type DisallowedConfig } from '../security/csrf.js'\n\nimport { incomingMessageToWebRequest } from './node-request.js'\nimport { sendError } from './send-response.js'\n\n/** A decorator controller constructor (`@Controller` class). */\ntype ControllerClass = new (...args: never[]) => object\n\n/** Loads a controller module by absolute path. In dev this is Vite's `ssrLoadModule`\n * (the Task 1.1 swc transform has already compiled the parameter decorators); tests\n * inject `@theokit/http`'s `loadControllerWithSwc`. */\nexport type ControllerModuleLoader = (absPath: string) => Promise<Record<string, unknown>>\n\n/** A built controller route table exposed as a pure Web-Standard handler. */\ninterface ControllerDispatcher {\n /** `null` = no controller route matched — the host owns the miss (404 / fall-through). */\n dispatch(request: Request): Promise<Response | null>\n /** Non-executing route probe — true when a controller route owns `method` + `pathname`. */\n matches(method: string, pathname: string): boolean\n}\n\n// State-mutating methods get CSRF, mirroring the file-route pipeline (execute.ts).\nconst CSRF_PROTECTED_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])\n\n/** Recursively collect `*.controller.ts` files under `dir` (absolute paths). */\nfunction findControllerFiles(dir: string): string[] {\n const found: string[] = []\n const walk = (current: string): void => {\n let entries: Dirent[]\n try {\n entries = readdirSync(current, { withFileTypes: true })\n } catch {\n return // dir doesn't exist — no controllers\n }\n for (const entry of entries) {\n const full = join(current, entry.name)\n if (entry.isDirectory()) walk(full)\n else if (entry.name.endsWith('.controller.ts')) found.push(full)\n }\n }\n walk(dir)\n return found\n}\n\n/** A discovered controller: its source file + the loaded `@Controller` class. */\ninterface ControllerModule {\n filePath: string\n cls: ControllerClass\n}\n\n/**\n * Load every `@Controller` class under `controllersDir` via the injected loader,\n * keeping each class paired with its source file (needed by the typed-client\n * codegen to emit `import type { X } from '<file>'`). Non-controller exports are\n * ignored (`isControllerClass` — reused from @theokit/http).\n */\nexport async function scanControllerModules(\n controllersDir: string,\n loadModule: ControllerModuleLoader,\n): Promise<ControllerModule[]> {\n const files = findControllerFiles(controllersDir)\n const modules: ControllerModule[] = []\n for (const filePath of files) {\n const mod = await loadModule(filePath)\n for (const exported of Object.values(mod)) {\n if (typeof exported === 'function' && isControllerClass(exported)) {\n modules.push({ filePath, cls: exported as ControllerClass })\n }\n }\n }\n return modules\n}\n\n/** Load every `@Controller` class under `controllersDir` (classes only). */\nasync function scanControllers(\n controllersDir: string,\n loadModule: ControllerModuleLoader,\n): Promise<ControllerClass[]> {\n const modules = await scanControllerModules(controllersDir, loadModule)\n return modules.map((m) => m.cls)\n}\n\n/**\n * Scan `controllersDir` and build a Web-Standard dispatcher over the decorator\n * controllers found. Returns `null` when the directory has no controllers, so\n * the host can skip the controller path entirely (zero cost for routes-only apps).\n *\n * Dispatch REUSES @theokit/http's `createDecoratorHandler` (match + `@Param`\n * binding + `@Body` validation + Response building) — never re-implemented (ADR-1).\n */\nexport async function createControllerDispatcher(opts: {\n controllersDir: string\n loadModule: ControllerModuleLoader\n /** M47 — serves `@Expose`-bound agent routes (theo supplies a `mountAgent`-backed impl). */\n serveAgent?: ServeAgent\n}): Promise<ControllerDispatcher | null> {\n const classes = await scanControllers(opts.controllersDir, opts.loadModule)\n if (classes.length === 0) return null\n const handle = createDecoratorHandler({ controllers: classes, serveAgent: opts.serveAgent })\n return {\n dispatch: (request) => handle(request),\n matches: (method, pathname) => handle.matches(method, pathname),\n }\n}\n\n/** Write a buffered Web `Response` (controllers never stream) to a Node response. */\nasync function writeControllerResponse(res: ServerResponse, response: Response): Promise<void> {\n const headersBag: Record<string, string> = {}\n for (const [k, v] of response.headers) {\n if (k.toLowerCase() !== 'set-cookie') headersBag[k] = v\n }\n const setCookies = response.headers.getSetCookie()\n if (setCookies.length > 0) res.setHeader('Set-Cookie', setCookies)\n res.writeHead(response.status, headersBag)\n const body = response.body ? await response.text() : ''\n res.end(body || undefined)\n}\n\n/**\n * The `api-middleware` fall-through in one call: scan `controllersDir`, build the\n * dispatcher, and serve the request. Builds a body-ful Web `Request` (`@Body`\n * needs the body; the raw stream is undrained at a route miss) and enforces CSRF\n * with the SAME gate file routes use (parity). Returns `true` when a controller\n * handled it (or CSRF blocked it), `false` when there are no controllers OR none\n * matched (the host continues to its own 404). Built per-miss so controller edits\n * reflect via HMR.\n */\nexport async function dispatchControllerRequest(args: {\n controllersDir: string\n loadModule: ControllerModuleLoader\n req: IncomingMessage\n res: ServerResponse\n csrfMode: 'off' | 'warn' | 'strict'\n disallowed?: DisallowedConfig\n requestId: string\n /** M47 — serves `@Expose`-bound agent routes (mountAgent-backed); omit for routes-only apps. */\n serveAgent?: ServeAgent\n}): Promise<boolean> {\n const { req, res, csrfMode, disallowed, requestId } = args\n const dispatcher = await createControllerDispatcher({\n controllersDir: args.controllersDir,\n loadModule: args.loadModule,\n serveAgent: args.serveAgent,\n })\n if (!dispatcher) return false\n\n const method = (req.method ?? 'GET').toUpperCase()\n const webRequest = incomingMessageToWebRequest(req)\n const pathname = new URL(webRequest.url).pathname\n\n // CSRF parity: enforce ONLY when a protected-method controller route actually\n // owns this path (probe with the non-executing matcher — never double-dispatch,\n // which would run the handler + its side effects). An unrouted path falls\n // through to the host's own 404, not a 403.\n if (CSRF_PROTECTED_METHODS.has(method) && dispatcher.matches(method, pathname)) {\n const decision = enforceCsrf(\n req,\n csrfMode,\n { warn: dispatchCsrfWarn, path: req.url },\n disallowed,\n )\n if (!decision.allow) {\n sendError(\n res,\n 'CSRF_INVALID',\n decision.reason ?? 'CSRF check failed',\n 403,\n undefined,\n requestId,\n )\n return true\n }\n }\n\n const response = await dispatcher.dispatch(webRequest)\n if (response === null) return false\n await writeControllerResponse(res, response)\n return true\n}\n","/**\n * M2 (theokit-ai-first) — mount a scanned `agents/<name>.ts` module as an SSE endpoint.\n *\n * The SINGLE wiring point shared by dev (vite middleware) and prod (built server), so the\n * two never drift (EC-4). Web-Standard `Request` → `Response`: parse the chat body, compile\n * the module (`compileAgentModule`, converges both surfaces), stream via the M0/M1 canonical\n * protocol (`streamAgentUIMessages` → `uiMessageStreamResponse`).\n *\n * Request body — accepts the `@ai-sdk/react` `useChat` shape (`{ id, messages: UIMessage[] }`,\n * the typed-client path) AND a simple `{ message, sessionId? }` shape (M0/M1-style clients).\n */\nimport { compileAgentModule, resolveEnabledSkills, streamAgentUIMessages } from '@theokit/agents'\n\nimport { validateCsrfRequest, type CsrfMode } from '../security/csrf.js'\n\nimport { buildAgentHitl } from './build-agent-streamer.js'\nimport { durableUiMessageStreamResponse } from './durable-ui-message-stream-response.js'\nimport { getRunEventCache, mintRunId } from './run-event-cache.js'\n\n/** The message + session extracted from a chat request, or `null` when the body is invalid. */\ninterface AgentRequestInput {\n message: string\n sessionId: string\n}\n\n/** Extract the text of a `{ type: 'text', text: string }` part from an untrusted value. */\nfunction partText(part: unknown): string {\n if (typeof part !== 'object' || part === null) return ''\n const p = part as Record<string, unknown>\n return p.type === 'text' && typeof p.text === 'string' ? p.text : ''\n}\n\nfunction jsonError(status: number, code: string, message: string): Response {\n return new Response(JSON.stringify({ error: { code, message } }), {\n status,\n headers: { 'content-type': 'application/json' },\n })\n}\n\n/**\n * Extract `{ message, sessionId }` from a chat request body. Returns `null` when neither the\n * ai-sdk `messages` shape nor the simple `message` shape yields non-empty user text.\n */\nexport function parseAgentRequestBody(body: unknown): AgentRequestInput | null {\n if (typeof body !== 'object' || body === null) return null\n const b = body as Record<string, unknown>\n\n // ai-sdk useChat shape: { id, messages: UIMessage[] } — take the last message's text parts.\n if (Array.isArray(b.messages) && b.messages.length > 0) {\n const last = b.messages[b.messages.length - 1] as Record<string, unknown>\n const parts = Array.isArray(last.parts) ? last.parts : []\n const text = parts.map(partText).join('')\n if (text.length === 0) return null\n const sessionId = typeof b.id === 'string' && b.id.length > 0 ? b.id : crypto.randomUUID()\n return { message: text, sessionId }\n }\n\n // Simple shape: { message, sessionId? }.\n if (typeof b.message === 'string' && b.message.length > 0) {\n const sessionId =\n typeof b.sessionId === 'string' && b.sessionId.length > 0 ? b.sessionId : crypto.randomUUID()\n return { message: b.message, sessionId }\n }\n\n return null\n}\n\n/** Non-runtime options for {@link mountAgent} (grouped so the call stays ≤ 5 params). */\ninterface MountAgentOptions {\n /** Labels a fail-fast `AgentDefinitionError` (the agent file path). Default `'agent module'`. */\n source?: string\n /** CSRF posture at this boundary. Default `'strict'`; `'off'` when a controller already gated (G5). */\n csrfMode?: CsrfMode\n /**\n * theokit-file-based-config (EC-1) — the framework-resolved app root. When the agent opted into\n * `.theokit/` file-based config (`.settingSources([...])`), discovery points here, NOT `process.cwd()`.\n */\n projectRoot?: string\n}\n\n/**\n * Mount a loaded agent module as a `Response`. `apiKey` is resolved by the caller\n * (`resolveProvider`). See {@link MountAgentOptions} for the labeling / CSRF / app-root knobs.\n */\nexport async function mountAgent(\n mod: unknown,\n request: Request,\n apiKey: string,\n { source = 'agent module', csrfMode = 'strict', projectRoot }: MountAgentOptions = {},\n): Promise<Response> {\n // Enforce CSRF BEFORE any work — an agent run spends real LLM tokens, so a cross-origin\n // POST must be rejected before it reaches the SDK (parity with actions/routes). The custom\n // `X-Theo-Action` header + Origin match is the same defense `executeRoute`/`executeAction`\n // apply; the `useAgent` client sends the header. `off` skips; `warn` never blocks.\n if (csrfMode !== 'off') {\n const csrf = validateCsrfRequest(request)\n if (!csrf.valid && csrfMode === 'strict') {\n return jsonError(403, 'CSRF_FAILED', `CSRF check failed: ${csrf.reason}`)\n }\n }\n\n const compiled = compileAgentModule(mod, source)\n\n // M13 — resolve a per-request skills selector (from `defineAgent({ skills: (ctx) => [...] })`)\n // against the M7 run-context, setting `skills.enabled` before the SDK runs. `undefined` ⇒ the\n // SDK enables every discovered skill. `compiled` is fresh per request, so mutation is safe.\n if (compiled.skillsResolver) {\n const enabled = await resolveEnabledSkills(compiled.skillsResolver, compiled.runContext ?? {})\n if (enabled !== undefined) compiled.skills = { enabled, autoInject: true }\n }\n\n let body: unknown = null\n try {\n body = await request.json()\n } catch {\n /* invalid/empty JSON → handled below as a 400 */\n }\n\n const input = parseAgentRequestBody(body)\n if (input === null) {\n return jsonError(400, 'BAD_REQUEST', 'Request must contain a non-empty message or messages[].')\n }\n\n // When the agent has @HumanInTheLoop-gated tools (M4), wire the pause: the plugin's `awaitApproval`\n // registers a pending approval in the shared registry (the Promise that PAUSES the run); the\n // approve route (`handleAgentApproval`) resolves it. No gated tools ⇒ the M2 stream path unchanged.\n // Extracted to `build-agent-streamer.ts` (M39 / DRY — the thread routes reuse the same wiring).\n const hitl = buildAgentHitl(compiled)\n\n // M37 (ADR-0046) — mint a transport runId + stream through the durable layer:\n // each SSE frame is cached + `id:`-tagged so a dropped client can reconnect\n // (or a second client observe) via `GET /api/agents/<name>/runs/<runId>/stream`.\n // The runId is surfaced in the `x-theokit-run-id` response header.\n const runId = mintRunId()\n return durableUiMessageStreamResponse(\n streamAgentUIMessages(compiled, apiKey, {\n ...input,\n hitl,\n signal: request.signal,\n cwd: resolveDiscoveryCwd(compiled, projectRoot),\n baseDir: resolveSessionBaseDir(projectRoot),\n }),\n { runId, cache: getRunEventCache() },\n )\n}\n\n/**\n * theokit-file-based-config (EC-1) — resolve the `.theokit/` discovery cwd. When the agent opted into\n * file-based config (`.settingSources([...])`), point discovery at the framework-resolved app root,\n * NOT `process.cwd()` (which is not guaranteed to be the app root). No opt-in ⇒ `undefined` (byte-unchanged).\n */\nfunction resolveDiscoveryCwd(\n compiled: { settingSources?: readonly unknown[] },\n projectRoot: string | undefined,\n): string | undefined {\n const optedIn = (compiled.settingSources?.length ?? 0) > 0\n return projectRoot !== undefined && optedIn ? projectRoot : undefined\n}\n\n/** Strip trailing `/` without a backtracking regex (linear scan). */\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length\n while (end > 0 && value[end - 1] === '/') end -= 1\n return value.slice(0, end)\n}\n\n/**\n * SDK 4.0 (SE40) — resolve the root of the native `.jsonl` session transcript. Unlike `.theokit/`\n * discovery, persistence is NOT gated on a file-based-config opt-in — every agent session persists.\n * Root it under the app's `.data/` (git-ignored, EC-2), kept OUT of the `.theokit/` config dir so a\n * `projects/` transcript subtree never collides with `settingSources` discovery. Absent `projectRoot`\n * ⇒ `undefined` (the SDK default `~/.theokit` applies).\n */\nexport function resolveSessionBaseDir(projectRoot: string | undefined): string | undefined {\n if (projectRoot === undefined) return undefined\n // Web-Standards discipline (R3a/G8): no `node:path` in `server/` — append with `/` (the SDK\n // normalizes the separator). Strip a trailing slash on `projectRoot` so we never emit `//`.\n // A trailing-slash strip written as a loop-free replace: `/\\/+$/` is super-linear under\n // backtracking on a long run of slashes, and this value can come from user config.\n return `${trimTrailingSlashes(projectRoot)}/.data/agent-sessions`\n}\n","/**\n * M39 (ADR-0048) — shared agent-run streamer builders, extracted from\n * `mount-agent.ts` (DRY / G12) so the thread routes drive the SAME SDK run path\n * as the plain POST. Reuses SDK primitives (`compileAgentModule` +\n * `streamAgentUIMessages`) — it does NOT reimplement the loop (G2).\n */\n\nimport {\n compileAgentModule,\n type HumanInTheLoopOptions,\n resolveEnabledSkills,\n streamAgentUIMessages,\n} from '@theokit/agents'\nimport type { UIMessageChunk } from 'ai'\n\nimport { getApprovalRegistry } from './approval-registry.js'\n\ntype Compiled = ReturnType<typeof compileAgentModule>\n\n/**\n * Build the HITL wiring for a compiled agent: gated tools register a pending\n * approval in the shared registry (the Promise that PAUSES the run). `undefined`\n * when the agent has no `@HumanInTheLoop`-gated tools. Extracted verbatim from\n * `mountAgent` so both the plain POST and the thread routes wire HITL identically.\n */\nexport function buildAgentHitl(compiled: Compiled) {\n const gated = compiled.hitl\n if (gated === undefined || gated.size === 0) return undefined\n const registry = getApprovalRegistry()\n return {\n gated,\n awaitApproval: (approvalId: string, opts: HumanInTheLoopOptions, toolName: string) =>\n registry.register(approvalId, {\n timeoutMs: opts.timeout ?? 300_000,\n onTimeout: opts.onTimeout ?? 'abort',\n toolName,\n question: opts.question,\n ...(opts.payloadSchema !== undefined ? { payloadSchema: opts.payloadSchema } : {}),\n }),\n }\n}\n\n/**\n * A `startRun(sessionId, message)` closure for the thread dispatcher. Per run it\n * compiles the module fresh (skills resolution mutates `compiled`), resolves\n * per-request skills, builds HITL, and streams. Headless — no request signal (a\n * thread continuation runs to completion into the durable cache, not to a client).\n */\nexport function makeThreadStartRun(\n mod: unknown,\n apiKey: string,\n source: string,\n): (sessionId: string, message: string) => AsyncIterable<UIMessageChunk> {\n return (sessionId, message) =>\n (async function* () {\n const compiled = compileAgentModule(mod, source)\n if (compiled.skillsResolver) {\n const enabled = await resolveEnabledSkills(\n compiled.skillsResolver,\n compiled.runContext ?? {},\n )\n if (enabled !== undefined) compiled.skills = { enabled, autoInject: true }\n }\n const hitl = buildAgentHitl(compiled)\n yield* streamAgentUIMessages(compiled, apiKey, { message, sessionId, hitl })\n })()\n}\n","/**\n * M4 (theokit-ai-first) — the in-process HITL approval registry.\n *\n * The HITL plugin's `awaitApproval` calls `register(approvalId)` and awaits the returned Promise\n * (this is what genuinely PAUSES the SDK run — the SDK `pre_tool_call` hook is awaited). The\n * approve route calls `resolve(approvalId, approved)` to settle it. A per-approval timeout settles\n * the Promise deterministically per the `@HumanInTheLoop` `onTimeout` policy so a hung approval\n * never leaks the paused stream.\n *\n * Single-process contract (ADR 0038 / plan Drawback 2): a multi-instance deploy needs a shared\n * registry — the interface is injectable so a durable impl (Redis, etc.) slots in without touching\n * the harness. We do NOT build a durable store now (YAGNI).\n */\n// The timeout policy vocabulary is owned by the `@HumanInTheLoop` decorator (DRY / G12) — reuse it\n// rather than re-declaring the union, so the two can never drift.\nimport type { TimeoutAction } from '@theokit/agents'\n\nexport interface RegisterOptions {\n /** Milliseconds before the approval auto-settles per `onTimeout`. */\n timeoutMs: number\n /**\n * What a timeout means. Only `'proceed'` auto-approves; `'abort'` and `'retry'` both deny — the\n * registry does NOT implement retry semantics (a timed-out `'retry'` is a deny, not a re-prompt).\n */\n onTimeout: TimeoutAction\n /** M14 — the gated tool name, surfaced by `list()` (optional; absent for legacy callers). */\n toolName?: string\n /** M14 — the approval question, surfaced by `list()` (optional). */\n question?: string\n /**\n * M20 — an optional JSON-schema descriptor of the custom payload the approver may attach. Carried\n * verbatim into `list()` + the `approval_required` event so the UI knows what to collect. Kept as\n * a plain JSON object (not a live Zod schema) so the registry stays serializable and SDK-free.\n */\n payloadSchema?: Record<string, unknown>\n}\n\n/**\n * M20 — a settled HITL decision. `approved` is the allow/deny bit (backward-compatible with the\n * legacy boolean); `reason` + `payload` are the optional approver-attached extras that surface to\n * the model (on denial, via the veto message) and to the app/UI.\n */\nexport interface ApprovalDecision {\n approved: boolean\n reason?: string\n payload?: unknown\n}\n\n/** M14 — a pending approval as surfaced by {@link ApprovalRegistry.list}. */\nexport interface PendingApproval {\n approvalId: string\n toolName?: string\n question?: string\n /** Epoch millis when the pending approval auto-settles (registeredAt + timeoutMs). */\n expiresAt: number\n /** M20 — the declared custom-payload schema, if the gated tool declares one. */\n payloadSchema?: Record<string, unknown>\n}\n\nexport interface ApprovalRegistry {\n /**\n * Register a pending approval; the returned Promise settles with the full {@link ApprovalDecision}\n * on `resolve` or timeout (M20 — was a bare boolean pre-M20).\n */\n register(approvalId: string, opts: RegisterOptions): Promise<ApprovalDecision>\n /**\n * Settle a pending approval. Accepts a full {@link ApprovalDecision} OR a bare boolean (coerced to\n * `{ approved }` — backward-compatible). Returns false if the id is unknown or already settled.\n */\n resolve(approvalId: string, decision: boolean | ApprovalDecision): boolean\n /** M14 — list the currently-pending approvals (process-wide; single-process contract). */\n list(): PendingApproval[]\n}\n\ninterface Pending {\n settle: (decision: ApprovalDecision) => void\n timer: ReturnType<typeof setTimeout>\n info: PendingApproval\n}\n\n/**\n * The one process-wide registry the stream mount (`mountAgent`) and the approve route share.\n *\n * The in-process impl holds LIVE Promise resolvers in memory — the approval a request awaits and\n * the approval the route resolves MUST be the same object, so a single instance per process is not\n * a convenience but a correctness requirement. Lazily created; a durable/multi-instance deploy\n * swaps this accessor for a shared-store impl (ADR 0038 / plan Drawback 2) without touching callers.\n * Tests use {@link createInProcessApprovalRegistry} directly — never this singleton.\n */\nlet serverRegistry: ApprovalRegistry | undefined\nexport function getApprovalRegistry(): ApprovalRegistry {\n serverRegistry ??= createInProcessApprovalRegistry()\n return serverRegistry\n}\n\nexport function createInProcessApprovalRegistry(): ApprovalRegistry {\n const pending = new Map<string, Pending>()\n\n return {\n register(approvalId, opts) {\n return new Promise<ApprovalDecision>((resolve) => {\n const settle = (decision: ApprovalDecision): void => {\n const entry = pending.get(approvalId)\n if (!entry) return\n clearTimeout(entry.timer)\n pending.delete(approvalId)\n resolve(decision)\n }\n // 'proceed' → allow on timeout; 'abort'/'retry' → deny on timeout.\n const timer = setTimeout(() => {\n settle({ approved: opts.onTimeout === 'proceed' })\n }, opts.timeoutMs)\n const info: PendingApproval = {\n approvalId,\n toolName: opts.toolName,\n question: opts.question,\n expiresAt: Date.now() + opts.timeoutMs,\n ...(opts.payloadSchema !== undefined ? { payloadSchema: opts.payloadSchema } : {}),\n }\n pending.set(approvalId, { settle, timer, info })\n })\n },\n resolve(approvalId, decision) {\n const entry = pending.get(approvalId)\n if (!entry) return false\n // M20 — coerce the legacy bare-boolean form to a decision object.\n entry.settle(typeof decision === 'boolean' ? { approved: decision } : decision)\n return true\n },\n list() {\n return [...pending.values()].map((p) => p.info)\n },\n }\n}\n","import type { UIMessageChunk } from 'ai'\n\nimport type { RunEventCache } from './run-event-cache.js'\n\n/**\n * M37 (ADR-0046) — the DURABLE variant of `uiMessageStreamResponse`. Same\n * `UIMessageStream` wire (`useChat` still consumes it), plus three additions so\n * a dropped client can reconnect without missing chunks:\n *\n * 1. each SSE frame gains a monotonic `id: <seq>\\n` line (SSE-native — the\n * browser echoes it as `Last-Event-ID` on reconnect, ADR-0046 D3);\n * 2. every frame is `append`ed to the {@link RunEventCache} keyed by `runId`\n * so the reconnect endpoint can replay it;\n * 3. the response carries `x-theokit-run-id: <runId>` so the client learns the\n * reconnect key (ADR-0046 D2).\n *\n * Fail-clear (error-handling.md): if the source aborts mid-stream, the run is\n * still `end`ed in the cache and `[DONE]` is flushed — never left hanging.\n */\n\n/** The UIMessageStream SSE base headers — shared by the encoder + reconnect handler (DRY). */\nexport const SSE_BASE_HEADERS = {\n 'content-type': 'text/event-stream',\n 'x-vercel-ai-ui-message-stream': 'v1',\n} as const\n\n/** Header the client reads to obtain the reconnect key. */\nexport const RUN_ID_HEADER = 'x-theokit-run-id'\n\nexport const SSE_DONE_FRAME = 'data: [DONE]\\n\\n'\n\n/** Format one SSE frame with its sequence id (shared by the encoder + reconnect replay). */\nexport function formatSseFrame(seq: number, data: string): string {\n return `id: ${seq}\\ndata: ${data}\\n\\n`\n}\n\n/** UTF-8 encode an SSE frame for a `ReadableStream<Uint8Array>` (shared). */\nexport function encodeSse(text: string): Uint8Array {\n return new TextEncoder().encode(text)\n}\n\ninterface DurableStreamDeps {\n readonly runId: string\n readonly cache: RunEventCache\n}\n\nexport function durableUiMessageStreamResponse(\n chunks: AsyncIterable<UIMessageChunk>,\n deps: DurableStreamDeps,\n): Response {\n const { runId, cache } = deps\n const stream = new ReadableStream<Uint8Array>({\n async start(controller) {\n try {\n for await (const chunk of chunks) {\n const data = JSON.stringify(chunk)\n const seq = cache.append(runId, data)\n controller.enqueue(encodeSse(formatSseFrame(seq, data)))\n }\n } catch {\n // Source aborted mid-stream. The upstream translator owns error\n // semantics (surfaces failures as chunks + closes gracefully); this\n // transport guarantees only a terminated, cache-ended stream.\n } finally {\n cache.end(runId)\n controller.enqueue(encodeSse(SSE_DONE_FRAME))\n controller.close()\n }\n },\n })\n return new Response(stream, {\n headers: { ...SSE_BASE_HEADERS, [RUN_ID_HEADER]: runId },\n })\n}\n","/**\n * M37 (ADR-0046) — the durable event cache behind resumable agent streams.\n *\n * As an agent turn streams over SSE, each `UIMessageChunk` frame is `append`ed\n * here keyed by a transport `runId`. A client that drops and reconnects (or a\n * second client that observes) `attach`es to the run: it replays the frames it\n * missed (`seq > Last-Event-ID`) and then follows the live tail. This is the\n * TRANSPORT half of durable agents (ADR-0040/0044) — it caches serialized\n * frames, it does NOT run the agent loop.\n *\n * Single-process by default (an in-memory `Map`, same contract as the HITL\n * `approval-registry`). A persistent backend (Redis / `ConversationStorageAdapter`)\n * plugs in behind {@link RunEventCache} for multi-instance deploys — it is NOT\n * shipped in core (ADR-0046 D4: no broker in core).\n */\n\n/** One recorded SSE frame: its monotonic sequence id + the serialized `data:` payload. */\nexport interface CachedFrame {\n readonly seq: number\n readonly data: string\n}\n\n/** The result of {@link RunEventCache.attach}. */\nexport interface AttachResult {\n /** False when `runId` is unknown (never started, or evicted). */\n readonly known: boolean\n /** Frames with `seq > afterSeq`, in order — replay these before the live tail. */\n readonly replay: readonly CachedFrame[]\n /** True when the run already terminated: `replay` is complete, no live frames follow. */\n readonly ended: boolean\n /** Detach the live listener (idempotent). */\n readonly unsubscribe: () => void\n}\n\n/**\n * A per-`runId` ordered frame buffer with live fan-out. Implemented in-memory by\n * default; swap a persistent backend for multi-instance deploys.\n */\nexport interface RunEventCache {\n /**\n * M39 — synchronously register `runId` as a live (frame-less) run so `has()` is\n * true and a subscriber can `attach()` BEFORE the first frame. Idempotent.\n * Closes the race where a thread's active run is resolvable in the registry but\n * not yet in the cache (a headless pump appends its first frame asynchronously).\n */\n begin(runId: string): void\n /** Record a frame for `runId`, returning its assigned monotonic `seq`. Notifies live listeners. */\n append(runId: string, data: string): number\n /** Mark `runId` terminated: notify listeners, then schedule bounded eviction. Idempotent. */\n end(runId: string): void\n /** Whether `runId` is currently cached (started + not yet evicted). */\n has(runId: string): boolean\n /**\n * Atomically snapshot the frames after `afterSeq` AND (when the run is still\n * live) register `onFrame`/`onEnd` in the SAME synchronous tick — so no frame\n * slips between replay and subscribe, and none is duplicated.\n */\n attach(\n runId: string,\n afterSeq: number,\n onFrame: (frame: CachedFrame) => void,\n onEnd: () => void,\n ): AttachResult\n}\n\ninterface Listener {\n readonly onFrame: (frame: CachedFrame) => void\n readonly onEnd: () => void\n}\n\ninterface RunBuffer {\n readonly frames: CachedFrame[]\n ended: boolean\n readonly listeners: Set<Listener>\n evictTimer?: ReturnType<typeof setTimeout>\n}\n\nconst DEFAULT_EVICT_AFTER_MS = 5 * 60_000 // 5 min after end (parity with approval-registry)\n\nconst NOOP_UNSUBSCRIBE = (): void => {\n // No live listener was registered (unknown or already-ended run).\n}\n\ninterface RunEventCacheOptions {\n /** Milliseconds after `end()` before a run's buffer is evicted. Default 5 min. */\n readonly evictAfterMs?: number\n}\n\nexport function createInMemoryRunEventCache(opts: RunEventCacheOptions = {}): RunEventCache {\n const evictAfterMs = opts.evictAfterMs ?? DEFAULT_EVICT_AFTER_MS\n const runs = new Map<string, RunBuffer>()\n\n function getOrCreate(runId: string): RunBuffer {\n let buf = runs.get(runId)\n if (buf === undefined) {\n buf = { frames: [], ended: false, listeners: new Set() }\n runs.set(runId, buf)\n }\n return buf\n }\n\n return {\n begin(runId) {\n getOrCreate(runId)\n },\n\n append(runId, data) {\n const buf = getOrCreate(runId)\n const seq = buf.frames.length\n const frame: CachedFrame = { seq, data }\n buf.frames.push(frame)\n // Notify live listeners (a throwing listener must not break the others).\n for (const l of buf.listeners) {\n try {\n l.onFrame(frame)\n } catch {\n /* a broken subscriber never breaks the producer or its peers */\n }\n }\n return seq\n },\n\n has(runId) {\n return runs.has(runId)\n },\n\n end(runId) {\n const buf = runs.get(runId)\n if (buf === undefined || buf.ended) return\n buf.ended = true\n for (const l of buf.listeners) {\n try {\n l.onEnd()\n } catch {\n /* isolate a broken subscriber */\n }\n }\n buf.listeners.clear()\n buf.evictTimer = setTimeout(() => runs.delete(runId), evictAfterMs)\n // Never keep the process alive just for an eviction timer.\n buf.evictTimer.unref()\n },\n\n attach(runId, afterSeq, onFrame, onEnd) {\n const buf = runs.get(runId)\n if (buf === undefined) {\n return { known: false, replay: [], ended: false, unsubscribe: NOOP_UNSUBSCRIBE }\n }\n // Synchronous snapshot — no `await` before the subscribe below, so no\n // append can interleave (single-threaded): no gap, no dup.\n const replay = buf.frames.filter((f) => f.seq > afterSeq)\n if (buf.ended) {\n return { known: true, replay, ended: true, unsubscribe: NOOP_UNSUBSCRIBE }\n }\n const listener: Listener = { onFrame, onEnd }\n buf.listeners.add(listener)\n return {\n known: true,\n replay,\n ended: false,\n unsubscribe: () => {\n buf.listeners.delete(listener)\n },\n }\n },\n }\n}\n\n/**\n * Process-wide singleton — the SSE encoder (`durableUiMessageStreamResponse`) and\n * the reconnect endpoint MUST share ONE cache. Lazily created; a multi-instance\n * deploy swaps this accessor for a shared-store impl (ADR-0046 D4) without\n * touching callers. Tests use {@link createInMemoryRunEventCache} directly.\n */\nlet serverCache: RunEventCache | undefined\nexport function getRunEventCache(): RunEventCache {\n serverCache ??= createInMemoryRunEventCache()\n return serverCache\n}\n\n/** Mint a stable transport `runId` (the reconnect key, ADR-0046 D2). */\nexport function mintRunId(): string {\n return `run-${crypto.randomUUID()}`\n}\n","/**\n * Provider Resolver — Strategy + Registry pattern (FAANG-grade).\n *\n * Inspiração: Dapr Conversation Registry (`dapr/pkg/components/conversation/registry.go`)\n * + Encore Manager provider array (`encore/runtimes/go/pubsub/manager_internal.go`).\n *\n * Princípio: provider routing é responsabilidade do FRAMEWORK, não do consumer.\n * Consumer template usa `model: { id: 'gpt-4o-mini' }` puro — sem conditionals.\n *\n * Wire protocol: OpenAI Chat Completions (universal — implementado por todos\n * os providers: OpenRouter, Groq, Mistral, Together, Anthropic via proxy, etc).\n *\n * Resolução por prioridade (FIRST match wins):\n * 1. OPENROUTER_API_KEY → baseUrl=openrouter.ai (gateway multi-modelo)\n * 2. OPENAI_API_KEY → baseUrl=api.openai.com\n * 3. ANTHROPIC_API_KEY → direct Anthropic (Messages API, não OpenAI-compat)\n *\n * Escape hatch: `options.apiKey` explícito SOBREPÕE auto-resolution\n * (consumer pode forçar provider específico se quiser).\n */\n\n/**\n * Provider configuration descriptor — Registry entry shape.\n *\n * @public\n */\nexport interface ProviderDescriptor {\n /** Stable name used internally — não exposto no wire. */\n name: string\n /** Environment variable that holds the API key for this provider. */\n envKey: string\n /** Base URL for the provider's OpenAI-compatible (or native) API. */\n baseUrl: string\n /** Resolution priority (lower = higher priority). FIRST match wins. */\n priority: number\n}\n\n/**\n * Resolved provider configuration — output of `resolveProvider()`.\n *\n * @public\n */\nexport interface ResolvedProvider {\n name: string\n apiKey: string\n baseUrl: string\n}\n\n/**\n * Default provider registry. Order = priority (first = highest).\n *\n * Adding a new provider:\n * 1. Append entry below (or register via `registerProvider()`).\n * 2. Set `envKey` matching the user's env var convention.\n * 3. Set `baseUrl` to the OpenAI-compat endpoint (or native if not compat).\n * 4. Provider name used in telemetry/logs only — never wire-exposed.\n */\nconst DEFAULT_REGISTRY: ProviderDescriptor[] = [\n {\n name: 'openrouter',\n envKey: 'OPENROUTER_API_KEY',\n baseUrl: 'https://openrouter.ai/api/v1',\n priority: 1,\n },\n {\n name: 'openai',\n envKey: 'OPENAI_API_KEY',\n baseUrl: 'https://api.openai.com/v1',\n priority: 2,\n },\n {\n name: 'anthropic',\n envKey: 'ANTHROPIC_API_KEY',\n baseUrl: 'https://api.anthropic.com',\n priority: 3,\n },\n]\n\n/**\n * Runtime registry — copy of DEFAULT_REGISTRY mutable via registerProvider().\n * Sorted by priority on every resolve (stable, O(n log n) — n <= ~10 providers).\n */\nconst registry: ProviderDescriptor[] = [...DEFAULT_REGISTRY]\n\n/**\n * Register a new provider (Registry pattern — runtime extension point).\n * Useful for self-hosted endpoints or custom providers without touching theokit src.\n *\n * @example\n * registerProvider({\n * name: 'self-hosted',\n * envKey: 'SELF_HOSTED_API_KEY',\n * baseUrl: 'https://llm.internal.acme.com/v1',\n * priority: 0, // highest priority\n * })\n *\n * @public\n */\nexport function registerProvider(descriptor: ProviderDescriptor): void {\n // Idempotent — replace existing by name.\n const idx = registry.findIndex((p) => p.name === descriptor.name)\n if (idx >= 0) registry[idx] = descriptor\n else registry.push(descriptor)\n}\n\n/**\n * Reset registry to DEFAULT_REGISTRY (test-only / dev escape hatch).\n *\n * @public\n */\nexport function resetProviderRegistry(): void {\n registry.length = 0\n registry.push(...DEFAULT_REGISTRY)\n}\n\n/**\n * Get current registry snapshot (read-only — inspection).\n *\n * @public\n */\nexport function listProviders(): readonly ProviderDescriptor[] {\n return [...registry].sort((a, b) => a.priority - b.priority)\n}\n\n/**\n * Resolve provider from env vars by priority. FIRST env var found wins.\n *\n * @returns ResolvedProvider with apiKey + baseUrl + name\n * @throws Error if NO provider env var is set (actionable message)\n *\n * @public\n */\nexport function resolveProvider(): ResolvedProvider {\n const sorted = [...registry].sort((a, b) => a.priority - b.priority)\n for (const desc of sorted) {\n const apiKey = process.env[desc.envKey]\n if (apiKey && apiKey.length > 0) {\n return {\n name: desc.name,\n apiKey,\n baseUrl: desc.baseUrl,\n }\n }\n }\n // No env var found — emit actionable error.\n const envKeys = sorted.map((p) => p.envKey).join(' OR ')\n throw new Error(\n `No LLM provider API key found in environment. Set one of: ${envKeys}. ` +\n `Get a free OpenRouter key at https://openrouter.ai/keys (recommended — one key, many models).`,\n )\n}\n\n/**\n * Try to resolve — does NOT throw. Returns null if no provider available.\n * Useful for graceful degradation (e.g., mock mode).\n *\n * @public\n */\nexport function tryResolveProvider(): ResolvedProvider | null {\n try {\n return resolveProvider()\n } catch {\n return null\n }\n}\n"],"mappings":"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","names":["compileAgentModule","resolveEnabledSkills","streamAgentUIMessages","registry","compileAgentModule","resolveEnabledSkills","streamAgentUIMessages"]}