theokit 0.4.0-beta.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. package/dist/{actions-virtual-module-HWNTIEPI.js → actions-virtual-module-IY46EEEX.js} +2 -2
  2. package/dist/{actions-virtual-module-SEIPACG5.js → actions-virtual-module-XNHDNCZ6.js} +2 -2
  3. package/dist/add-2ZFFGGE4.js +0 -0
  4. package/dist/{app-typed-client-ITIYTBXO.js → app-typed-client-OUJO3V5J.js} +10 -5
  5. package/dist/{app-typed-client-62FYBLVJ.js.map → app-typed-client-OUJO3V5J.js.map} +1 -1
  6. package/dist/{app-typed-client-62FYBLVJ.js → app-typed-client-YOMWSA3F.js} +11 -6
  7. package/dist/{app-typed-client-ITIYTBXO.js.map → app-typed-client-YOMWSA3F.js.map} +1 -1
  8. package/dist/audit-log-BQWM5YLG.d.ts +60 -0
  9. package/dist/{aws-lambda-XYCGZH3I.js → aws-lambda-GKSTX6HD.js} +3 -3
  10. package/dist/body-parser-web-MUWBKZ3F.js +70 -0
  11. package/dist/body-parser-web-MUWBKZ3F.js.map +1 -0
  12. package/dist/broadcast-QOQGUNNK.js +0 -0
  13. package/dist/{build-HIGHJQQV.js → build-D4J7XECU.js} +31 -22
  14. package/dist/build-D4J7XECU.js.map +1 -0
  15. package/dist/build-request-body-preview-II2235E6.js +0 -0
  16. package/dist/{bun-K73TQEWC.js → bun-ISHSNFIO.js} +3 -3
  17. package/dist/{check-PZR67OY5.js → check-NXYPLM6M.js} +2 -2
  18. package/dist/{chunk-WZ7CPVQB.js → chunk-27LWMYNK.js} +28 -24
  19. package/dist/chunk-27LWMYNK.js.map +1 -0
  20. package/dist/{chunk-BIGBFZSU.js → chunk-2F4FROEQ.js} +1689 -1521
  21. package/dist/chunk-2F4FROEQ.js.map +1 -0
  22. package/dist/chunk-4HBI7DHP.js +20 -0
  23. package/dist/chunk-4HBI7DHP.js.map +1 -0
  24. package/dist/{chunk-X4JAX2U3.js → chunk-4S2UCILN.js} +180 -125
  25. package/dist/chunk-4S2UCILN.js.map +1 -0
  26. package/dist/{chunk-C52GSJPF.js → chunk-4S6YHNG2.js} +11 -8
  27. package/dist/chunk-4S6YHNG2.js.map +1 -0
  28. package/dist/chunk-5ODOE6EF.js +0 -0
  29. package/dist/{chunk-KJVEJILQ.js → chunk-5PU65T5W.js} +9 -3
  30. package/dist/chunk-5PU65T5W.js.map +1 -0
  31. package/dist/chunk-5QW7IQQU.js +36 -0
  32. package/dist/chunk-5QW7IQQU.js.map +1 -0
  33. package/dist/chunk-5Z2727GV.js +1324 -0
  34. package/dist/chunk-5Z2727GV.js.map +1 -0
  35. package/dist/{chunk-YLBSSEHX.js → chunk-6NEXVBPY.js} +5 -15
  36. package/dist/chunk-6NEXVBPY.js.map +1 -0
  37. package/dist/chunk-7MQOHNHE.js +36 -0
  38. package/dist/chunk-7MQOHNHE.js.map +1 -0
  39. package/dist/{chunk-TPCT3MXV.js → chunk-ABVITXFH.js} +405 -272
  40. package/dist/chunk-ABVITXFH.js.map +1 -0
  41. package/dist/chunk-ASDXVRJD.js +185 -0
  42. package/dist/chunk-ASDXVRJD.js.map +1 -0
  43. package/dist/chunk-B3L3TJVF.js +406 -0
  44. package/dist/chunk-B3L3TJVF.js.map +1 -0
  45. package/dist/{chunk-PB4GR7EP.js → chunk-C3ZZ56YZ.js} +1 -18
  46. package/dist/chunk-C3ZZ56YZ.js.map +1 -0
  47. package/dist/{chunk-O7335ZGH.js → chunk-CG563V5M.js} +5 -3
  48. package/dist/chunk-CG563V5M.js.map +1 -0
  49. package/dist/{chunk-5OFPQK6N.js → chunk-COXLEZCN.js} +2 -1
  50. package/dist/chunk-COXLEZCN.js.map +1 -0
  51. package/dist/{chunk-O4BLVPML.js → chunk-DNMSV3R3.js} +22 -28
  52. package/dist/chunk-DNMSV3R3.js.map +1 -0
  53. package/dist/chunk-E3JH6YUM.js +1 -0
  54. package/dist/chunk-ESC54TAK.js +220 -0
  55. package/dist/chunk-ESC54TAK.js.map +1 -0
  56. package/dist/chunk-FI7MPTJW.js +77 -0
  57. package/dist/chunk-FI7MPTJW.js.map +1 -0
  58. package/dist/chunk-H4J2LECY.js +201 -0
  59. package/dist/chunk-H4J2LECY.js.map +1 -0
  60. package/dist/chunk-IAJ2JVEH.js +256 -0
  61. package/dist/chunk-IAJ2JVEH.js.map +1 -0
  62. package/dist/{chunk-F3TG5FJV.js → chunk-IEZCAT2I.js} +7 -1
  63. package/dist/{chunk-F3TG5FJV.js.map → chunk-IEZCAT2I.js.map} +1 -1
  64. package/dist/chunk-JHEAWR3L.js +1 -0
  65. package/dist/chunk-JQSKBMXP.js +17 -0
  66. package/dist/chunk-JQSKBMXP.js.map +1 -0
  67. package/dist/{chunk-4QTKSLTO.js → chunk-K4M64WD6.js} +9 -5
  68. package/dist/{chunk-4QTKSLTO.js.map → chunk-K4M64WD6.js.map} +1 -1
  69. package/dist/chunk-KI7OWQUX.js +293 -0
  70. package/dist/chunk-KI7OWQUX.js.map +1 -0
  71. package/dist/chunk-KT3MWNZG.js +0 -0
  72. package/dist/{chunk-ZJW5FFYJ.js → chunk-LC5PYNJP.js} +2 -2
  73. package/dist/{chunk-JAAHOGKI.js → chunk-M2EY7KDR.js} +1223 -1124
  74. package/dist/chunk-M2EY7KDR.js.map +1 -0
  75. package/dist/{chunk-2VQKDRVF.js → chunk-MR7OLIC6.js} +3 -3
  76. package/dist/chunk-NM4WF3XD.js +63 -0
  77. package/dist/chunk-NM4WF3XD.js.map +1 -0
  78. package/dist/chunk-NPMCKOX4.js +1 -0
  79. package/dist/{chunk-VRHXOKRP.js → chunk-NZXH2LQQ.js} +86 -83
  80. package/dist/chunk-NZXH2LQQ.js.map +1 -0
  81. package/dist/{chunk-B6RP57M3.js → chunk-OLPB36O2.js} +4 -4
  82. package/dist/chunk-PIVX3DYW.js +142 -0
  83. package/dist/chunk-PIVX3DYW.js.map +1 -0
  84. package/dist/{chunk-7TOMTMHT.js → chunk-R7OC6UDK.js} +2 -1
  85. package/dist/chunk-R7OC6UDK.js.map +1 -0
  86. package/dist/chunk-RESN62GB.js +269 -0
  87. package/dist/chunk-RESN62GB.js.map +1 -0
  88. package/dist/{chunk-64JI5LTO.js → chunk-RMU7EBRO.js} +2 -2
  89. package/dist/chunk-RMU7EBRO.js.map +1 -0
  90. package/dist/chunk-TQYSPYKU.js +131 -0
  91. package/dist/chunk-TQYSPYKU.js.map +1 -0
  92. package/dist/chunk-TSLSIRBR.js +107 -0
  93. package/dist/chunk-TSLSIRBR.js.map +1 -0
  94. package/dist/{chunk-XP7YXRHO.js → chunk-U6TPSW4L.js} +37 -5
  95. package/dist/chunk-U6TPSW4L.js.map +1 -0
  96. package/dist/chunk-UD3LFGDL.js +45 -0
  97. package/dist/chunk-UD3LFGDL.js.map +1 -0
  98. package/dist/chunk-UUFYP2UM.js +161 -0
  99. package/dist/chunk-UUFYP2UM.js.map +1 -0
  100. package/dist/{chunk-OXIQI2XZ.js → chunk-VBZCVFSA.js} +2 -2
  101. package/dist/chunk-VMEWD57H.js +137 -0
  102. package/dist/chunk-VMEWD57H.js.map +1 -0
  103. package/dist/{chunk-TRH2L3FI.js → chunk-WEGALZEU.js} +3 -3
  104. package/dist/{chunk-ZOXNJV2O.js → chunk-WGHJD6I7.js} +35 -138
  105. package/dist/chunk-WGHJD6I7.js.map +1 -0
  106. package/dist/chunk-XMS5VRIK.js +0 -0
  107. package/dist/chunk-Y4H3JNVK.js +18 -0
  108. package/dist/chunk-Y4H3JNVK.js.map +1 -0
  109. package/dist/chunk-Z5IGLBWE.js +329 -0
  110. package/dist/chunk-Z5IGLBWE.js.map +1 -0
  111. package/dist/chunk-ZEGYW52B.js +26 -0
  112. package/dist/chunk-ZEGYW52B.js.map +1 -0
  113. package/dist/chunk-ZJQ4O76G.js +87 -0
  114. package/dist/chunk-ZJQ4O76G.js.map +1 -0
  115. package/dist/cli/index.js +32 -21
  116. package/dist/cli/index.js.map +1 -1
  117. package/dist/client/index.d.ts +107 -1
  118. package/dist/client/index.js +152 -6
  119. package/dist/client/index.js.map +1 -1
  120. package/dist/{cloudflare-LCAOTRYZ.js → cloudflare-OJGJ7R2D.js} +3 -3
  121. package/dist/configure-agent-registry-6YGTJYBC.js +0 -0
  122. package/dist/cookies-MJKMGJ7N.js +22 -0
  123. package/dist/csrf-BBrEZSBW.d.ts +107 -0
  124. package/dist/csrf-readiness-store-CjIoub3U.d.ts +43 -0
  125. package/dist/define-websocket-CdK94O-D.d.ts +64 -0
  126. package/dist/{deno-deploy-ZN4RE5HF.js → deno-deploy-BHWKFTOW.js} +3 -3
  127. package/dist/{dev-266MVCVA.js → dev-MJVSRZGF.js} +11 -11
  128. package/dist/{dev-emit-RBSFZZNO.js → dev-emit-5VPRCHOD.js} +39 -142
  129. package/dist/dev-emit-5VPRCHOD.js.map +1 -0
  130. package/dist/{dev-emit-NO6OZJOQ.js → dev-emit-HHP2XJXE.js} +5 -5
  131. package/dist/devtools/entry.js +185 -131
  132. package/dist/devtools/entry.js.map +1 -1
  133. package/dist/{dispatcher-AQJGI3HU.js → dispatcher-63LBXYLE.js} +2 -2
  134. package/dist/{dispatcher-E6QV32BO.js → dispatcher-EJME6C6M.js} +5 -2
  135. package/dist/dispatcher-EJME6C6M.js.map +1 -0
  136. package/dist/{dist-5V77Z223.js → dist-KRW6OVD4.js} +7 -7
  137. package/dist/dist-KRW6OVD4.js.map +1 -0
  138. package/dist/docker-EZDA5FT7.js +0 -0
  139. package/dist/error-envelope-BsNzzAV5.d.ts +62 -0
  140. package/dist/{generate-DT4IIAHF.js → generate-AZ2K6Z2Z.js} +75 -2
  141. package/dist/generate-AZ2K6Z2Z.js.map +1 -0
  142. package/dist/index-DWWEdFh5.d.ts +399 -0
  143. package/dist/index.d.ts +161 -1391
  144. package/dist/index.js +20 -8
  145. package/dist/index.js.map +1 -1
  146. package/dist/{info-FJ4NXKTB.js → info-47VB62MV.js} +5 -5
  147. package/dist/job-backend-CgC8Xf33.d.ts +68 -0
  148. package/dist/{lib-NL5JXGEB.js → lib-NST3PNZX.js} +31 -31
  149. package/dist/lib-NST3PNZX.js.map +1 -0
  150. package/dist/module-loader-Cfz7dgCP.d.ts +26 -0
  151. package/dist/{netlify-5VQ22Z2P.js → netlify-GSNSJGMN.js} +3 -3
  152. package/dist/{node-3APTLGWB.js → node-6I5B6RL3.js} +3 -3
  153. package/dist/node-6I5B6RL3.js.map +1 -0
  154. package/dist/{openapi-FNVSWZOL.js → openapi-NFLSNNVQ.js} +10 -10
  155. package/dist/plugin-runner-BGBkzgi0.d.ts +95 -0
  156. package/dist/plugin-types-DNJGxr4Z.d.ts +79 -0
  157. package/dist/{proper-lockfile-4Y3DP3RP.js → proper-lockfile-MVKMQGFK.js} +27 -27
  158. package/dist/proper-lockfile-MVKMQGFK.js.map +1 -0
  159. package/dist/rate-limit-BdNDZ3vt.d.ts +58 -0
  160. package/dist/registry-QHEZ3BWB.js +25 -0
  161. package/dist/router-RGZFX75G.js +0 -0
  162. package/dist/{routes-H4SPLFHJ.js → routes-3A4XGIEJ.js} +6 -6
  163. package/dist/{scan-C2BOKLSY.js → scan-NQFI5S7P.js} +2 -2
  164. package/dist/scan-NQFI5S7P.js.map +1 -0
  165. package/dist/schema-D3v8VB7o.d.ts +76 -0
  166. package/dist/{schema-VR6YNVLQ.js → schema-KZVOV333.js} +5 -3
  167. package/dist/schema-KZVOV333.js.map +1 -0
  168. package/dist/server/agent/index.d.ts +229 -0
  169. package/dist/server/agent/index.js +16 -0
  170. package/dist/server/agent/index.js.map +1 -0
  171. package/dist/server/auth/index.d.ts +46 -1
  172. package/dist/server/auth/index.js +10 -3
  173. package/dist/server/cost/index.d.ts +1 -3
  174. package/dist/server/cost/index.js +1 -1
  175. package/dist/server/cron/index.js +4 -2
  176. package/dist/server/define/index.d.ts +281 -0
  177. package/dist/server/define/index.js +26 -0
  178. package/dist/server/define/index.js.map +1 -0
  179. package/dist/server/http/index.d.ts +10 -0
  180. package/dist/server/http/index.js +74 -0
  181. package/dist/server/http/index.js.map +1 -0
  182. package/dist/server/index.d.ts +151 -1677
  183. package/dist/server/index.js +558 -1102
  184. package/dist/server/index.js.map +1 -1
  185. package/dist/server/jobs/index.d.ts +348 -2
  186. package/dist/server/jobs/index.js +5 -3
  187. package/dist/server/observability/index.d.ts +324 -0
  188. package/dist/server/observability/index.js +48 -0
  189. package/dist/server/observability/index.js.map +1 -0
  190. package/dist/server/plugins/index.d.ts +17 -0
  191. package/dist/server/plugins/index.js +17 -0
  192. package/dist/server/plugins/index.js.map +1 -0
  193. package/dist/server/rate-limit/index.d.ts +105 -0
  194. package/dist/server/rate-limit/index.js +25 -0
  195. package/dist/server/rate-limit/index.js.map +1 -0
  196. package/dist/server/realtime/index.d.ts +15 -0
  197. package/dist/server/realtime/index.js +8 -0
  198. package/dist/server/realtime/index.js.map +1 -0
  199. package/dist/server/scan/index.d.ts +106 -0
  200. package/dist/server/scan/index.js +43 -0
  201. package/dist/server/scan/index.js.map +1 -0
  202. package/dist/server/security/index.d.ts +193 -0
  203. package/dist/server/security/index.js +50 -0
  204. package/dist/server/security/index.js.map +1 -0
  205. package/dist/server/storage/index.d.ts +22 -0
  206. package/dist/server/storage/index.js +14 -0
  207. package/dist/server/storage/index.js.map +1 -0
  208. package/dist/server/webhook/index.d.ts +148 -0
  209. package/dist/server/webhook/index.js +19 -0
  210. package/dist/server/webhook/index.js.map +1 -0
  211. package/dist/server-error-to-envelope-NO4CCAFQ.js +8 -0
  212. package/dist/server-error-to-envelope-NO4CCAFQ.js.map +1 -0
  213. package/dist/server-error-to-envelope-UJK6OWDJ.js +134 -0
  214. package/dist/server-error-to-envelope-UJK6OWDJ.js.map +1 -0
  215. package/dist/server-routes-hmr-GZJGPWMS.js +0 -0
  216. package/dist/services-json-Z2QNGVPW.js +142 -0
  217. package/dist/services-json-Z2QNGVPW.js.map +1 -0
  218. package/dist/{services-typed-client-XWYYBWGW.js → services-typed-client-KK6RHRDG.js} +2 -2
  219. package/dist/{services-typed-client-ZX5JUHH3.js → services-typed-client-T7M5VPBP.js} +2 -2
  220. package/dist/{sqlite-vec-ARPNUBWT.js → sqlite-vec-54KB4RD3.js} +2 -2
  221. package/dist/sqlite-vec-54KB4RD3.js.map +1 -0
  222. package/dist/{start-HX3QUSOS.js → start-CGSZPBAG.js} +23 -23
  223. package/dist/start-CGSZPBAG.js.map +1 -0
  224. package/dist/{static-TZBVBDTB.js → static-QI5NQT2X.js} +6 -6
  225. package/dist/storage-manager-C4jsO0Tp.d.ts +89 -0
  226. package/dist/storage-manager-D5KBXXKB.js +0 -0
  227. package/dist/{storage-types-DtIVejC1.d.ts → storage-types-DsDTCPbp.d.ts} +1 -1
  228. package/dist/{theo-cloud-3K4DGB3S.js → theo-cloud-RSQCBNXL.js} +4 -4
  229. package/dist/theo-cloud-RSQCBNXL.js.map +1 -0
  230. package/dist/upgrade-readiness-GUJBCJIS.js +0 -0
  231. package/dist/{vercel-MWW24ABC.js → vercel-TKPZK62A.js} +3 -3
  232. package/dist/vite-plugin/index.d.ts +3 -1
  233. package/dist/vite-plugin/index.js +20 -8
  234. package/dist/{vite-plugin-IK3NOWXS.js → vite-plugin-CR4JDFUQ.js} +9 -9
  235. package/dist/vite-plugin-CR4JDFUQ.js.map +1 -0
  236. package/package.json +59 -10
  237. package/LICENSE +0 -201
  238. package/dist/build-HIGHJQQV.js.map +0 -1
  239. package/dist/chunk-5OFPQK6N.js.map +0 -1
  240. package/dist/chunk-64JI5LTO.js.map +0 -1
  241. package/dist/chunk-7TOMTMHT.js.map +0 -1
  242. package/dist/chunk-BIGBFZSU.js.map +0 -1
  243. package/dist/chunk-C52GSJPF.js.map +0 -1
  244. package/dist/chunk-CZM6WWWS.js +0 -2450
  245. package/dist/chunk-CZM6WWWS.js.map +0 -1
  246. package/dist/chunk-JAAHOGKI.js.map +0 -1
  247. package/dist/chunk-KJVEJILQ.js.map +0 -1
  248. package/dist/chunk-O4BLVPML.js.map +0 -1
  249. package/dist/chunk-O7335ZGH.js.map +0 -1
  250. package/dist/chunk-PB4GR7EP.js.map +0 -1
  251. package/dist/chunk-TPCT3MXV.js.map +0 -1
  252. package/dist/chunk-VRHXOKRP.js.map +0 -1
  253. package/dist/chunk-WZ7CPVQB.js.map +0 -1
  254. package/dist/chunk-X4JAX2U3.js.map +0 -1
  255. package/dist/chunk-XP7YXRHO.js.map +0 -1
  256. package/dist/chunk-YLBSSEHX.js.map +0 -1
  257. package/dist/chunk-ZOXNJV2O.js.map +0 -1
  258. package/dist/dev-emit-RBSFZZNO.js.map +0 -1
  259. package/dist/dispatcher-E6QV32BO.js.map +0 -1
  260. package/dist/dist-5V77Z223.js.map +0 -1
  261. package/dist/generate-DT4IIAHF.js.map +0 -1
  262. package/dist/index-li83Swxa.d.ts +0 -506
  263. package/dist/lib-NL5JXGEB.js.map +0 -1
  264. package/dist/proper-lockfile-4Y3DP3RP.js.map +0 -1
  265. package/dist/registry-4MZ26TZD.js +0 -25
  266. package/dist/schema-CjVly9c_.d.ts +0 -274
  267. package/dist/sqlite-vec-ARPNUBWT.js.map +0 -1
  268. package/dist/start-HX3QUSOS.js.map +0 -1
  269. package/dist/theo-cloud-3K4DGB3S.js.map +0 -1
  270. /package/dist/{actions-virtual-module-HWNTIEPI.js.map → actions-virtual-module-IY46EEEX.js.map} +0 -0
  271. /package/dist/{actions-virtual-module-SEIPACG5.js.map → actions-virtual-module-XNHDNCZ6.js.map} +0 -0
  272. /package/dist/{aws-lambda-XYCGZH3I.js.map → aws-lambda-GKSTX6HD.js.map} +0 -0
  273. /package/dist/{bun-K73TQEWC.js.map → bun-ISHSNFIO.js.map} +0 -0
  274. /package/dist/{check-PZR67OY5.js.map → check-NXYPLM6M.js.map} +0 -0
  275. /package/dist/{dispatcher-AQJGI3HU.js.map → chunk-E3JH6YUM.js.map} +0 -0
  276. /package/dist/{node-3APTLGWB.js.map → chunk-JHEAWR3L.js.map} +0 -0
  277. /package/dist/{chunk-ZJW5FFYJ.js.map → chunk-LC5PYNJP.js.map} +0 -0
  278. /package/dist/{chunk-2VQKDRVF.js.map → chunk-MR7OLIC6.js.map} +0 -0
  279. /package/dist/{scan-C2BOKLSY.js.map → chunk-NPMCKOX4.js.map} +0 -0
  280. /package/dist/{chunk-B6RP57M3.js.map → chunk-OLPB36O2.js.map} +0 -0
  281. /package/dist/{chunk-OXIQI2XZ.js.map → chunk-VBZCVFSA.js.map} +0 -0
  282. /package/dist/{chunk-TRH2L3FI.js.map → chunk-WEGALZEU.js.map} +0 -0
  283. /package/dist/{cloudflare-LCAOTRYZ.js.map → cloudflare-OJGJ7R2D.js.map} +0 -0
  284. /package/dist/{schema-VR6YNVLQ.js.map → cookies-MJKMGJ7N.js.map} +0 -0
  285. /package/dist/{deno-deploy-ZN4RE5HF.js.map → deno-deploy-BHWKFTOW.js.map} +0 -0
  286. /package/dist/{dev-266MVCVA.js.map → dev-MJVSRZGF.js.map} +0 -0
  287. /package/dist/{dev-emit-NO6OZJOQ.js.map → dev-emit-HHP2XJXE.js.map} +0 -0
  288. /package/dist/{vite-plugin-IK3NOWXS.js.map → dispatcher-63LBXYLE.js.map} +0 -0
  289. /package/dist/{info-FJ4NXKTB.js.map → info-47VB62MV.js.map} +0 -0
  290. /package/dist/{netlify-5VQ22Z2P.js.map → netlify-GSNSJGMN.js.map} +0 -0
  291. /package/dist/{openapi-FNVSWZOL.js.map → openapi-NFLSNNVQ.js.map} +0 -0
  292. /package/dist/{registry-4MZ26TZD.js.map → registry-QHEZ3BWB.js.map} +0 -0
  293. /package/dist/{routes-H4SPLFHJ.js.map → routes-3A4XGIEJ.js.map} +0 -0
  294. /package/dist/{services-typed-client-XWYYBWGW.js.map → services-typed-client-KK6RHRDG.js.map} +0 -0
  295. /package/dist/{services-typed-client-ZX5JUHH3.js.map → services-typed-client-T7M5VPBP.js.map} +0 -0
  296. /package/dist/{static-TZBVBDTB.js.map → static-QI5NQT2X.js.map} +0 -0
  297. /package/dist/{vercel-MWW24ABC.js.map → vercel-TKPZK62A.js.map} +0 -0
@@ -0,0 +1,107 @@
1
+ import {
2
+ safeAudit
3
+ } from "./chunk-UD3LFGDL.js";
4
+
5
+ // src/server/security/csrf.ts
6
+ function matchDisallowed(path, patterns) {
7
+ for (const p of patterns) {
8
+ if (typeof p === "string") {
9
+ if (path === p) return true;
10
+ } else if (p instanceof RegExp) {
11
+ p.lastIndex = 0;
12
+ if (p.test(path)) return true;
13
+ }
14
+ }
15
+ return false;
16
+ }
17
+ var CSRF_WARN_CODE = "CSRF_STRICT_CUTOVER";
18
+ var CSRF_WARN_DOCS_URL = "https://theokit.dev/upgrade/csrf-strict-cutover";
19
+ function pickHeader(value) {
20
+ if (typeof value === "string") return value;
21
+ if (Array.isArray(value) && value.length > 0) return value[0];
22
+ return "";
23
+ }
24
+ function isCsrfValidFromHeaders(opts) {
25
+ if (opts.csrfActionHeader !== "1") {
26
+ return { valid: false, reason: "Missing X-Theo-Action header" };
27
+ }
28
+ if (opts.origin === null || opts.origin === "") {
29
+ return { valid: true };
30
+ }
31
+ if (opts.host === null || opts.host === "") {
32
+ return { valid: true };
33
+ }
34
+ try {
35
+ const originHost = new URL(opts.origin).host;
36
+ if (originHost !== opts.host) {
37
+ return { valid: false, reason: `Origin ${opts.origin} does not match host ${opts.host}` };
38
+ }
39
+ } catch {
40
+ return { valid: false, reason: `Invalid origin: ${opts.origin}` };
41
+ }
42
+ return { valid: true };
43
+ }
44
+ function validateCsrf(req) {
45
+ const action = req.headers["x-theo-action"];
46
+ const origin = req.headers.origin;
47
+ const host = req.headers.host;
48
+ return isCsrfValidFromHeaders({
49
+ csrfActionHeader: typeof action === "string" ? action : null,
50
+ origin: origin !== void 0 ? pickHeader(origin) || null : null,
51
+ host: host !== void 0 ? pickHeader(host) || null : null
52
+ });
53
+ }
54
+ function validateCsrfRequest(request) {
55
+ return isCsrfValidFromHeaders({
56
+ csrfActionHeader: request.headers.get("x-theo-action"),
57
+ origin: request.headers.get("origin"),
58
+ host: request.headers.get("host")
59
+ });
60
+ }
61
+ function dispatchCsrfWarn(req, reason, logger, auditLogger, pathFallback = "") {
62
+ const payload = {
63
+ event: "csrf.warn",
64
+ method: req.method ?? "UNKNOWN",
65
+ path: logger?.path ?? pathFallback,
66
+ reason,
67
+ code: CSRF_WARN_CODE,
68
+ docsUrl: CSRF_WARN_DOCS_URL
69
+ };
70
+ logger?.warn(payload);
71
+ safeAudit(auditLogger, {
72
+ action: "csrf.warn",
73
+ actor: { type: "anonymous" },
74
+ metadata: { ...payload }
75
+ });
76
+ }
77
+ function enforceCsrf(req, mode, logger, disallowed, auditLogger) {
78
+ if (mode === "off") {
79
+ return { allow: true };
80
+ }
81
+ const check = validateCsrf(req);
82
+ if (check.valid) {
83
+ return { allow: true };
84
+ }
85
+ if (disallowed?.behavior === "raise") {
86
+ const path = logger?.path ?? req.url ?? "";
87
+ if (matchDisallowed(path, disallowed.routes)) {
88
+ return { allow: false, reason: check.reason };
89
+ }
90
+ }
91
+ if (mode === "warn") {
92
+ dispatchCsrfWarn(req, check.reason, logger, auditLogger);
93
+ return { allow: true, reason: check.reason };
94
+ }
95
+ dispatchCsrfWarn(req, check.reason, logger, auditLogger);
96
+ return { allow: false, reason: check.reason };
97
+ }
98
+
99
+ export {
100
+ matchDisallowed,
101
+ CSRF_WARN_CODE,
102
+ CSRF_WARN_DOCS_URL,
103
+ validateCsrf,
104
+ validateCsrfRequest,
105
+ enforceCsrf
106
+ };
107
+ //# sourceMappingURL=chunk-TSLSIRBR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/security/csrf.ts"],"sourcesContent":["import type { IncomingMessage } from 'node:http'\n\nimport type { AuditLogger } from '../observability/audit-log.js'\nimport { safeAudit } from '../observability/audit-log.js'\n\n/**\n * CSRF enforcement mode.\n *\n * - `off` — skip CSRF entirely. Use only when you have another defense\n * (e.g. you don't ship session cookies, all auth is bearer).\n * - `warn` — log a structured warning when the check would fail, but\n * still serve the request. Default for 0.2.0. Migration mode.\n * - `strict` — reject failing requests with 403 + code `CSRF_INVALID`.\n * Will become the default in 0.3.0.\n */\nexport type CsrfMode = 'off' | 'warn' | 'strict'\n\n/**\n * Per-request structured logger surface. Only `warn` is used by enforceCsrf;\n * we don't require a full Logger here so callers can pass a mock or the\n * console directly.\n */\nexport interface CsrfLogger {\n warn: (payload: CsrfWarnPayload) => void\n /** Optional path the request was destined for — used for log correlation. */\n path?: string\n}\n\n/**\n * T5.1 — Rails-inspired per-route escalation.\n *\n * `routes` accepts string (exact match) or RegExp entries. When a request\n * path matches AND the request would otherwise emit a warning, the\n * `behavior` field decides what happens:\n *\n * - `'warn'` → normal warn dispatch (no-op vs default)\n * - `'raise'` → escalate to 403 regardless of global `csrf` mode\n *\n * `'raise'` never downgrades: when global mode is `'off'`, validation is\n * skipped entirely and disallowed dispatch never runs.\n */\nexport interface DisallowedConfig {\n routes: (string | RegExp)[]\n behavior: 'warn' | 'raise'\n}\n\n/**\n * Test whether `path` matches any of the supplied patterns. String\n * patterns are EXACT (trailing slash matters — use RegExp for tolerance).\n *\n * EC-5: when a RegExp carries the `/g` flag, `.test()` mutates\n * `lastIndex` and the next invocation may miss. We reset `lastIndex`\n * before each test so the matcher is a pure function.\n */\nexport function matchDisallowed(path: string, patterns: readonly (string | RegExp)[]): boolean {\n for (const p of patterns) {\n if (typeof p === 'string') {\n if (path === p) return true\n } else if (p instanceof RegExp) {\n p.lastIndex = 0\n if (p.test(path)) return true\n }\n // Neither string nor RegExp: ignore silently (defensive — the public\n // type forbids it but runtime data may slip past).\n }\n return false\n}\n\n/**\n * T2.2 — Stable cutover identifier shipped with every csrf.warn payload.\n *\n * Convention borrowed from Vite's `deprecations.ts:74` — a `code` plus a\n * `docsUrl` lets users (a) grep their logs for a single stable identifier\n * to find every csrf.warn line, and (b) click through directly to the\n * migration guide. Strings are exported constants so the analyzer (T2.3)\n * and migration guide can reference the same source of truth.\n */\nexport const CSRF_WARN_CODE = 'CSRF_STRICT_CUTOVER' as const\nexport const CSRF_WARN_DOCS_URL = 'https://theokit.dev/upgrade/csrf-strict-cutover' as const\n\n/**\n * Pick a header value, choosing the first entry when an array (Node sets\n * arrays for headers that legitimately appear multiple times). Returns\n * `''` when the header is absent or empty — callers treat `''` as \"skip\".\n */\nfunction pickHeader(value: string | string[] | undefined): string {\n if (typeof value === 'string') return value\n if (Array.isArray(value) && value.length > 0) return value[0]\n return ''\n}\n\nexport interface CsrfWarnPayload {\n event: 'csrf.warn'\n method: string\n path: string | undefined\n reason: string\n /**\n * Stable identifier for the 0.2 → 0.3 CSRF strict cutover. Always\n * `'CSRF_STRICT_CUTOVER'`. Grep-able from prod logs.\n */\n code: string\n /**\n * Link to the section of the migration guide explaining how to clear\n * this specific warning class.\n */\n docsUrl: string\n}\n\n/**\n * T5a.2 Phase B (slice 1/6): pure header-only CSRF check extracted from\n * `validateCsrf(req: IncomingMessage)` so it can be re-used by the Web-\n * Standards `validateCsrfRequest(request: Request)` sibling. Per the T5a.2\n * plan v1.0 § Phase B, header-only leaves are first to migrate. This is\n * the dual-signature pattern (anti-pattern #2 avoidance): IncomingMessage\n * consumers unchanged; new Request consumers go through the same logic\n * via the shared helper.\n *\n * Pure logic — accepts pre-extracted header values as strings or null.\n */\nfunction isCsrfValidFromHeaders(opts: {\n csrfActionHeader: string | null\n origin: string | null\n host: string | null\n}): { valid: true } | { valid: false; reason: string } {\n // 1. Custom header must be present (primary defense — simple form posts\n // cannot set custom headers, browsers gate via CORS preflight)\n if (opts.csrfActionHeader !== '1') {\n return { valid: false, reason: 'Missing X-Theo-Action header' }\n }\n\n // 2. Origin matching (secondary defense)\n if (opts.origin === null || opts.origin === '') {\n // Browsers omit Origin for same-origin requests — treat as valid\n return { valid: true }\n }\n\n if (opts.host === null || opts.host === '') {\n return { valid: true }\n }\n\n try {\n const originHost = new URL(opts.origin).host\n if (originHost !== opts.host) {\n return { valid: false, reason: `Origin ${opts.origin} does not match host ${opts.host}` }\n }\n } catch {\n return { valid: false, reason: `Invalid origin: ${opts.origin}` }\n }\n\n return { valid: true }\n}\n\nexport function validateCsrf(\n req: IncomingMessage,\n): { valid: true } | { valid: false; reason: string } {\n // IncomingMessage adapter — normalize Node header shape to the pure\n // helper's input shape (string|null).\n const action = req.headers['x-theo-action']\n const origin = req.headers.origin\n const host = req.headers.host\n return isCsrfValidFromHeaders({\n csrfActionHeader: typeof action === 'string' ? action : null,\n origin: origin !== undefined ? pickHeader(origin) || null : null,\n host: host !== undefined ? pickHeader(host) || null : null,\n })\n}\n\n/**\n * T5a.2 Phase B (slice 1/6) — Web-Standards-shaped CSRF validator.\n *\n * Mirror of `validateCsrf(req: IncomingMessage)` for the Web `Request`\n * shape. Consumes `request.headers.get(name)` (native Web `Headers` API)\n * instead of `req.headers[name]` (Node `IncomingMessage` indexer). Same\n * CSRF policy + same return shape — the difference is only the input\n * extraction.\n *\n * Used by `executeWebRequest` (T5a.2 Phase A) to enforce CSRF on the\n * Web-Standards request handler entry-point.\n */\nexport function validateCsrfRequest(\n request: Request,\n): { valid: true } | { valid: false; reason: string } {\n return isCsrfValidFromHeaders({\n csrfActionHeader: request.headers.get('x-theo-action'),\n origin: request.headers.get('origin'),\n host: request.headers.get('host'),\n })\n}\n\n/**\n * Enforce CSRF policy with mode-aware behavior. Wrapper over `validateCsrf`\n * that turns the boolean valid/invalid into a request-level allow decision,\n * gated by mode + structured warning in warn mode.\n *\n * Phase 5 — CSRF warn-first (EC-1). See plan docs/plans/nextjs-maturity-plan.md.\n */\n/**\n * Dispatch the csrf.warn payload to both the structured logger and the\n * audit sink (when configured). Extracted from `enforceCsrf` to keep that\n * function's complexity within ceiling.\n */\nfunction dispatchCsrfWarn(\n req: IncomingMessage,\n reason: string,\n logger: CsrfLogger | undefined,\n auditLogger: AuditLogger | undefined,\n pathFallback = '',\n): void {\n const payload: CsrfWarnPayload = {\n event: 'csrf.warn',\n method: req.method ?? 'UNKNOWN',\n path: logger?.path ?? pathFallback,\n reason,\n code: CSRF_WARN_CODE,\n docsUrl: CSRF_WARN_DOCS_URL,\n }\n logger?.warn(payload)\n // `metadata` is typed as Record<string, unknown>; CsrfWarnPayload is a\n // structurally-equivalent shape but lacks the index signature.\n safeAudit(auditLogger, {\n action: 'csrf.warn',\n actor: { type: 'anonymous' },\n metadata: { ...payload },\n })\n}\n\nexport function enforceCsrf(\n req: IncomingMessage,\n mode: CsrfMode,\n logger?: CsrfLogger,\n disallowed?: DisallowedConfig,\n auditLogger?: AuditLogger,\n): { allow: boolean; reason?: string } {\n if (mode === 'off') {\n // `off` short-circuits before disallowed dispatch — users who set\n // csrf: 'off' globally have explicitly turned validation off, and\n // disallowed must never re-introduce it. The escape hatch is to\n // set csrf: 'warn' and use disallowed for surgical strict pockets.\n return { allow: true }\n }\n\n const check = validateCsrf(req)\n if (check.valid) {\n return { allow: true }\n }\n\n // T5.1 — disallowed dispatch: when the failing request matches a\n // disallowed pattern AND behavior is 'raise', escalate to 403 even if\n // global mode is 'warn'. Strict mode would 403 anyway, so the branch\n // is a no-op there.\n if (disallowed?.behavior === 'raise') {\n const path = logger?.path ?? req.url ?? ''\n if (matchDisallowed(path, disallowed.routes)) {\n return { allow: false, reason: check.reason }\n }\n }\n\n if (mode === 'warn') {\n // T2.1: emit via warnOnce by default — callers can override via the\n // injected logger.warn (tests, custom log routers).\n // T2.2: include the stable cutover code + docsUrl so logs are\n // grep-able and click-through-able.\n dispatchCsrfWarn(req, check.reason, logger, auditLogger)\n return { allow: true, reason: check.reason }\n }\n\n // strict — 403 the request, AND emit a warn payload so the dev (and\n // devtools UI) sees WHY it was blocked + the docsUrl to fix it.\n // Without this, strict-mode users get a silent 403 with no context.\n dispatchCsrfWarn(req, check.reason, logger, auditLogger)\n return { allow: false, reason: check.reason }\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  theoConfigSchema
5
- } from "./chunk-X4JAX2U3.js";
5
+ } from "./chunk-4S2UCILN.js";
6
6
 
7
7
  // src/config/load-env.ts
8
8
  import { lstatSync, readFileSync, realpathSync, statSync } from "fs";
@@ -101,7 +101,6 @@ function loadEnv(options = {}) {
101
101
  // src/config/load-config.ts
102
102
  import { existsSync } from "fs";
103
103
  import { resolve as resolve2 } from "path";
104
- import { pathToFileURL } from "url";
105
104
 
106
105
  // src/config/errors.ts
107
106
  var TheoConfigError = class extends Error {
@@ -124,6 +123,38 @@ ${issueLines}
124
123
  }
125
124
  };
126
125
 
126
+ // src/config/import-user-module.ts
127
+ import { pathToFileURL } from "url";
128
+ var CYCLE_PATTERNS = [
129
+ // Node 22 strict ESM cycle detection when a registered loader hook
130
+ // re-enters its own evaluation context.
131
+ "require() ES Module",
132
+ "in a cycle",
133
+ // Vite SSR throws this when it cannot resolve an out-of-root URL.
134
+ "Failed to load url",
135
+ "Does the file exist?",
136
+ // Node native ESM resolver throws this for `.ts` files when no
137
+ // tsx loader is registered globally (the common test-worker case).
138
+ "Cannot find module",
139
+ // ERR_UNKNOWN_FILE_EXTENSION for `.ts` files.
140
+ "Unknown file extension"
141
+ ];
142
+ function isLoaderInteropError(err) {
143
+ if (!(err instanceof Error)) return false;
144
+ const msg = err.message;
145
+ return CYCLE_PATTERNS.some((p) => msg.includes(p));
146
+ }
147
+ async function importUserModule(absoluteFilePath, parentURL = import.meta.url) {
148
+ const fileURL = pathToFileURL(absoluteFilePath).href;
149
+ try {
150
+ return await import(fileURL);
151
+ } catch (err) {
152
+ if (!isLoaderInteropError(err)) throw err;
153
+ const { tsImport } = await import("tsx/esm/api");
154
+ return await tsImport(fileURL, parentURL);
155
+ }
156
+ }
157
+
127
158
  // src/config/load-config.ts
128
159
  var CONFIG_FILE = "theo.config.ts";
129
160
  function deepMerge(base, override) {
@@ -151,7 +182,7 @@ async function loadConfig(dir) {
151
182
  }
152
183
  let mod;
153
184
  try {
154
- mod = await import(pathToFileURL(configPath).href);
185
+ mod = await importUserModule(configPath);
155
186
  } catch (err) {
156
187
  throw new TheoConfigError([{ field: "_file", message: err.message }], configPath);
157
188
  }
@@ -174,7 +205,7 @@ async function loadConfig(dir) {
174
205
  const envPath = resolve2(dir, envFile);
175
206
  if (existsSync(envPath)) {
176
207
  try {
177
- const envMod = await import(pathToFileURL(envPath).href);
208
+ const envMod = await importUserModule(envPath);
178
209
  const envConfig = envMod.default;
179
210
  if (envConfig != null && typeof envConfig === "object") {
180
211
  rawConfig = deepMerge(rawConfig, envConfig);
@@ -196,7 +227,8 @@ async function loadConfig(dir) {
196
227
  }
197
228
 
198
229
  export {
230
+ importUserModule,
199
231
  loadEnv,
200
232
  loadConfig
201
233
  };
202
- //# sourceMappingURL=chunk-XP7YXRHO.js.map
234
+ //# sourceMappingURL=chunk-U6TPSW4L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/load-env.ts","../src/config/load-config.ts","../src/config/errors.ts","../src/config/import-user-module.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Reads `.env` files from a CLI-controlled `cwd`. File names are a fixed\n * literal set. Build-time + CLI tool; no HTTP input.\n */\n/**\n * `loadEnv()` — auto-loads `.env` files into `process.env` for server code.\n *\n * Implements the Next.js `loadEnvConfig` algorithm\n * (`referencias/next.js/packages/next-env/index.ts:114-180`) with TheoKit\n * adaptations:\n *\n * - EC-1: 1MB file-size cap (anti-OOM, anti-supply-chain).\n * - EC-2: `_resetEnvCache()` test-only side-door.\n * - EC-8: `dotenv-expand` circular-ref safe (lib-provided).\n * - EC-13: log when `.env` is a symlink (transparency).\n * - D6: real `process.env` wins over `.env`-file values.\n * - NODE_ENV stash: `.env`-set NODE_ENV NEVER overrides the real\n * `process.env.NODE_ENV`. Stashed in `__THEOKIT_USER_NODE_ENV` instead.\n */\n\nimport { lstatSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport dotenv from 'dotenv'\nimport { expand, type DotenvPopulateInput } from 'dotenv-expand'\n\nimport type { LoadEnvOptions, LoadEnvResult } from './load-env-types.js'\n\n/** EC-1: 1MB cap. Real `.env`s are < 10KB. */\nconst MAX_ENV_FILE_BYTES = 1_048_576\n\nconst cache = new Map<string, LoadEnvResult>()\n\n/** Test-only side-door for EC-2 — clear the module-level cache between vitest test files. */\nexport function _resetEnvCache(): void {\n cache.clear()\n}\n\nfunction envFilesInPriorityOrder(mode: string): string[] {\n // Top of list = highest priority. Will be read in REVERSE so first-in\n // wins via overwrite during merge.\n const files = [`.env.${mode}.local`, `.env.local`, `.env.${mode}`, `.env`]\n // Test mode skips `.env.local` per dotenv convention (avoid leaking dev\n // secrets into the test suite).\n if (mode === 'test') {\n return files.filter((f) => f !== '.env.local')\n }\n return files\n}\n\nfunction readEnvFile(path: string): Record<string, string> | null {\n let stat\n try {\n stat = statSync(path)\n } catch {\n return null // ENOENT / EACCES → skip\n }\n\n // Allow files + FIFOs (1Password/SOPS pipe support).\n if (!stat.isFile() && !stat.isFIFO()) return null\n\n // EC-1 — anti-OOM cap.\n if (stat.size > MAX_ENV_FILE_BYTES) {\n console.warn(\n `[theokit] .env file at ${path} exceeds ${MAX_ENV_FILE_BYTES} bytes — skipping (likely a generated artifact, not a real env file)`,\n )\n return null\n }\n\n // EC-13 — symlink transparency. Don't refuse; just log.\n try {\n const lstat = lstatSync(path)\n if (lstat.isSymbolicLink()) {\n const real = realpathSync(path)\n // eslint-disable-next-line no-console -- intentional transparency log on a build-time tool\n console.info(`[theokit] .env at ${path} is a symlink → ${real}`)\n }\n } catch {\n // lstat failure is non-fatal — fall through to read.\n }\n\n try {\n const content = readFileSync(path, 'utf-8')\n return dotenv.parse(content)\n } catch {\n return null\n }\n}\n\n// eslint-disable-next-line complexity -- canonical env-load algorithm (priority → expand → guards → apply); inlining branches is clearer than extracting micro-helpers\nexport function loadEnv(options: LoadEnvOptions = {}): LoadEnvResult {\n const cwd = options.cwd ?? process.cwd()\n const mode = options.mode ?? process.env.NODE_ENV ?? 'development'\n const cacheKey = `${cwd}:${mode}`\n\n if (!options.forceReload) {\n const cached = cache.get(cacheKey)\n if (cached) return cached\n }\n\n const fileNames = envFilesInPriorityOrder(mode)\n const filePaths = fileNames.map((f) => resolve(cwd, f))\n\n // Read in REVERSE — lower-priority files first, so higher-priority\n // (lower-index) overwrites during merge.\n const merged: Record<string, string> = {}\n const loadedFromFiles: string[] = []\n for (const path of [...filePaths].reverse()) {\n const parsed = readEnvFile(path)\n if (parsed === null) continue\n for (const [k, v] of Object.entries(parsed)) {\n merged[k] = v\n }\n loadedFromFiles.unshift(path) // keep priority order in result\n }\n\n // NODE_ENV stash — `.env`-set NODE_ENV never overrides real process.env.NODE_ENV.\n if (merged.NODE_ENV && process.env.__THEOKIT_USER_NODE_ENV === undefined) {\n process.env.__THEOKIT_USER_NODE_ENV = merged.NODE_ENV\n }\n delete merged.NODE_ENV // never propagate\n\n // EC-8 — dotenv-expand@11 stack-overflows on circular refs (A=${B}, B=${A}).\n // Wrap in try/catch — on overflow, leave the parsed map untouched (literal\n // values survive). Tested via test_loadEnv_circular_expand_no_loop_EC8.\n // Pass a CLONE of process.env (string-only, filtered) so expand can\n // reference real env without mutating it.\n const processEnvClone: DotenvPopulateInput = {}\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === 'string') processEnvClone[k] = v\n }\n try {\n expand({ parsed: merged, processEnv: processEnvClone })\n } catch (err) {\n if (err instanceof RangeError) {\n console.warn(\n `[theokit] .env expansion overflow (likely circular reference like A=\\${B}, B=\\${A}). Leaving values as literals.`,\n )\n } else {\n throw err\n }\n }\n\n // Apply: D6 — real process.env wins over file values.\n const loaded: Record<string, string> = {}\n for (const [k, v] of Object.entries(merged)) {\n if (process.env[k] !== undefined) continue // real env wins\n process.env[k] = v\n loaded[k] = v\n }\n\n // Sentinel\n process.env.__THEOKIT_PROCESSED_ENV = 'true'\n\n const result: LoadEnvResult = { loaded, loadedFromFiles }\n cache.set(cacheKey, result)\n return result\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Config loader. Reads `theo.config.{ts,js,mjs}` under the user's `cwd`.\n * Names are a fixed set of literals; `cwd` is a CLI arg resolved to\n * absolute. Build-time tool — no HTTP input.\n */\nimport { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport { TheoConfigError } from './errors.js'\nimport { importUserModule } from './import-user-module.js'\nimport { loadEnv } from './load-env.js'\nimport { theoConfigSchema } from './schema.js'\nimport type { TheoConfig } from './schema.js'\n\nconst CONFIG_FILE = 'theo.config.ts'\n\n/**\n * Deep merges two plain objects. Override values take precedence.\n * Arrays are replaced (not concatenated).\n * Protects against prototype pollution (EC-4).\n */\nexport function deepMerge(\n base: Record<string, unknown>,\n override: Record<string, unknown>,\n): Record<string, unknown> {\n const result = { ...base }\n for (const key of Object.keys(override)) {\n // EC-4: Prevent prototype pollution\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue\n\n const baseVal = base[key]\n const overVal = override[key]\n\n if (\n overVal !== null &&\n typeof overVal === 'object' &&\n !Array.isArray(overVal) &&\n baseVal !== null &&\n typeof baseVal === 'object' &&\n !Array.isArray(baseVal)\n ) {\n result[key] = deepMerge(\n baseVal as Record<string, unknown>,\n overVal as Record<string, unknown>,\n )\n } else {\n result[key] = overVal\n }\n }\n return result\n}\n\nexport async function loadConfig(dir: string): Promise<TheoConfig> {\n // T1.3 — Load .env BEFORE reading theo.config.ts. Defensive: CLI commands\n // (dev/build/start) already call loadEnv() first, but programmatic users\n // who call loadConfig directly (tests, custom scripts) need this too.\n // Module-level cache makes the second call a Map-lookup (no FS).\n loadEnv({ cwd: dir })\n\n const configPath = resolve(dir, CONFIG_FILE)\n\n if (!existsSync(configPath)) {\n return theoConfigSchema.parse({})\n }\n\n let mod: Record<string, unknown>\n try {\n mod = await importUserModule(configPath)\n } catch (err) {\n throw new TheoConfigError([{ field: '_file', message: (err as Error).message }], configPath)\n }\n\n const userConfig = mod.default\n\n if (userConfig == null || typeof userConfig !== 'object') {\n throw new TheoConfigError(\n [\n {\n field: '_export',\n message: 'theo.config.ts must use export default defineConfig({...})',\n },\n ],\n configPath,\n )\n }\n\n // Merge with per-environment config if NODE_ENV is set\n let rawConfig = userConfig as Record<string, unknown>\n const nodeEnv = process.env.NODE_ENV\n\n if (nodeEnv) {\n const envFile = `theo.config.${nodeEnv}.ts`\n const envPath = resolve(dir, envFile)\n\n if (existsSync(envPath)) {\n try {\n const envMod = await importUserModule(envPath)\n const envConfig = envMod.default\n\n if (envConfig != null && typeof envConfig === 'object') {\n rawConfig = deepMerge(rawConfig, envConfig as Record<string, unknown>)\n }\n } catch (err) {\n throw new TheoConfigError([{ field: '_file', message: (err as Error).message }], envPath)\n }\n }\n }\n\n const result = theoConfigSchema.safeParse(rawConfig)\n\n if (!result.success) {\n const issues = result.error.issues.map((i) => ({\n field: i.path.join('.'),\n message: i.message,\n }))\n throw new TheoConfigError(issues, configPath)\n }\n\n return result.data\n}\n","export interface ConfigIssue {\n field: string\n message: string\n}\n\nexport class TheoConfigError extends Error {\n public readonly issues: ConfigIssue[]\n public readonly configPath: string\n\n constructor(issues: ConfigIssue[], configPath: string) {\n const issueLines = issues.map((i) => ` - ${i.field}: ${i.message}`).join('\\n')\n\n super(\n `Invalid theo.config.ts\\n\\n` +\n ` File: ${configPath}\\n\\n` +\n (issueLines ? ` Issues:\\n${issueLines}\\n` : ''),\n )\n\n this.name = 'TheoConfigError'\n this.issues = issues\n this.configPath = configPath\n }\n}\n","/**\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":"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","names":["resolve","resolve"]}
@@ -0,0 +1,45 @@
1
+ // src/server/observability/audit-log.ts
2
+ var JsonStdoutSink = class {
3
+ log(event) {
4
+ const enriched = {
5
+ level: "audit",
6
+ ...event,
7
+ timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
8
+ };
9
+ try {
10
+ console.log(JSON.stringify(enriched, jsonReplacer));
11
+ } catch {
12
+ console.log(
13
+ `{"level":"audit","action":${JSON.stringify(event.action)},"timestamp":${JSON.stringify(enriched.timestamp)},"note":"payload could not be serialized"}`
14
+ );
15
+ }
16
+ }
17
+ };
18
+ function jsonReplacer(_key, value) {
19
+ if (typeof value === "bigint") return value.toString();
20
+ return value;
21
+ }
22
+ function createNoOpLogger() {
23
+ return {
24
+ log() {
25
+ }
26
+ };
27
+ }
28
+ function safeAudit(logger, event) {
29
+ if (!logger) return;
30
+ try {
31
+ const r = logger.log(event);
32
+ if (r && typeof r.then === "function") {
33
+ r.catch(() => {
34
+ });
35
+ }
36
+ } catch {
37
+ }
38
+ }
39
+
40
+ export {
41
+ JsonStdoutSink,
42
+ createNoOpLogger,
43
+ safeAudit
44
+ };
45
+ //# sourceMappingURL=chunk-UD3LFGDL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/observability/audit-log.ts"],"sourcesContent":["/**\n * T4.1 — Audit logging interface + default JSON stdout sink.\n *\n * Per ADR D4: define the interface; ship a zero-dep default; reserve\n * adapter shapes for Postgres, File, OpenTelemetry, Sentry as follow-up\n * packages. Persistence has heavy deps (`pg`, `better-sqlite3`); we\n * keep core dep-free and let users opt in.\n *\n * Compatibility:\n * - Node / Bun / Deno / Vercel — console.log is sync, captured.\n * - Edge runtimes (CF Workers, Vercel Edge) — console.log is captured\n * but may be rate-limited by the platform. For high-volume edge audit,\n * implement a custom sink writing to a queue / HTTP endpoint.\n */\n\nexport interface AuditEvent {\n /** Domain-qualified verb. Convention: `<domain>.<verb>` (e.g. csrf.warn, session.rotated). */\n action: string\n /** Who triggered the event. Anonymous = no auth at time of event. */\n actor?: { type: 'user' | 'system' | 'anonymous'; id?: string }\n /** What was operated on (optional). */\n resource?: { type: string; id?: string }\n /** Arbitrary event-specific metadata. JSON-serializable. */\n metadata?: Record<string, unknown>\n /** ISO 8601 timestamp. If absent, sink fills in `new Date().toISOString()`. */\n timestamp?: string\n /** Optional trace id (populated by middleware from `x-trace-id`). */\n traceId?: string\n}\n\nexport interface AuditLogger {\n log(event: AuditEvent): void | Promise<void>\n}\n\n/**\n * Default sink: one JSON line per event to stdout. Sync. Never throws.\n *\n * EC: circular refs / BigInt values fall back to a placeholder line so\n * the event is still observable (action + traceId) without crashing the\n * request lifecycle.\n */\nexport class JsonStdoutSink implements AuditLogger {\n log(event: AuditEvent): void {\n const enriched = {\n level: 'audit' as const,\n ...event,\n timestamp: event.timestamp ?? new Date().toISOString(),\n }\n try {\n // eslint-disable-next-line no-console -- JsonStdoutSink IS the audit output\n console.log(JSON.stringify(enriched, jsonReplacer))\n } catch {\n // eslint-disable-next-line no-console -- fallback when payload won't serialize\n console.log(\n `{\"level\":\"audit\",\"action\":${JSON.stringify(event.action)},\"timestamp\":${JSON.stringify(enriched.timestamp)},\"note\":\"payload could not be serialized\"}`,\n )\n }\n }\n}\n\n/**\n * Replacer that walks BigInt → string. Circular ref handling is via the\n * outer try/catch (JSON.stringify throws TypeError on cycles; we drop to\n * the fallback line). We don't implement custom cycle-breaking walker\n * because the audit payload is meant to be JSON — if user metadata has\n * a cycle, the right answer is to fix the caller, not silently lose\n * the structure.\n */\nfunction jsonReplacer(_key: string, value: unknown): unknown {\n if (typeof value === 'bigint') return value.toString()\n return value\n}\n\n/**\n * No-op logger. Returned when `config.audit` is unset. Zero overhead;\n * framework wiring sites null-check before calling.\n */\nexport function createNoOpLogger(): AuditLogger {\n return {\n log() {\n // intentionally empty\n },\n }\n}\n\n/**\n * T4.2 — Safe-emit wrapper. Used by framework wiring sites (csrf.ts,\n * rate-limit.ts, session.ts) so a logger throw NEVER propagates into\n * the request handler.\n */\nexport function safeAudit(logger: AuditLogger | undefined, event: AuditEvent): void {\n if (!logger) return\n try {\n const r = logger.log(event)\n // Discard the Promise — async sinks are fire-and-forget by design.\n if (r && typeof r.then === 'function') {\n r.catch(() => {\n // swallow async sink failures — audit must never crash the request\n })\n }\n } catch {\n // swallow sync sink failures — audit must never crash the request\n }\n}\n"],"mappings":";AAyCO,IAAM,iBAAN,MAA4C;AAAA,EACjD,IAAI,OAAyB;AAC3B,UAAM,WAAW;AAAA,MACf,OAAO;AAAA,MACP,GAAG;AAAA,MACH,WAAW,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACvD;AACA,QAAI;AAEF,cAAQ,IAAI,KAAK,UAAU,UAAU,YAAY,CAAC;AAAA,IACpD,QAAQ;AAEN,cAAQ;AAAA,QACN,6BAA6B,KAAK,UAAU,MAAM,MAAM,CAAC,gBAAgB,KAAK,UAAU,SAAS,SAAS,CAAC;AAAA,MAC7G;AAAA,IACF;AAAA,EACF;AACF;AAUA,SAAS,aAAa,MAAc,OAAyB;AAC3D,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,SAAS;AACrD,SAAO;AACT;AAMO,SAAS,mBAAgC;AAC9C,SAAO;AAAA,IACL,MAAM;AAAA,IAEN;AAAA,EACF;AACF;AAOO,SAAS,UAAU,QAAiC,OAAyB;AAClF,MAAI,CAAC,OAAQ;AACb,MAAI;AACF,UAAM,IAAI,OAAO,IAAI,KAAK;AAE1B,QAAI,KAAK,OAAO,EAAE,SAAS,YAAY;AACrC,QAAE,MAAM,MAAM;AAAA,MAEd,CAAC;AAAA,IACH;AAAA,EACF,QAAQ;AAAA,EAER;AACF;","names":[]}
@@ -0,0 +1,161 @@
1
+ import {
2
+ extractTraceContext,
3
+ generateNewTraceContext
4
+ } from "./chunk-6NEXVBPY.js";
5
+ import {
6
+ __require
7
+ } from "./chunk-DGUM43GV.js";
8
+
9
+ // src/server/webhook/timing-safe-equal.ts
10
+ var cachedNodeImpl;
11
+ function resolveNodeImpl() {
12
+ if (cachedNodeImpl !== void 0) return cachedNodeImpl;
13
+ try {
14
+ const cryptoMod = __require("crypto");
15
+ cachedNodeImpl = cryptoMod.timingSafeEqual ?? null;
16
+ } catch {
17
+ cachedNodeImpl = null;
18
+ }
19
+ return cachedNodeImpl;
20
+ }
21
+ function timingSafeEqual(a, b) {
22
+ if (!(a instanceof Uint8Array) || !(b instanceof Uint8Array)) {
23
+ throw new TypeError(
24
+ `timingSafeEqual expects Uint8Array arguments (got ${typeof a} and ${typeof b})`
25
+ );
26
+ }
27
+ if (a.length !== b.length) return false;
28
+ if (a.length === 0) return true;
29
+ const nodeImpl = resolveNodeImpl();
30
+ if (nodeImpl) return nodeImpl(a, b);
31
+ let diff = 0;
32
+ for (let i = 0; i < a.length; i++) {
33
+ diff |= a[i] ^ b[i];
34
+ }
35
+ return diff === 0;
36
+ }
37
+
38
+ // src/server/webhook/raw-body.ts
39
+ var DEFAULT_MAX_BODY_BYTES = 1e6;
40
+ var BodyTooLargeError = class extends Error {
41
+ constructor(limit, actualSeen) {
42
+ super(`Request body exceeds maxBodyBytes: seen ${actualSeen} bytes, limit ${limit} bytes`);
43
+ this.limit = limit;
44
+ this.actualSeen = actualSeen;
45
+ this.name = "BodyTooLargeError";
46
+ }
47
+ limit;
48
+ actualSeen;
49
+ status = 413;
50
+ code = "BODY_TOO_LARGE";
51
+ };
52
+ async function readRawBody(request, options = {}) {
53
+ const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
54
+ const clone = request.clone();
55
+ if (clone.body === null) {
56
+ return { rawBody: "", bodyClone: request };
57
+ }
58
+ const reader = clone.body.getReader();
59
+ const chunks = [];
60
+ let total = 0;
61
+ try {
62
+ for (; ; ) {
63
+ const { value, done } = await reader.read();
64
+ if (done) break;
65
+ total += value.byteLength;
66
+ if (total > maxBodyBytes) {
67
+ void reader.cancel();
68
+ throw new BodyTooLargeError(maxBodyBytes, total);
69
+ }
70
+ chunks.push(value);
71
+ }
72
+ } finally {
73
+ try {
74
+ reader.releaseLock();
75
+ } catch {
76
+ }
77
+ }
78
+ const bytes = new Uint8Array(total);
79
+ let offset = 0;
80
+ for (const chunk of chunks) {
81
+ bytes.set(chunk, offset);
82
+ offset += chunk.byteLength;
83
+ }
84
+ const rawBody = new TextDecoder().decode(bytes);
85
+ return { rawBody, bodyClone: request };
86
+ }
87
+
88
+ // src/server/webhook/define-webhook.ts
89
+ function defineWebhook(opts) {
90
+ return {
91
+ verify: opts.verify,
92
+ handler: opts.handler,
93
+ maxBodyBytes: opts.maxBodyBytes,
94
+ __theokit_kind: "webhook"
95
+ };
96
+ }
97
+ async function dispatchWebhook(def, request) {
98
+ let rawBody;
99
+ let bodyClone;
100
+ try {
101
+ const result2 = await readRawBody(request, { maxBodyBytes: def.maxBodyBytes });
102
+ rawBody = result2.rawBody;
103
+ bodyClone = result2.bodyClone;
104
+ } catch (err) {
105
+ if (err instanceof BodyTooLargeError) {
106
+ return new Response(JSON.stringify({ error: err.code, message: err.message }), {
107
+ status: 413,
108
+ headers: { "content-type": "application/json" }
109
+ });
110
+ }
111
+ return new Response(
112
+ JSON.stringify({
113
+ error: "BAD_REQUEST",
114
+ message: err instanceof Error ? err.message : "failed to read body"
115
+ }),
116
+ { status: 400, headers: { "content-type": "application/json" } }
117
+ );
118
+ }
119
+ const incomingTrace = extractTraceContext(request.headers);
120
+ const traceId = incomingTrace?.trace_id ?? generateNewTraceContext().trace_id;
121
+ let verifyResult;
122
+ try {
123
+ verifyResult = await def.verify(bodyClone);
124
+ } catch (err) {
125
+ verifyResult = {
126
+ ok: false,
127
+ reason: `verify threw: ${err instanceof Error ? err.message : String(err)}`
128
+ };
129
+ }
130
+ if (!verifyResult.ok) {
131
+ return new Response(
132
+ JSON.stringify({ error: "WEBHOOK_VERIFY_FAILED", message: verifyResult.reason }),
133
+ { status: 401, headers: { "content-type": "application/json" } }
134
+ );
135
+ }
136
+ const ctx = {
137
+ request: bodyClone,
138
+ rawBody,
139
+ traceId,
140
+ signal: request.signal
141
+ };
142
+ const result = await def.handler(ctx);
143
+ if (result instanceof Response) return result;
144
+ if (result === void 0 || result === null) {
145
+ return new Response(null, { status: 204 });
146
+ }
147
+ return new Response(JSON.stringify(result), {
148
+ status: 200,
149
+ headers: { "content-type": "application/json" }
150
+ });
151
+ }
152
+
153
+ export {
154
+ timingSafeEqual,
155
+ DEFAULT_MAX_BODY_BYTES,
156
+ BodyTooLargeError,
157
+ readRawBody,
158
+ defineWebhook,
159
+ dispatchWebhook
160
+ };
161
+ //# sourceMappingURL=chunk-UUFYP2UM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/webhook/timing-safe-equal.ts","../src/server/webhook/raw-body.ts","../src/server/webhook/define-webhook.ts"],"sourcesContent":["/**\n * Constant-time byte comparison.\n *\n * Wraps `node:crypto.timingSafeEqual` when available (Node 6.6+) and falls\n * back to a constant-time XOR loop for runtimes without `node:crypto`\n * (Cloudflare Workers, Deno, Bun edge). Required to defeat timing attacks\n * on webhook signature verification — a naive `===` or `Buffer.equals`\n * would short-circuit on first mismatch byte and leak signature position\n * via wall-clock timing.\n *\n * Web Crypto's `crypto.subtle.verify` would also work, but requires a\n * `CryptoKey` object and is asymmetric (verify a signature against a key).\n * For our case — comparing two pre-computed digests — raw byte equality\n * is the correct primitive.\n *\n * @see https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/verify\n */\n\ntype NodeTimingSafeEqual = (a: Uint8Array, b: Uint8Array) => boolean\n\nlet cachedNodeImpl: NodeTimingSafeEqual | null | undefined\n\nfunction resolveNodeImpl(): NodeTimingSafeEqual | null {\n if (cachedNodeImpl !== undefined) return cachedNodeImpl\n try {\n // require() avoids the dynamic-import-of-node-builtin warnings some\n // bundlers emit; `node:crypto` is always synchronously available.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const cryptoMod = require('node:crypto') as {\n timingSafeEqual?: NodeTimingSafeEqual\n }\n cachedNodeImpl = cryptoMod.timingSafeEqual ?? null\n } catch {\n cachedNodeImpl = null\n }\n return cachedNodeImpl\n}\n\n/**\n * Returns true iff `a` and `b` have identical bytes. Takes time\n * proportional to `a.length` regardless of where bytes differ.\n *\n * @throws TypeError if either argument is not a Uint8Array.\n */\nexport function timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (!(a instanceof Uint8Array) || !(b instanceof Uint8Array)) {\n throw new TypeError(\n `timingSafeEqual expects Uint8Array arguments (got ${typeof a} and ${typeof b})`,\n )\n }\n // Length mismatch is constant-time-safe by construction (no per-byte work).\n if (a.length !== b.length) return false\n if (a.length === 0) return true\n\n // Prefer the Node built-in when present — it's implemented in C and\n // matches the contract exactly. node:crypto.timingSafeEqual throws on\n // length mismatch, which we've already filtered above.\n const nodeImpl = resolveNodeImpl()\n if (nodeImpl) return nodeImpl(a, b)\n\n // Fallback: XOR-accumulate every byte into one accumulator. NEVER\n // short-circuit. The compiler / V8 will not constant-fold this loop\n // because the inputs are dynamic.\n let diff = 0\n for (let i = 0; i < a.length; i++) {\n diff |= a[i] ^ b[i]\n }\n return diff === 0\n}\n","/**\n * Read a Web `Request` body as a raw string EXACTLY ONCE and expose it\n * alongside the original request (which remains readable by downstream\n * code). Enforces a configurable `maxBodyBytes` cap to prevent OOM via\n * pathological POST.\n *\n * MUST be called FIRST in the webhook pipeline, before any other code\n * touches the body (`request.text()`, `request.json()`, parsers). Once\n * the body is consumed, `Request.clone()` throws and this function fails.\n *\n * EC-101: default `maxBodyBytes = 1_000_000` (1 MB) covers Stripe\n * (256 KB max), Slack (4 MB but compressed), and is well below Node\n * memory thresholds. GitHub webhooks up to 25 MB MUST opt in\n * (`maxBodyBytes: 25_000_000`).\n *\n * @see https://docs.stripe.com/webhooks/signatures\n * @see https://docs.github.com/en/webhooks/using-webhooks/best-practices-for-using-webhooks\n */\n\nexport const DEFAULT_MAX_BODY_BYTES = 1_000_000\n\nexport interface ReadRawBodyOptions {\n /** Maximum bytes to read before throwing `BodyTooLargeError`. Defaults to 1 MB. */\n maxBodyBytes?: number\n}\n\nexport interface RawBodyResult {\n /** UTF-8 decoded body (or empty string when no body present). */\n rawBody: string\n /** The ORIGINAL request, still readable by downstream code. */\n bodyClone: Request\n}\n\n/**\n * Thrown when the request body exceeds `maxBodyBytes`. Carries status\n * 413 (Payload Too Large) and stable code `BODY_TOO_LARGE` so callers\n * can map it to an HTTP response without sniffing the message.\n */\nexport class BodyTooLargeError extends Error {\n readonly status = 413\n readonly code = 'BODY_TOO_LARGE'\n\n constructor(\n public readonly limit: number,\n public readonly actualSeen: number,\n ) {\n super(`Request body exceeds maxBodyBytes: seen ${actualSeen} bytes, limit ${limit} bytes`)\n this.name = 'BodyTooLargeError'\n }\n}\n\nexport async function readRawBody(\n request: Request,\n options: ReadRawBodyOptions = {},\n): Promise<RawBodyResult> {\n const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES\n\n // Clone the request so the original remains readable. `.clone()` throws\n // synchronously (TypeError) if the body was already consumed — we let\n // that propagate so callers fail fast with a clear error.\n const clone = request.clone()\n\n // No body at all (GET, HEAD, or empty POST). Both clone.body and\n // clone.text() handle this gracefully but we short-circuit for clarity\n // and to avoid an unnecessary stream read.\n if (clone.body === null) {\n return { rawBody: '', bodyClone: request }\n }\n\n const reader = clone.body.getReader()\n const chunks: Uint8Array[] = []\n let total = 0\n\n try {\n for (;;) {\n const { value, done } = await reader.read()\n if (done) break\n total += value.byteLength\n if (total > maxBodyBytes) {\n // Cancel the stream without awaiting (avoids deadlock on some\n // ReadableStream impls). The finally block releases the lock.\n void reader.cancel()\n throw new BodyTooLargeError(maxBodyBytes, total)\n }\n chunks.push(value)\n }\n } finally {\n try {\n reader.releaseLock()\n } catch {\n // lock may already be released by cancel()\n }\n }\n\n // Concat all chunks into a single Uint8Array, then UTF-8 decode.\n const bytes = new Uint8Array(total)\n let offset = 0\n for (const chunk of chunks) {\n bytes.set(chunk, offset)\n offset += chunk.byteLength\n }\n const rawBody = new TextDecoder().decode(bytes)\n\n return { rawBody, bodyClone: request }\n}\n","import {\n extractTraceContext,\n generateNewTraceContext,\n} from '../observability/trace-context-propagation.js'\n\nimport { BodyTooLargeError, readRawBody } from './raw-body.js'\nimport type {\n DefineWebhookOptions,\n VerifyResult,\n WebhookContext,\n WebhookDefinition,\n} from './webhook-types.js'\n\n/**\n * Declare a webhook handler with first-class signature verification\n * (R0.5.10, ADR-0005). Pure identity helper — returns the definition\n * unchanged for downstream dispatch.\n *\n * @example\n * ```ts\n * // server/webhooks/stripe.ts\n * import { defineWebhook } from 'theokit/server'\n * import { stripe } from 'theokit/server/webhook/providers'\n *\n * export default defineWebhook({\n * verify: stripe({ secret: process.env.STRIPE_WEBHOOK_SECRET! }),\n * async handler({ rawBody }) {\n * const event = JSON.parse(rawBody)\n * // ...\n * return new Response('ok')\n * },\n * })\n * ```\n */\nexport function defineWebhook(opts: DefineWebhookOptions): WebhookDefinition {\n return {\n verify: opts.verify,\n handler: opts.handler,\n maxBodyBytes: opts.maxBodyBytes,\n __theokit_kind: 'webhook',\n }\n}\n\n/**\n * Dispatch a webhook request through the definition's verify → handler\n * pipeline. Returns the handler's `Response` (or a wrapped one), or a\n * 401/413 response when verification or body size guards trip.\n *\n * EC-101: enforces `maxBodyBytes` (default 1MB via readRawBody).\n * EC-103: every throw from `verify` (sync or async) is treated as\n * `{ok: false, reason: 'verify threw: <message>'}`. Handler NEVER\n * invoked on verify failure.\n */\nexport async function dispatchWebhook(def: WebhookDefinition, request: Request): Promise<Response> {\n let rawBody: string\n let bodyClone: Request\n try {\n const result = await readRawBody(request, { maxBodyBytes: def.maxBodyBytes })\n rawBody = result.rawBody\n bodyClone = result.bodyClone\n } catch (err) {\n if (err instanceof BodyTooLargeError) {\n return new Response(JSON.stringify({ error: err.code, message: err.message }), {\n status: 413,\n headers: { 'content-type': 'application/json' },\n })\n }\n return new Response(\n JSON.stringify({\n error: 'BAD_REQUEST',\n message: err instanceof Error ? err.message : 'failed to read body',\n }),\n { status: 400, headers: { 'content-type': 'application/json' } },\n )\n }\n\n // Resolve traceId — propagate or generate.\n const incomingTrace = extractTraceContext(request.headers)\n const traceId = incomingTrace?.trace_id ?? generateNewTraceContext().trace_id\n\n // EC-103: verify exception MUST close the door, never let handler run.\n let verifyResult: VerifyResult\n try {\n verifyResult = await def.verify(bodyClone)\n } catch (err) {\n verifyResult = {\n ok: false,\n reason: `verify threw: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n\n if (!verifyResult.ok) {\n return new Response(\n JSON.stringify({ error: 'WEBHOOK_VERIFY_FAILED', message: verifyResult.reason }),\n { status: 401, headers: { 'content-type': 'application/json' } },\n )\n }\n\n const ctx: WebhookContext = {\n request: bodyClone,\n rawBody,\n traceId,\n signal: request.signal,\n }\n\n const result = await def.handler(ctx)\n if (result instanceof Response) return result\n if (result === undefined || result === null) {\n return new Response(null, { status: 204 })\n }\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: { 'content-type': 'application/json' },\n })\n}\n"],"mappings":"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","names":["result"]}
@@ -2,7 +2,7 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  walkSourceFiles
5
- } from "./chunk-5OFPQK6N.js";
5
+ } from "./chunk-COXLEZCN.js";
6
6
 
7
7
  // src/core/contracts/http-methods.ts
8
8
  var HTTP_METHODS = [
@@ -268,4 +268,4 @@ export {
268
268
  scanServerRoutes,
269
269
  scanWebSocketRoutes
270
270
  };
271
- //# sourceMappingURL=chunk-OXIQI2XZ.js.map
271
+ //# sourceMappingURL=chunk-VBZCVFSA.js.map