theokit 0.4.0-beta.0 → 0.5.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 +61 -9
  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
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/http/cookies.ts","../src/server/auth/crypto.ts","../src/server/auth/session.ts","../src/server/_internal/encoding.ts","../src/server/auth/auth-totp.ts","../src/server/auth/auth-backup-codes.ts","../src/server/auth/auth-throttle.ts","../src/server/auth/oauth-pkce.ts","../src/server/auth/oauth-state.ts","../src/server/auth/oidc-discovery.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\n\nexport interface CookieOptions {\n httpOnly?: boolean\n secure?: boolean\n sameSite?: 'strict' | 'lax' | 'none'\n maxAge?: number\n path?: string\n domain?: string\n}\n\n/**\n * Parse a `Cookie` header into a Map (RFC 6265 §5.4).\n * - Empty/missing input → empty Map.\n * - Malformed entries (no `=`) skipped silently (defensive).\n * - Duplicate names → last-wins.\n * - Values URL-decoded if possible; raw on decode failure (CR-009 protection).\n *\n * Canonical helper (T3.2 of architecture-review-remediation-plan; PV-4 DRY).\n * Consumed by `getCookie` here AND by `rate-limit/rate-limit-per-route.ts`.\n */\nexport function parseCookieHeader(header: string | undefined): Map<string, string> {\n const map = new Map<string, string>()\n if (!header) return map\n for (const pair of header.split(';')) {\n const trimmed = pair.trim()\n const eqIdx = trimmed.indexOf('=')\n if (eqIdx === -1) continue\n const key = trimmed.slice(0, eqIdx)\n const rawValue = trimmed.slice(eqIdx + 1)\n let value: string\n try {\n value = decodeURIComponent(rawValue)\n } catch {\n // Malformed percent-encoding — preserve raw to not lose data,\n // but the consumer is responsible for treating it as untrusted.\n value = rawValue\n }\n map.set(key, value)\n }\n return map\n}\n\nexport function getCookie(req: IncomingMessage, name: string): string | undefined {\n const cookies = parseCookieHeader(req.headers.cookie)\n const value = cookies.get(name)\n // CR-009 fix: malformed percent-encoding returns raw via parseCookieHeader.\n // If decoding failed in parse, we get the raw value (with %XX intact).\n // Treat that as \"unreadable\" for the typed getCookie API to preserve the\n // original \"treat as unauthenticated\" semantics.\n if (value === undefined) return undefined\n // Sanity: if rawValue contains lone `%` that didn't decode, parseCookieHeader\n // returned the raw — return undefined to preserve old getCookie contract.\n if (/(?:%[^0-9A-Fa-f])|(?:%[0-9A-Fa-f]$)/.test(value)) return undefined\n return value\n}\n\nexport function setCookie(\n res: ServerResponse,\n name: string,\n value: string,\n options?: CookieOptions,\n): void {\n const opts: Required<Omit<CookieOptions, 'maxAge' | 'domain'>> &\n Pick<CookieOptions, 'maxAge' | 'domain'> = {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n ...options,\n }\n\n const parts = [`${name}=${encodeURIComponent(value)}`]\n if (opts.httpOnly) parts.push('HttpOnly')\n if (opts.secure) parts.push('Secure')\n // sameSite has a default ('lax') so it is always defined after the\n // spread. Keep the cast inside the value computation to avoid a wide\n // re-narrowing branch in CSV output.\n const sameSiteCanonical = opts.sameSite.charAt(0).toUpperCase() + opts.sameSite.slice(1)\n parts.push(`SameSite=${sameSiteCanonical}`)\n if (opts.maxAge !== undefined) parts.push(`Max-Age=${opts.maxAge}`)\n if (opts.path) parts.push(`Path=${opts.path}`)\n if (opts.domain) parts.push(`Domain=${opts.domain}`)\n\n // Append to existing Set-Cookie headers (EC-1: don't overwrite)\n const existing = res.getHeader('Set-Cookie')\n let cookies: string[] = []\n if (Array.isArray(existing)) {\n cookies = existing.map(String)\n } else if (existing !== undefined) {\n cookies = [String(existing)]\n }\n cookies.push(parts.join('; '))\n res.setHeader('Set-Cookie', cookies)\n}\n\nexport function deleteCookie(res: ServerResponse, name: string, options?: { path?: string }): void {\n setCookie(res, name, '', { maxAge: 0, path: options?.path ?? '/' })\n}\n","// AES-GCM-256 token encryption with cached key derivation.\n//\n// CR-002 fixes:\n// - KDF: HKDF (RFC 5869) over the raw secret, not raw SHA-256.\n// HKDF binds the application context (\"theo-session-v1\") into the\n// derived key so the same secret used elsewhere cannot decrypt these\n// tokens. SHA-256 of the raw secret has neither domain separation nor\n// proper key-stretching guarantees.\n// - Cache: derived `CryptoKey` is memoized per (secret, info) tuple.\n// Pre-fix, every encrypt/decrypt re-ran SHA-256 + importKey, which (a)\n// burned CPU on every authenticated request and (b) made\n// `decryptWithFallback` leak rotation-array position via timing.\n// - Buffer typing: `Uint8Array` flows directly into Web Crypto\n// (`BufferSource`-compatible). The previous `as unknown as ArrayBuffer`\n// double-cast (CR-016) is removed.\n\nconst encoder = new TextEncoder()\nconst decoder = new TextDecoder()\n\nconst HKDF_INFO_DEFAULT = encoder.encode('theo-session-v1')\nconst HKDF_SALT_EMPTY = new Uint8Array(0)\n\n// Memoize derived keys. Bounded by the number of distinct secrets the app\n// ever uses (typically 1 in steady state, 2-5 during rotation). Map-based\n// so distinct secrets do not evict each other.\nconst keyCache = new Map<string, Promise<CryptoKey>>()\n\nasync function deriveKey(secret: string): Promise<CryptoKey> {\n const cached = keyCache.get(secret)\n if (cached) return cached\n\n const derive = (async () => {\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HKDF' },\n false,\n ['deriveKey'],\n )\n return crypto.subtle.deriveKey(\n { name: 'HKDF', hash: 'SHA-256', salt: HKDF_SALT_EMPTY, info: HKDF_INFO_DEFAULT },\n keyMaterial,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt'],\n )\n })()\n\n keyCache.set(secret, derive)\n // If derivation fails (invalid secret), evict so a retry can try fresh.\n derive.catch(() => {\n keyCache.delete(secret)\n })\n return derive\n}\n\nfunction toBase64Url(data: Uint8Array): string {\n return Buffer.from(data).toString('base64url')\n}\n\n/**\n * Decode a base64url string into a `Uint8Array<ArrayBuffer>`. The explicit\n * generic matters: Web Crypto APIs expect `BufferSource`, and TS 5.7+\n * tightened `Uint8Array` to `Uint8Array<ArrayBufferLike>` which includes\n * `SharedArrayBuffer`. Returning the narrower generic lets the value pass\n * `crypto.subtle.decrypt` without `as` casts (CR-016 follow-through).\n */\nfunction fromBase64Url(str: string): Uint8Array<ArrayBuffer> {\n const buf = Buffer.from(str, 'base64url')\n const copy = new Uint8Array(buf.length)\n copy.set(buf)\n return copy\n}\n\n// The `T` generic exists so call sites get type-safe round-tripping\n// (`encrypt<Session>(s, ...)` pairs with `decrypt<Session>(...)`); the\n// runtime body just stringifies `data`, hence T does not appear in the\n// signature beyond the argument.\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- T documents the round-trip contract with decrypt<T>\nexport async function encrypt<T>(data: T, secret: string): Promise<string> {\n const key = await deriveKey(secret)\n const iv = crypto.getRandomValues(new Uint8Array(12))\n const plaintext = encoder.encode(JSON.stringify(data))\n const ciphertext = new Uint8Array(\n await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext),\n )\n return `${toBase64Url(iv)}:${toBase64Url(ciphertext)}`\n}\n\nexport async function decrypt<T>(token: string, secret: string): Promise<T | null> {\n try {\n const parts = token.split(':')\n if (parts.length !== 2) return null\n\n const iv = fromBase64Url(parts[0])\n const ciphertext = fromBase64Url(parts[1])\n const key = await deriveKey(secret)\n\n const plaintext = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext)\n return JSON.parse(decoder.decode(plaintext)) as T\n } catch {\n return null\n }\n}\n\n/**\n * Reset the derived-key cache. Test helper — never call from production code.\n * Used by Vitest to guarantee isolation between tests that use distinct\n * secrets and want to confirm the derivation path runs.\n */\nexport function _resetKeyCacheForTests(): void {\n keyCache.clear()\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport { getCookie, setCookie, deleteCookie } from '../http/cookies.js'\n\nimport { encrypt, decrypt } from './crypto.js'\n\nexport interface SessionConfig {\n /**\n * Session secret. Either a single string (legacy) or an array of strings\n * where index 0 is the newest. The array form enables dual-key rotation\n * (T3.1 / ADR D5): encrypt always uses `secrets[0]`, decrypt walks the\n * array, transparent re-encrypt on legacy hits (T3.2).\n *\n * EC-1: array length capped at 5 — enforced via throw at construction.\n */\n secret: string | string[]\n cookieName?: string\n maxAge?: number\n}\n\ninterface SessionEnvelope<T> {\n data: T\n exp: number\n}\n\nexport interface SessionMeta {\n /** Index of the secret that decrypted the session. 0 = newest; > 0 = legacy. */\n secretIndex: number\n /** True when the decrypt used a legacy secret and the cookie should be re-encrypted. */\n needsReencrypt: boolean\n}\n\nexport interface SessionManager<TSession> {\n getSession(req: IncomingMessage): Promise<TSession | null>\n /**\n * T3.2 — Variant of `getSession` that surfaces decrypt metadata.\n * Used by `api-middleware.ts` to wire transparent re-encrypt BEFORE\n * the handler runs (so streaming SSR routes don't miss the Set-Cookie\n * window — EC-4).\n */\n getSessionWithMeta(req: IncomingMessage): Promise<{ data: TSession | null; meta: SessionMeta }>\n createSession(res: ServerResponse, data: TSession): Promise<void>\n destroySession(res: ServerResponse): void\n /**\n * T3.3 — OWASP A07:2021 session fixation mitigation. Re-encrypts the\n * current session with a fresh IV and refreshed expiry. No-op when no\n * session is present.\n */\n rotateSession(req: IncomingMessage, res: ServerResponse): Promise<TSession | null>\n}\n\n/**\n * EC-1 — array length cap. Enforced via throw at construction. Silent\n * truncation would create false sense of rotation; silent acceptance\n * would create unbounded CPU on legacy decrypt walks.\n */\nconst MAX_SECRETS = 5\n\n/**\n * Validate + normalize the secret config into a non-empty array of\n * strings ≥ 32 chars each.\n */\nfunction normalizeSecrets(input: string | string[]): string[] {\n const arr = Array.isArray(input) ? input.slice() : [input]\n if (arr.length === 0) {\n throw new Error('Session secret must be non-empty (received an empty array)')\n }\n if (arr.length > MAX_SECRETS) {\n throw new Error(\n `Session secret array exceeds maximum of ${MAX_SECRETS} entries — drop the oldest before adding a new one (received ${arr.length})`,\n )\n }\n const wasArray = Array.isArray(input)\n for (let i = 0; i < arr.length; i++) {\n const s = arr[i]\n if (typeof s !== 'string' || s.length < 32) {\n const where = wasArray ? ` at index ${i}` : ''\n throw new Error(`Session secret${where} must be at least 32 characters for secure encryption`)\n }\n }\n return arr\n}\n\nexport function createSessionManager<TSession>(config: SessionConfig): SessionManager<TSession> {\n const secrets = normalizeSecrets(config.secret)\n const cookieName = config.cookieName ?? 'theo_session'\n const maxAge = config.maxAge ?? 604800 // 7 days\n\n async function encryptEnvelope(data: TSession): Promise<string> {\n const envelope: SessionEnvelope<TSession> = {\n data,\n exp: Date.now() + maxAge * 1000,\n }\n return encrypt(envelope, secrets[0]) // newest\n }\n\n function writeCookie(res: ServerResponse, token: string): void {\n setCookie(res, cookieName, token, {\n httpOnly: true,\n sameSite: 'lax',\n maxAge,\n path: '/',\n })\n }\n\n async function decryptWithFallback(\n raw: string,\n ): Promise<{ envelope: SessionEnvelope<TSession>; index: number } | null> {\n // CR-002 constant-time: try EVERY rotation entry, then pick the newest\n // match. Sequential early-exit leaked rotation position via timing\n // (success on entry 0 returned in ~3 ms; success on entry 4 in ~15 ms).\n // Running in parallel binds wall-clock to the slowest single attempt,\n // independent of which entry actually matched. With derived-key cache\n // (CR-002 in crypto.ts), the CPU multiplier per request is ~0 after\n // the first request per secret.\n const results = await Promise.all(\n secrets.map(async (secret, i) => {\n const env = await decrypt<SessionEnvelope<TSession>>(raw, secret)\n return env ? { envelope: env, index: i } : null\n }),\n )\n for (const result of results) {\n if (result) return result\n }\n return null\n }\n\n return {\n async getSession(req) {\n const { data } = await this.getSessionWithMeta(req)\n return data\n },\n\n async getSessionWithMeta(req) {\n const raw = getCookie(req, cookieName)\n if (!raw) return { data: null, meta: { secretIndex: -1, needsReencrypt: false } }\n const decoded = await decryptWithFallback(raw)\n if (!decoded) return { data: null, meta: { secretIndex: -1, needsReencrypt: false } }\n if (decoded.envelope.exp < Date.now()) {\n return { data: null, meta: { secretIndex: decoded.index, needsReencrypt: false } }\n }\n return {\n data: decoded.envelope.data,\n meta: { secretIndex: decoded.index, needsReencrypt: decoded.index > 0 },\n }\n },\n\n async createSession(res, data) {\n const token = await encryptEnvelope(data)\n writeCookie(res, token)\n },\n\n destroySession(res) {\n deleteCookie(res, cookieName)\n },\n\n async rotateSession(req, res) {\n const { data } = await this.getSessionWithMeta(req)\n if (data === null) return null\n // Fresh IV per encrypt call (Web Crypto guarantee — see crypto.ts)\n // + refreshed expiry. Last write wins for the cookie value.\n const token = await encryptEnvelope(data)\n writeCookie(res, token)\n return data\n },\n }\n}\n\n/**\n * T3.2 — Transparent re-encrypt helper (EC-4 timing-safe wrapper).\n *\n * Call this in your `createContext` (before any rendering / streaming\n * starts). It:\n * 1. Reads the session via `getSessionWithMeta`.\n * 2. If the cookie was decrypted with a legacy secret (index > 0), it\n * immediately re-issues the cookie with `secrets[0]` so the next\n * request lands on the newest key.\n * 3. Returns the session data (or null) for use downstream.\n *\n * EC-4: this MUST run before `renderToPipeableStream` / `res.writeHead`\n * fires. Calling it inside an SSR component or handler body that has\n * already streamed bytes makes the re-encrypt a silent no-op (Set-Cookie\n * is locked once headers commit), trapping users on the legacy secret\n * forever once it's removed from the array.\n */\nexport async function rotateIfNeeded<TSession>(\n sm: SessionManager<TSession>,\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<TSession | null> {\n const { data, meta } = await sm.getSessionWithMeta(req)\n if (data !== null && meta.needsReencrypt) {\n await sm.createSession(res, data)\n }\n return data\n}\n\n/**\n * EC-2 — Production secret guard. Refuses to boot when `NODE_ENV === 'production'`\n * AND the secret is too short (< 32 chars) OR matches a known placeholder.\n *\n * Accepts a single secret OR an array. In array form, each entry is validated\n * independently — a single bad entry refuses boot with an index-qualified message.\n */\nconst PLACEHOLDER_PATTERN = /CHANGE_ME|demo[-_]|placeholder/i\n\nexport function assertProductionSecret(secret: string | string[]): void {\n const arr = Array.isArray(secret) ? secret : [secret]\n const isProd = process.env.NODE_ENV === 'production'\n\n for (let i = 0; i < arr.length; i++) {\n const s = arr[i]\n const isPlaceholder = PLACEHOLDER_PATTERN.test(s)\n const isTooShort = s.length < 32\n const prefix = arr.length > 1 ? `Session secret at index ${i}` : 'Session secret'\n\n if (isProd) {\n if (isTooShort) {\n throw new Error(\n `${prefix} too short for production (${s.length} chars; minimum 32). ` +\n `Set a 32+ random char secret in your env (e.g., \\`openssl rand -hex 32\\`).`,\n )\n }\n if (isPlaceholder) {\n throw new Error(\n `${prefix} looks like a placeholder (\"${s.slice(0, 16)}…\") and NODE_ENV is \"production\". ` +\n `Replace it with a 32+ random char secret (e.g., \\`openssl rand -hex 32\\`) before deploying.`,\n )\n }\n continue\n }\n if (isPlaceholder || isTooShort) {\n console.warn(\n `[theokit] WARNING: ${prefix.toLowerCase()} is a placeholder or too short. ` +\n `This is OK for dev, but the production server will REFUSE to boot until you replace it.`,\n )\n }\n }\n}\n","/**\n * Shared encoding utilities for crypto-adjacent code.\n *\n * CR-020 DRY: `base64urlEncode` was duplicated across `oauth-pkce.ts` and\n * `oauth-state.ts`. Duplication in cryptographic helpers is a bug class —\n * a future RFC-driven tweak (e.g., padding semantics) would diverge across\n * files. Centralizing the single canonical implementation eliminates that\n * vector.\n *\n * Module is intentionally under `_internal/` so it is **not** part of the\n * public API surface. Consumers outside `packages/theo/src/server` must\n * not import from here.\n */\n\n/**\n * RFC 4648 §5 — base64url-encode bytes without padding. Used wherever an\n * RFC requires URL-safe base64 (PKCE per RFC 7636 §4.1, JWT per RFC 7515,\n * etc.). Pure function — does not mutate `bytes`.\n */\nexport function base64urlEncode(bytes: Uint8Array): string {\n let s = ''\n for (const b of bytes) s += String.fromCharCode(b)\n // The `=+$` trailing-padding regex is bounded (at most 2 chars for\n // base64). sonarjs flags the `+` quantifier conservatively, but the\n // input is the output of `btoa()` — a string with at most 2 trailing\n // `=` characters by spec.\n // eslint-disable-next-line sonarjs/slow-regex -- bounded trailing-padding pattern (max 2 chars)\n return btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\n/**\n * Constant-time string equality.\n *\n * CR-012: prior implementations early-exited on length mismatch\n * (`if (a.length !== b.length) return false`). That early exit leaks\n * the comparison-target length via wall-clock timing — observable when\n * the secret length is itself sensitive (length-based bucket assignment,\n * variable-length nonces). This implementation always iterates\n * `max(a.length, b.length)` characters, OR-folding mismatches into a\n * single accumulator that is checked once at the end.\n *\n * Returns `false` for empty inputs as a defensive default — never accept\n * \"both empty\" as a match.\n */\nexport function constantTimeEquals(a: string, b: string): boolean {\n if (typeof a !== 'string' || typeof b !== 'string') return false\n if (a.length === 0 || b.length === 0) return false\n\n const maxLen = Math.max(a.length, b.length)\n let diff = a.length ^ b.length\n for (let i = 0; i < maxLen; i++) {\n // charCodeAt returns NaN for out-of-range indices; (NaN ^ x) is x, so we\n // explicitly substitute 0 to keep the OR-fold meaningful.\n const ca = i < a.length ? a.charCodeAt(i) : 0\n const cb = i < b.length ? b.charCodeAt(i) : 0\n diff |= ca ^ cb\n }\n return diff === 0\n}\n","/**\n * T6.2 — RFC 6238 TOTP primitive.\n *\n * Reference: https://datatracker.ietf.org/doc/html/rfc6238\n * HMAC-based one-time password (HOTP) base: https://datatracker.ietf.org/doc/html/rfc4226\n *\n * Pure-function, dependency-free implementation via Web Crypto. Secrets\n * may be passed as Uint8Array (preferred) or base32 string.\n *\n * SECURITY NOTES (documented per EC-13):\n * - TOTP secrets are equivalent to passwords. Encrypt at rest using a\n * separate KMS key from the session secret. If your DB leaks, ALL\n * 2FA codes are compromised — rotate by forcing all users to re-enroll.\n * - Use `verifyTotp` constant-time (we use crypto.timingSafeEqual internally).\n */\n\n// CR-012 fix: use the shared constant-time helper that does not early-exit\n// on length mismatch (the previous local version did, leaking the digit\n// count via timing).\nimport { constantTimeEquals } from '../_internal/encoding.js'\n\n/** Supported HMAC algorithms per RFC 6238 §1.2. Default SHA-1. */\nexport type TotpAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-512'\n\nexport interface TotpOptions {\n /** Shared secret — bytes (preferred) OR base32 string. */\n secret: Uint8Array | string\n /** Time step in seconds. Default 30 (RFC 6238 §5.2 recommended). */\n step?: number\n /** Code length: 6, 7, or 8 digits. Default 6. */\n digits?: 6 | 7 | 8\n /** HMAC algorithm. Default SHA-1 (RFC default). */\n algorithm?: TotpAlgorithm\n /** Time in ms since epoch. Default Date.now(). */\n time?: number\n}\n\nexport interface VerifyTotpOptions extends TotpOptions {\n /**\n * Drift tolerance in number of steps on each side. Default 1\n * (RFC 6238 §5.2 recommends ±1 step = 90s total window).\n */\n window?: number\n}\n\nconst DEFAULT_STEP = 30\nconst DEFAULT_DIGITS = 6\nconst DEFAULT_ALGORITHM: TotpAlgorithm = 'SHA-1'\n\n/** Decode base32 (RFC 4648, no padding) to bytes. Throws on invalid input. */\nfunction base32Decode(s: string): Uint8Array {\n const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'\n // Trailing `=` is bounded by spec to 0..6 chars; `\\s+` collapses runs\n // of whitespace. Input length is the user's TOTP secret (10..50 chars\n // typical), so super-linear backtracking cannot escalate.\n // eslint-disable-next-line sonarjs/slow-regex -- bounded inputs (TOTP secrets are short)\n const clean = s.toUpperCase().replace(/=+$/, '').replace(/\\s+/g, '')\n if (!/^[A-Z2-7]+$/.test(clean)) {\n throw new Error('Invalid base32 secret')\n }\n const bits: number[] = []\n for (const c of clean) {\n const idx = alphabet.indexOf(c)\n for (let i = 4; i >= 0; i--) bits.push((idx >> i) & 1)\n }\n // Trim trailing partial byte\n const fullBytes = Math.floor(bits.length / 8)\n const out = new Uint8Array(fullBytes)\n for (let i = 0; i < fullBytes; i++) {\n let v = 0\n for (let j = 0; j < 8; j++) v = (v << 1) | bits[i * 8 + j]\n out[i] = v\n }\n return out\n}\n\n/** Encode bytes to base32 (RFC 4648, no padding). */\nfunction base32Encode(bytes: Uint8Array): string {\n const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'\n let out = ''\n let buffer = 0\n let bits = 0\n for (const b of bytes) {\n buffer = (buffer << 8) | b\n bits += 8\n while (bits >= 5) {\n out += alphabet[(buffer >> (bits - 5)) & 0x1f]\n bits -= 5\n }\n }\n if (bits > 0) out += alphabet[(buffer << (5 - bits)) & 0x1f]\n return out\n}\n\nfunction normalizeSecret(secret: Uint8Array | string): Uint8Array {\n if (typeof secret === 'string') return base32Decode(secret)\n return secret\n}\n\n/** Counter (8-byte big-endian) from time in ms / step in seconds. */\nfunction counterBytes(timeMs: number, stepSec: number): Uint8Array {\n const counter = Math.floor(timeMs / 1000 / stepSec)\n const out = new Uint8Array(8)\n // Two 32-bit halves (Number can safely represent up to 2^53; OK until year 285,000+)\n const hi = Math.floor(counter / 0x100000000)\n const lo = counter >>> 0\n out[0] = (hi >>> 24) & 0xff\n out[1] = (hi >>> 16) & 0xff\n out[2] = (hi >>> 8) & 0xff\n out[3] = hi & 0xff\n out[4] = (lo >>> 24) & 0xff\n out[5] = (lo >>> 16) & 0xff\n out[6] = (lo >>> 8) & 0xff\n out[7] = lo & 0xff\n return out\n}\n\nasync function hmac(\n secret: Uint8Array,\n message: Uint8Array,\n algorithm: TotpAlgorithm,\n): Promise<Uint8Array> {\n const key = await crypto.subtle.importKey(\n 'raw',\n secret as BufferSource,\n { name: 'HMAC', hash: algorithm },\n false,\n ['sign'],\n )\n const sig = await crypto.subtle.sign('HMAC', key, message as BufferSource)\n return new Uint8Array(sig)\n}\n\n/** RFC 4226 §5.3 dynamic truncation. */\nfunction truncate(mac: Uint8Array, digits: number): string {\n const offset = mac[mac.length - 1] & 0x0f\n const code =\n ((mac[offset] & 0x7f) << 24) |\n ((mac[offset + 1] & 0xff) << 16) |\n ((mac[offset + 2] & 0xff) << 8) |\n (mac[offset + 3] & 0xff)\n const mod = 10 ** digits\n return String(code % mod).padStart(digits, '0')\n}\n\n/** Generate a TOTP code for a given time. */\nexport async function generateTotp(opts: TotpOptions): Promise<string> {\n const secret = normalizeSecret(opts.secret)\n const step = opts.step ?? DEFAULT_STEP\n const digits = opts.digits ?? DEFAULT_DIGITS\n const algorithm = opts.algorithm ?? DEFAULT_ALGORITHM\n const time = opts.time ?? Date.now()\n const mac = await hmac(secret, counterBytes(time, step), algorithm)\n return truncate(mac, digits)\n}\n\n/**\n * Verify a TOTP code against the current window ± `window` steps.\n *\n * Returns `false` for malformed tokens (non-digit, wrong length) without\n * throwing — defensive against accidental user-input passthrough.\n */\nexport async function verifyTotp(token: string, opts: VerifyTotpOptions): Promise<boolean> {\n if (typeof token !== 'string') return false\n const digits = opts.digits ?? DEFAULT_DIGITS\n if (!/^\\d+$/.test(token) || token.length !== digits) return false\n\n const step = opts.step ?? DEFAULT_STEP\n const algorithm = opts.algorithm ?? DEFAULT_ALGORITHM\n const time = opts.time ?? Date.now()\n const drift = opts.window ?? 1\n const secret = normalizeSecret(opts.secret)\n\n // Walk the whole drift range constant-time-ish (no early exit).\n let matched = false\n for (let delta = -drift; delta <= drift; delta++) {\n const t = time + delta * step * 1000\n const code = truncate(await hmac(secret, counterBytes(t, step), algorithm), digits)\n if (constantTimeEquals(code, token)) matched = true\n }\n return matched\n}\n\n/** Generate a cryptographically random TOTP secret. Default 20 bytes (RFC minimum). */\nexport function generateTotpSecret(bytes = 20): Uint8Array {\n if (bytes < 16) {\n throw new Error('TOTP secret must be at least 16 bytes (RFC 6238 §3 minimum)')\n }\n const out = new Uint8Array(bytes)\n crypto.getRandomValues(out)\n return out\n}\n\n/**\n * Build an `otpauth://` URI for QR code enrollment. Format follows the\n * de facto Google Authenticator spec adopted by every major TOTP app.\n * otpauth://totp/<issuer>:<account>?secret=<base32>&issuer=<issuer>&algorithm=<alg>&digits=<n>&period=<sec>\n */\nexport interface TotpUriOptions {\n secret: Uint8Array\n issuer: string\n account: string\n algorithm?: TotpAlgorithm\n digits?: 6 | 7 | 8\n step?: number\n}\n\nexport function totpUri(opts: TotpUriOptions): string {\n const label = `${opts.issuer}:${opts.account}`\n const params = new URLSearchParams({\n secret: base32Encode(opts.secret),\n issuer: opts.issuer,\n algorithm: opts.algorithm ?? DEFAULT_ALGORITHM,\n digits: String(opts.digits ?? DEFAULT_DIGITS),\n period: String(opts.step ?? DEFAULT_STEP),\n })\n return `otpauth://totp/${encodeURIComponent(label)}?${params.toString()}`\n}\n","/**\n * T6.3 — Backup codes for 2FA recovery.\n *\n * generateBackupCodes returns N plaintexts (display once to user) + hashes\n * (store in DB). verifyBackupCode constant-time-walks all hashes and\n * returns the matchedHash so caller can delete the used code from storage\n * — replay protection lives at the caller (we can't see their database).\n *\n * SECURITY NOTES:\n * - Codes have ~40 bits entropy (8 chars × 5 bits per char from a\n * 32-char alphabet excluding I/L/O/0/1). Single-use → argon2id\n * overhead is unnecessary; SHA-256 of the normalized code suffices.\n * - The caller MUST atomically delete the matched hash on successful\n * verify. Without that, the code is replayable. We surface\n * matchedHash explicitly so this step is conspicuous.\n * - Pair this with throttleLoginAttempts (T6.1) on the verify endpoint\n * to prevent online brute-force against the 40-bit space.\n */\n\nexport interface BackupCodeOptions {\n /** How many codes to generate. Default 10. */\n count?: number\n /** Length in chars (excluding separator). Default 8. */\n length?: number\n /** Separator inserted at the midpoint. Default '-'; pass null to omit. */\n separator?: '-' | null\n /** Custom alphabet. Default excludes ambiguous chars (I, L, O, 0, 1). */\n alphabet?: string\n}\n\nexport interface BackupCode {\n plaintext: string\n hash: string\n}\n\nconst DEFAULT_ALPHABET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789' // no I, O, 0, 1\nconst DEFAULT_COUNT = 10\nconst DEFAULT_LENGTH = 8\n\n/**\n * Generate cryptographically random backup codes + their SHA-256 hashes.\n *\n * Plaintext is uppercase alphanumeric (default alphabet excludes ambiguous\n * chars). Separator inserted at the midpoint (default `-`).\n */\nexport async function generateBackupCodes(opts: BackupCodeOptions = {}): Promise<BackupCode[]> {\n const count = opts.count ?? DEFAULT_COUNT\n const length = opts.length ?? DEFAULT_LENGTH\n const separator = opts.separator === undefined ? '-' : opts.separator\n const alphabet = opts.alphabet ?? DEFAULT_ALPHABET\n\n // CR-022 fix: bound count and length explicitly. Pathological inputs\n // (count=Infinity, length=0) would cause an infinite loop or wasteful\n // resource usage. Bounds are generous (count ≤ 1000, length ∈ [4, 64])\n // — well above any realistic 2FA backup-codes use case.\n if (!Number.isInteger(count) || count <= 0 || count > 1000) {\n throw new RangeError(\n `generateBackupCodes: count must be an integer in [1, 1000] (got ${String(count)})`,\n )\n }\n if (!Number.isInteger(length) || length < 4 || length > 64) {\n throw new RangeError(\n `generateBackupCodes: length must be an integer in [4, 64] (got ${String(length)})`,\n )\n }\n if (alphabet.length < 8) {\n throw new RangeError(\n `generateBackupCodes: alphabet must contain at least 8 distinct chars (got ${alphabet.length})`,\n )\n }\n\n const codes: BackupCode[] = []\n const seen = new Set<string>()\n while (codes.length < count) {\n const raw = randomFromAlphabet(length, alphabet)\n if (seen.has(raw)) continue\n seen.add(raw)\n const plaintext = formatWithSeparator(raw, separator)\n const hash = await sha256Hex(normalizeCode(plaintext))\n codes.push({ plaintext, hash })\n }\n return codes\n}\n\n/**\n * Verify a code against a list of stored hashes. Walks all hashes\n * constant-time (no early exit). Returns `valid:true` + matchedHash on\n * hit; `valid:false` otherwise.\n *\n * `matchedHash` is the EXACT string the caller stored, ready to be passed\n * to a `DELETE FROM backup_codes WHERE hash = ?` query.\n */\nexport async function verifyBackupCode(\n code: string,\n hashes: readonly string[],\n): Promise<{ valid: boolean; matchedHash?: string }> {\n const candidate = await sha256Hex(normalizeCode(code))\n let matchedHash: string | undefined\n // Constant-time iteration over hashes: never short-circuit.\n for (const h of hashes) {\n if (constantTimeEquals(h, candidate)) {\n matchedHash = h\n }\n }\n return matchedHash ? { valid: true, matchedHash } : { valid: false }\n}\n\n/**\n * Normalize a code for hashing: uppercase + strip separator. This way\n * `abcd-efgh` and `ABCDEFGH` produce the same hash. Whitespace is also\n * stripped defensively.\n */\nfunction normalizeCode(input: string): string {\n return input.toUpperCase().replace(/[-\\s]+/g, '')\n}\n\nfunction formatWithSeparator(raw: string, separator: '-' | null): string {\n if (!separator || raw.length < 4) return raw\n const mid = Math.floor(raw.length / 2)\n return raw.slice(0, mid) + separator + raw.slice(mid)\n}\n\nfunction randomFromAlphabet(length: number, alphabet: string): string {\n const random = new Uint8Array(length)\n crypto.getRandomValues(random)\n let out = ''\n for (let i = 0; i < length; i++) {\n out += alphabet[random[i] % alphabet.length]\n }\n return out\n}\n\nasync function sha256Hex(input: string): Promise<string> {\n const bytes = new TextEncoder().encode(input)\n const hash = await crypto.subtle.digest('SHA-256', bytes)\n return Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\nfunction constantTimeEquals(a: string, b: string): boolean {\n if (a.length !== b.length) return false\n let diff = 0\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i)\n return diff === 0\n}\n","import type { RateLimitStore } from '../rate-limit/rate-limit-store.js'\n\n/**\n * T6.1 — Login throttling primitive.\n *\n * Per-credential failure counter backed by any `RateLimitStore`. After\n * `maxAttempts` failures within `windowMs`, the identifier is locked\n * for `lockoutMs`. Successful login resets the counter.\n *\n * Usage in a login handler:\n *\n * const state = await checkThrottle({ store, identifier: hash(email) })\n * if (!state.allowed) return 429\n * const valid = await verifyPassword(creds)\n * await recordAttempt({ store, identifier: hash(email) }, valid)\n * if (!valid) return 401\n *\n * SECURITY:\n * - NEVER pass raw email/username as `identifier`. Hash or normalize\n * first (e.g. SHA-256 of the lowercased email). This prevents PII\n * from landing in the rate-limit store or audit logs.\n * - Combine with the per-route IP rate limit (T2.2) for layered defense:\n * IP-level limits stop scripted floods; credential-level limits stop\n * distributed brute force.\n */\n\nexport interface ThrottleOptions {\n store: RateLimitStore\n /**\n * Stable identifier per credential. Hash raw emails/usernames before\n * passing in — never leak PII to the rate-limit key space.\n */\n identifier: string\n /** Failures before lockout. Default 5. */\n maxAttempts?: number\n /** Sliding window for counting failures. Default 15 minutes. */\n windowMs?: number\n /** Lockout duration after maxAttempts hit. Default 1 hour. */\n lockoutMs?: number\n}\n\nexport interface ThrottleState {\n allowed: boolean\n remainingAttempts: number\n /** Set when `allowed === false`. Absolute timestamp when the lockout expires. */\n lockedUntil?: Date\n}\n\nconst DEFAULT_MAX_ATTEMPTS = 5\nconst DEFAULT_LOCKOUT_MS = 60 * 60_000\n\n/**\n * Read the current throttle state for an identifier WITHOUT modifying\n * the counter. Call before validating credentials so locked attempts\n * are rejected fast.\n */\nexport async function checkThrottle(opts: ThrottleOptions): Promise<ThrottleState> {\n const maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS\n const state = await opts.store.get(opts.identifier)\n if (!state) {\n return { allowed: true, remainingAttempts: maxAttempts }\n }\n if (state.count >= maxAttempts) {\n return {\n allowed: false,\n remainingAttempts: 0,\n // Lockout expires when the store TTL fires.\n lockedUntil: new Date(state.resetAt),\n }\n }\n return {\n allowed: true,\n remainingAttempts: Math.max(0, maxAttempts - state.count),\n }\n}\n\n/**\n * Record an attempt outcome. On success → reset the counter. On failure\n * → increment within the sliding window. Returns the new throttle state.\n *\n * Storage model: the store entry's TTL is `lockoutMs` (which doubles as\n * the failure-accumulation window). When `lockoutMs` is short — common\n * in tests or for soft lockouts — the entry auto-expires and the next\n * attempt starts fresh.\n */\nexport async function recordAttempt(\n opts: ThrottleOptions,\n success: boolean,\n): Promise<ThrottleState> {\n const maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS\n if (success) {\n await opts.store.reset(opts.identifier)\n return {\n allowed: true,\n remainingAttempts: maxAttempts,\n }\n }\n const lockoutMs = opts.lockoutMs ?? DEFAULT_LOCKOUT_MS\n const state = await opts.store.incr(opts.identifier, lockoutMs)\n\n if (state.count >= maxAttempts) {\n return {\n allowed: false,\n remainingAttempts: 0,\n lockedUntil: new Date(state.resetAt),\n }\n }\n return {\n allowed: true,\n remainingAttempts: Math.max(0, maxAttempts - state.count),\n }\n}\n","/**\n * T7.3 — RFC 7636 PKCE primitive.\n *\n * Reference: https://datatracker.ietf.org/doc/html/rfc7636\n *\n * Pure-function, dependency-free implementation using Web Crypto.\n *\n * Usage in an OAuth authorization-code flow:\n *\n * const { codeVerifier, codeChallenge, codeChallengeMethod } = await generatePkceChallenge()\n * // Store codeVerifier in the user's session\n * // Send codeChallenge + codeChallengeMethod in the /authorize redirect\n * // ... user authenticates with provider ...\n * // On /callback, send codeVerifier with the code → token exchange\n */\n\nexport interface PkceChallenge {\n codeVerifier: string\n codeChallenge: string\n codeChallengeMethod: 'S256'\n}\n\n// CR-020 DRY: single canonical base64url encoder lives in _internal/encoding.\nimport { base64urlEncode } from '../_internal/encoding.js'\n\n/**\n * Compute the code_challenge from a code_verifier per RFC 7636 §4.2.\n * Exported separately to enable RFC 7636 Appendix B vector testing.\n */\nexport async function pkceChallengeFromVerifier(verifier: string): Promise<string> {\n const bytes = new TextEncoder().encode(verifier)\n const hash = await crypto.subtle.digest('SHA-256', bytes)\n return base64urlEncode(new Uint8Array(hash))\n}\n\n/**\n * Generate a fresh PKCE challenge pair.\n *\n * Verifier: 32 cryptographically random bytes → 43-char base64url string.\n * RFC 7636 §4.1 allows 43–128 chars; we ship the minimum-safe default.\n *\n * Method: 'S256' only — no 'plain' fallback. RFC 7636 §7.2 strongly\n * discourages plain and modern providers reject it.\n */\nexport async function generatePkceChallenge(): Promise<PkceChallenge> {\n const random = new Uint8Array(32)\n crypto.getRandomValues(random)\n const codeVerifier = base64urlEncode(random)\n const codeChallenge = await pkceChallengeFromVerifier(codeVerifier)\n return { codeVerifier, codeChallenge, codeChallengeMethod: 'S256' }\n}\n","/**\n * T7.4 — OAuth `state` parameter helpers (RFC 6749 §10.12).\n *\n * `state` is a cryptographically random anti-CSRF token. The client\n * stores it (in session/cookie/db) before redirecting to the\n * authorization endpoint and verifies it on the callback. Without it,\n * an attacker can authorize on the user's account using a captured code.\n */\n\n// CR-020 DRY + CR-012 constant-time: shared helpers in _internal/encoding.\nimport { base64urlEncode, constantTimeEquals } from '../_internal/encoding.js'\n\n/**\n * Generate a cryptographically random state token. Default 32 bytes\n * (~43 base64url chars). Increase for higher entropy if your provider\n * supports it.\n */\nexport function generateOAuthState(opts: { bytes?: number } = {}): string {\n const len = opts.bytes ?? 32\n const buf = new Uint8Array(len)\n crypto.getRandomValues(buf)\n return base64urlEncode(buf)\n}\n\n/**\n * Verify a state token. Constant-time compare. Empty inputs always fail\n * (defensive — never accept empty as \"they match\").\n *\n * CR-012 fix: `constantTimeEquals` does not early-exit on length mismatch,\n * so the comparison time is independent of how the input was forged.\n */\nexport function verifyOAuthState(provided: string, stored: string): boolean {\n return constantTimeEquals(provided, stored)\n}\n","/**\n * T7.4 — OpenID Connect Discovery 1.0 metadata fetcher.\n *\n * Reference: https://openid.net/specs/openid-connect-discovery-1_0.html\n *\n * Caches metadata in module scope. Cache key is the exact issuer string\n * (trailing-slash sensitive per RFC 8414 §3). Failures are NOT cached —\n * subsequent calls retry the fetch.\n *\n * EC-7 — HTTPS enforced. RFC 8414 §3 requires HTTPS for OIDC issuers.\n * Localhost (loopback) is allowed for development.\n */\n\nexport interface OidcMetadata {\n issuer: string\n authorization_endpoint: string\n token_endpoint: string\n jwks_uri?: string\n userinfo_endpoint?: string\n end_session_endpoint?: string\n scopes_supported?: string[]\n response_types_supported?: string[]\n grant_types_supported?: string[]\n id_token_signing_alg_values_supported?: string[]\n [key: string]: unknown // OIDC providers ship many optional fields\n}\n\nconst cache = new Map<string, Promise<OidcMetadata>>()\n\n/** Clear the discovery cache. Used by tests. */\nexport function clearOidcCache(): void {\n cache.clear()\n}\n\nfunction isLoopback(host: string): boolean {\n return host === 'localhost' || host === '127.0.0.1' || host === '[::1]' || host === '::1'\n}\n\n/**\n * Fetch (or return cached) OIDC provider metadata.\n *\n * Throws when:\n * - Issuer URL is malformed\n * - Issuer is HTTP and not a loopback host (EC-7)\n * - HTTP response is non-OK\n * - Metadata lacks `authorization_endpoint` (sanity check)\n */\nexport async function discoverOidcProvider(issuer: string | URL): Promise<OidcMetadata> {\n const issuerStr = typeof issuer === 'string' ? issuer : issuer.toString()\n // Validate protocol BEFORE checking cache — invalid issuers should never poison.\n const url = new URL(issuerStr)\n if (url.protocol !== 'https:' && !isLoopback(url.hostname)) {\n throw new Error(\n `OIDC issuer must use HTTPS (received \"${url.protocol}//${url.hostname}…\"). ` +\n `RFC 8414 §3 forbids plain HTTP except for loopback hosts.`,\n )\n }\n\n const cached = cache.get(issuerStr)\n if (cached) return cached\n\n const promise = (async () => {\n const wellKnown = new URL(\n '.well-known/openid-configuration',\n issuerStr.endsWith('/') ? issuerStr : issuerStr + '/',\n )\n const res = await fetch(wellKnown)\n if (!res.ok) {\n throw new Error(`OIDC discovery failed: ${res.status} ${res.statusText} at ${wellKnown}`)\n }\n const metadata = (await res.json()) as OidcMetadata\n if (!metadata.authorization_endpoint) {\n throw new Error('OIDC metadata missing authorization_endpoint — provider response is invalid')\n }\n return metadata\n })()\n // Cache the promise; on rejection, remove so the next call retries.\n cache.set(issuerStr, promise)\n promise.catch(() => {\n if (cache.get(issuerStr) === promise) cache.delete(issuerStr)\n })\n return promise\n}\n"],"mappings":"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","names":["constantTimeEquals"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/services/adapters-bridge/adapter-support.ts","../src/services/generators/caddy-generator.ts","../src/services/generators/compose-generator.ts","../src/services/generators/openapi-client-gen.ts","../src/services/adapters-bridge/manifest.ts","../src/services/schema/schema.ts","../src/services/runtime/orchestrator.ts","../src/services/runtime/healthcheck-poller.ts","../src/services/runtime/log-merge.ts","../src/services/runtime/process-spawn-helpers.ts","../src/services/adapters-bridge/vite-proxy-builder.ts","../src/services/adapters-bridge/theo-cloud-adapter-stub.ts"],"sourcesContent":["/**\n * Adapter support gates (Wave 2 — TheoCloud-first focus).\n *\n * Wave 2 SUPPORTS polyglot `services: {}` on TWO targets ONLY:\n * - `node` (local docker-compose harness — TheoCloud-shaped)\n * - `theo-cloud` (the principal deploy target — Wave 3 adapter)\n *\n * All other in-tree deploy adapters (vercel, cloudflare, bun, deno-deploy,\n * aws-lambda, netlify, static) ARE STILL FIRST-CLASS DEPLOY TARGETS for\n * the TS app, but `services: {}` Wave 2 is NOT yet wired through them.\n * They reject loudly with an actionable message when the manifest has\n * non-empty services — pointing the user at `node` (local) or TheoCloud.\n *\n * Per owner decision 2026-05-27: TheoKit's polyglot services energy is\n * 100% TheoCloud; Vercel/Cloudflare/etc. polyglot-services wire-ups are\n * out of Wave 2 scope and deferred to fresh ADRs if demand emerges.\n */\nimport type { ServicesManifest } from './manifest.js'\n\nconst SUPPORTED_IN_WAVE_2 = ['node (local)', 'theo-cloud (Wave 3)'] as const\n\n/**\n * Reject if the adapter does not support polyglot services. Adapters\n * outside `node` + `theo-cloud` call this; the message points to the\n * supported alternatives.\n *\n * Throws when manifest has non-empty services. No-op when manifest is null\n * or empty (Wave 1 BC — the app still deploys, just without sidecars).\n */\nexport function assertServicesUnsupported(\n adapterName: string,\n manifest: ServicesManifest | null,\n): void {\n if (!manifest || manifest.services.length === 0) return\n const names = manifest.services.map((s) => s.name).join(', ')\n throw new Error(\n `Adapter '${adapterName}' does not support polyglot services in Wave 2.\\n` +\n `Detected services in theo.config.ts: ${names}.\\n\\n` +\n `Wave 2 supports: ${SUPPORTED_IN_WAVE_2.join(', ')}.\\n` +\n `TheoCloud is the strategic deploy target — the adapter ships in Wave 3.\\n` +\n `For local dev/prod-like validation today, use \\`theokit build --target node\\`\\n` +\n `(emits docker-compose + Caddyfile — TheoCloud-shaped harness).\\n\\n` +\n `See docs/concepts/services.md.`,\n )\n}\n","/**\n * Caddyfile generator (T3.3).\n *\n * Emits a Caddyfile that fronts the TheoKit web app + declared services\n * with W3C trace context propagation enabled (Caddy 2.11+ `tracing` directive).\n *\n * Generated output sits at `<dist>/.theo/node/Caddyfile`, consumed by the\n * docker-compose stack (T3.3 compose-generator).\n *\n * EC-23: `reverse_proxy` directives are ordered by prefix length DESC.\n * Caddy matches longest-prefix-first when written in order.\n */\nimport type { ServicesManifest } from '../adapters-bridge/manifest.js'\n\nexport interface CaddyfileOptions {\n /** Port Caddy listens on (TheoKit web port; default 3000). */\n port: number\n /** TheoKit web container hostname (compose service name). Default 'web'. */\n webHost: string\n}\n\nfunction reverseProxyLines(servicePath: string, target: string, cors: boolean): string[] {\n const out = [`\\treverse_proxy ${servicePath}* ${target}`]\n if (cors) {\n out.push(\n `\\theader ${servicePath}* Access-Control-Allow-Origin \"*\"`,\n `\\theader ${servicePath}* Access-Control-Allow-Methods \"GET, POST, PUT, DELETE, OPTIONS\"`,\n `\\theader ${servicePath}* Access-Control-Allow-Headers \"Content-Type, Authorization, traceparent, tracestate, baggage\"`,\n )\n }\n return out\n}\n\nexport function generateCaddyfile(\n manifest: ServicesManifest | null,\n options: CaddyfileOptions,\n): string {\n // EC-23: sort services by proxy prefix length DESC so longest matches first\n const services = (manifest?.services ?? [])\n .slice()\n .sort((a, b) => b.proxy.length - a.proxy.length)\n\n const serviceLines = services.flatMap((svc) =>\n reverseProxyLines(svc.proxy, `${svc.name}:${String(svc.port)}`, svc.cors),\n )\n\n const lines: string[] = [\n `:${String(options.port)} {`,\n `\\t# W3C Trace Context propagation (Caddy 2.11+)`,\n `\\ttracing`,\n `\\theader -Server`,\n ...serviceLines,\n `\\treverse_proxy ${options.webHost}:${String(options.port)}`,\n `}`,\n '',\n ]\n return lines.join('\\n')\n}\n","/**\n * docker-compose.yml generator (T3.3).\n *\n * Emits the \"TheoCloud-shaped\" local harness — Caddy ingress in front of\n * web + declared services. Each service has a healthcheck and Caddy\n * `depends_on: service_healthy`.\n *\n * Used by the Node adapter: `theokit build --target node` writes the\n * compose stack to `.theo/node/docker-compose.yml`.\n */\nimport type { ManifestServiceEntry, ServicesManifest } from '../adapters-bridge/manifest.js'\n\nexport interface ComposeOptions {\n /** Port for the web container (TheoKit). Default 3000. */\n webPort: number\n /** Caddy listening port (default same as webPort — Caddy fronts everything). */\n caddyPort?: number\n /** Project name (compose file `name:` field). */\n projectName?: string\n}\n\nfunction indent(level: number): string {\n return ' '.repeat(level)\n}\n\nfunction healthcheckLines(svc: ManifestServiceEntry): string[] {\n const checker =\n svc.runtime === 'python'\n ? `curl -f http://localhost:${String(svc.port)}${svc.healthcheck} || exit 1`\n : `wget --spider -q http://localhost:${String(svc.port)}${svc.healthcheck} || exit 1`\n return [\n `${indent(2)}healthcheck:`,\n `${indent(3)}test: [\"CMD-SHELL\", \"${checker}\"]`,\n `${indent(3)}interval: 10s`,\n `${indent(3)}timeout: 5s`,\n `${indent(3)}retries: 3`,\n ]\n}\n\nfunction envLines(env: Record<string, string>): string[] {\n const lines: string[] = [`${indent(2)}environment:`]\n for (const [k, v] of Object.entries(env)) {\n lines.push(`${indent(3)}${k}: ${JSON.stringify(v)}`)\n }\n return lines\n}\n\nfunction serviceBlockLines(svc: ManifestServiceEntry): string[] {\n // EC-8: auto-inject convention env vars in the container too\n const env: Record<string, string> = {\n THEOKIT_SERVICE_NAME: svc.name,\n THEOKIT_SERVICE_PORT: String(svc.port),\n ...(svc.env ?? {}),\n }\n return [\n `${indent(1)}${svc.name}:`,\n `${indent(2)}build:`,\n `${indent(3)}context: ./services/${svc.name}`,\n `${indent(2)}expose:`,\n `${indent(3)}- \"${String(svc.port)}\"`,\n ...envLines(env),\n ...healthcheckLines(svc),\n ]\n}\n\nfunction caddyBlockLines(caddyPort: number, services: ManifestServiceEntry[]): string[] {\n const depends: string[] = [\n `${indent(2)}depends_on:`,\n `${indent(3)}web:`,\n `${indent(4)}condition: service_healthy`,\n ]\n for (const svc of services) {\n depends.push(`${indent(3)}${svc.name}:`, `${indent(4)}condition: service_healthy`)\n }\n return [\n `${indent(1)}caddy:`,\n `${indent(2)}image: caddy:2.11`,\n `${indent(2)}ports:`,\n `${indent(3)}- \"${String(caddyPort)}:${String(caddyPort)}\"`,\n `${indent(2)}volumes:`,\n `${indent(3)}- ./Caddyfile:/etc/caddy/Caddyfile:ro`,\n ...depends,\n ]\n}\n\nfunction webBlockLines(webPort: number): string[] {\n return [\n `${indent(1)}web:`,\n `${indent(2)}build:`,\n `${indent(3)}context: .`,\n `${indent(3)}dockerfile: Dockerfile`,\n `${indent(2)}expose:`,\n `${indent(3)}- \"${String(webPort)}\"`,\n `${indent(2)}healthcheck:`,\n `${indent(3)}test: [\"CMD-SHELL\", \"wget --spider -q http://localhost:${String(webPort)}/api/health || exit 1\"]`,\n `${indent(3)}interval: 10s`,\n `${indent(3)}timeout: 5s`,\n `${indent(3)}retries: 3`,\n ]\n}\n\nexport function generateComposeYaml(\n manifest: ServicesManifest | null,\n options: ComposeOptions,\n): string {\n const services = manifest?.services ?? []\n const webPort = options.webPort\n const caddyPort = options.caddyPort ?? webPort\n\n const projectLines = options.projectName ? [`name: ${options.projectName}`] : []\n\n const lines: string[] = [\n ...projectLines,\n `services:`,\n ...caddyBlockLines(caddyPort, services),\n ...webBlockLines(webPort),\n ...services.flatMap(serviceBlockLines),\n '',\n ]\n return lines.join('\\n')\n}\n","/**\n * OpenAPI → TypeScript client generation (T5.1).\n *\n * Thin wrapper around `@hey-api/openapi-ts` (the de facto 2026 generator\n * used by Vercel/OpenCode/PayPal). Called by the Vite plugin\n * `services-typed-client.ts` at dev startup and when an OpenAPI URL\n * changes.\n *\n * Production behavior:\n * - For each service with a `openapi` URL, fetch the spec\n * - Run Hey API generator to write `<cwd>/clients/<service-name>.ts`\n * - On any failure: log warning, do NOT crash dev (best-effort)\n *\n * The actual `@hey-api/openapi-ts` invocation is dynamic-imported so\n * that consumers without the dep (TS-only Wave 1 apps) don't pay\n * the bundle cost.\n */\nimport type { ManifestServiceEntry } from '../adapters-bridge/manifest.js'\n\nexport interface GenerateClientOptions {\n service: ManifestServiceEntry\n /** Directory to write `<service-name>.ts` into. */\n outputDir: string\n /** Logger for warnings/info. */\n log?: (level: 'info' | 'warn' | 'error', msg: string) => void\n /** Test injection — replace fetch (so tests don't hit the network). */\n customFetch?: typeof fetch\n}\n\nexport interface GenerateClientResult {\n generated: boolean\n outputFile?: string\n skippedReason?: string\n}\n\n/**\n * Generate a typed client for one service. No-op (returns skipped=true)\n * if the service has no `openapi` URL.\n *\n * The generator runs the Hey API tool. If the tool import fails (not\n * installed), the function logs a warning and returns `{ generated: false }`.\n */\nexport async function generateTypedClient(\n options: GenerateClientOptions,\n): Promise<GenerateClientResult> {\n const log =\n options.log ??\n ((_level: 'info' | 'warn' | 'error', _msg: string) => {\n // default: silent in production; tests inject their own\n })\n const { service, outputDir } = options\n\n if (!service.openapi) {\n return { generated: false, skippedReason: 'no openapi URL declared' }\n }\n\n const f = options.customFetch ?? fetch\n let spec: unknown\n try {\n const res = await f(service.openapi)\n if (!res.ok) {\n log('warn', `[${service.name}] openapi fetch returned ${String(res.status)}; skipping`)\n return { generated: false, skippedReason: `fetch returned ${String(res.status)}` }\n }\n spec = await res.json()\n } catch (err) {\n log(\n 'warn',\n `[${service.name}] openapi fetch failed: ${err instanceof Error ? err.message : String(err)}`,\n )\n return { generated: false, skippedReason: 'fetch failed' }\n }\n\n // Dynamic import — soft dep. We pass through a variable so the typechecker\n // doesn't resolve the literal at build time (the dep is optional;\n // consumers without it get a graceful skip).\n let createClient: unknown\n try {\n // Soft-dep resolution. We pass the module name through a String wrapper\n // call site that the typechecker cannot statically resolve — so missing\n // dep at typecheck time does not break the build. Runtime behavior is\n // identical to `import('@hey-api/openapi-ts')`.\n const segment1 = '@hey-api/'\n const segment2 = 'openapi-ts'\n const moduleName = `${segment1}${segment2}`\n const dyn: Promise<unknown> = import(moduleName).catch(() => null)\n const mod = (await dyn) as { createClient?: unknown } | null\n createClient = mod?.createClient\n } catch {\n createClient = undefined\n }\n\n if (typeof createClient !== 'function') {\n log(\n 'warn',\n `[${service.name}] @hey-api/openapi-ts not installed; typed client not generated. ` +\n `Run \\`pnpm add -D @hey-api/openapi-ts @hey-api/client-fetch\\` to enable.`,\n )\n return { generated: false, skippedReason: 'hey-api not installed' }\n }\n\n const outputFile = `${outputDir}/${service.name}.ts`\n try {\n await (createClient as (cfg: unknown) => Promise<unknown>)({\n input: spec,\n output: { path: outputDir, format: 'prettier' },\n plugins: [{ name: '@hey-api/client-fetch' }],\n })\n log('info', `[${service.name}] typed client generated at ${outputFile}`)\n return { generated: true, outputFile }\n } catch (err) {\n log(\n 'warn',\n `[${service.name}] Hey API generation failed: ${err instanceof Error ? err.message : String(err)}`,\n )\n return { generated: false, skippedReason: 'generator threw' }\n }\n}\n","/**\n * Neutral cross-product manifest (T1.4).\n *\n * Emitted by `theokit build` at `<cwd>/.theo/services.json` (schemaVersion 1).\n * Consumed by EVERY deploy adapter (Vercel, Node, Cloudflare, future TheoCloud).\n *\n * Shape is INTENTIONALLY platform-neutral (ADR-0015 invariant + D5). No\n * `vercel`/`cloudflare`/`theoCloud` keys — platform-specific tuning lives in\n * `theo.config.ts` and is read by each adapter's own code, NOT serialized\n * into this manifest.\n *\n * Topological ordering enforced (dependsOn-resolved deps first) so adapters\n * that need boot order (docker-compose, K8s) can consume the array verbatim.\n */\n/* eslint-disable security/detect-non-literal-fs-filename --\n * Manifest read/write paths are derived from the trusted `cwd` plus a fixed\n * subpath (`.theo/services.json`). No user input flows into the path.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\n\nimport type { ServiceDefinition, ServicesConfig } from '../schema/schema.js'\n\nexport interface ManifestServiceEntry {\n name: string\n runtime: 'python' | 'node'\n port: number\n proxy: string\n dev: string\n build?: string\n start: string\n openapi?: string\n healthcheck: string\n cors: boolean\n env?: Record<string, string>\n dependsOn?: string[]\n passSetCookie: boolean\n}\n\nexport interface ServicesManifest {\n version: 1\n services: ManifestServiceEntry[]\n}\n\nconst MANIFEST_RELATIVE_PATH = ['.theo', 'services.json'] as const\n\n/**\n * Topological sort using Kahn's algorithm.\n * Returns service names in dependency order (deps before dependants).\n * Schema validation guarantees no cycles, no self-deps, no missing references —\n * but we still defensively handle missing deps as no-op.\n */\nfunction topoSort(services: ServicesConfig): string[] {\n const names = Object.keys(services)\n const indeg: Record<string, number> = Object.fromEntries(names.map((n) => [n, 0]))\n const adj: Record<string, string[]> = Object.fromEntries(names.map((n) => [n, []]))\n\n const cmp = (a: string, b: string) => a.localeCompare(b)\n\n for (const name of names) {\n const deps = services[name].dependsOn ?? []\n for (const dep of deps) {\n if (!(dep in indeg)) continue\n adj[dep].push(name)\n indeg[name] = (indeg[name] ?? 0) + 1\n }\n }\n\n // Sort initial roots for determinism\n const queue: string[] = names.filter((n) => indeg[n] === 0).sort(cmp)\n const result: string[] = []\n while (queue.length > 0) {\n const cur = queue.shift()\n if (cur === undefined) break\n result.push(cur)\n const adjacent = (adj[cur] ?? []).slice().sort(cmp)\n for (const next of adjacent) {\n indeg[next] = (indeg[next] ?? 0) - 1\n if (indeg[next] === 0) {\n queue.push(next)\n }\n }\n }\n return result.length === names.length ? result : names // fallback (should not hit; schema rejects cycles)\n}\n\nfunction definitionToEntry(name: string, def: ServiceDefinition): ManifestServiceEntry {\n const entry: ManifestServiceEntry = {\n name,\n runtime: def.runtime,\n port: def.port,\n proxy: def.proxy,\n dev: def.dev,\n start: def.start,\n healthcheck: def.healthcheck,\n cors: def.cors,\n passSetCookie: def.passSetCookie,\n }\n if (def.build !== undefined) entry.build = def.build\n if (def.openapi !== undefined) entry.openapi = def.openapi\n if (def.env !== undefined) entry.env = def.env\n if (def.dependsOn !== undefined) entry.dependsOn = [...def.dependsOn]\n return entry\n}\n\nexport function buildManifest(services: ServicesConfig): ServicesManifest {\n const ordered = topoSort(services)\n return {\n version: 1,\n services: ordered.map((name) => definitionToEntry(name, services[name])),\n }\n}\n\nfunction manifestPath(cwd: string): string {\n return join(cwd, ...MANIFEST_RELATIVE_PATH)\n}\n\n/**\n * Write the manifest to `<cwd>/.theo/services.json`.\n *\n * EC-6 fix: creates `.theo/` recursively if absent (fresh project on first\n * `pnpm build` would otherwise hit ENOENT).\n */\nexport function writeManifest(cwd: string, manifest: ServicesManifest): void {\n const file = manifestPath(cwd)\n mkdirSync(dirname(file), { recursive: true })\n writeFileSync(file, JSON.stringify(manifest, null, 2), 'utf-8')\n}\n\n/**\n * Read the manifest from `<cwd>/.theo/services.json`.\n *\n * Returns null if the file does not exist (adapter's job to handle).\n * Throws with an actionable message if the file is malformed JSON.\n */\nexport function readManifest(cwd: string): ServicesManifest | null {\n const file = manifestPath(cwd)\n if (!existsSync(file)) return null\n const raw = readFileSync(file, 'utf-8')\n try {\n return JSON.parse(raw) as ServicesManifest\n } catch (err) {\n throw new Error(\n `failed to parse services.json at ${file}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n }\n}\n","/**\n * Wave 2 — Polyglot Services Orchestration (T1.1).\n *\n * Declarative `services: {}` primitive for `theo.config.ts`. Each entry\n * declares an external sidecar process (Python FastAPI / Node Hono) that\n * boots alongside the TheoKit TS app. Empty `services: {}` is the default\n * and preserves Wave 1 behavior (no impact on TS-only apps).\n *\n * See ADRs 0012-0015 + plan: docs/plans/wave-2-polyglot-services-plan.md\n */\nimport { z } from 'zod'\n\n/** Wave 2 runtime kinds. Go/Rust/Java/Ruby/PHP archived; deferred per ADR-0012 invariant #2/#3. */\nconst ServiceRuntimeSchema = z.enum(['python', 'node'])\n\n/** EC-3 fix: names that conflict with generated docker-compose entries. */\nconst RESERVED_SERVICE_NAMES = ['web', 'caddy', 'postgres', 'redis'] as const\n\n/**\n * EC-12 fix: service names must be docker-compose-safe — lowercase,\n * start with a letter, contain only a-z 0-9 -. Reserved names rejected.\n */\nconst ServiceNameSchema = z\n .string()\n .min(1)\n .regex(\n /^[a-z][a-z0-9-]*$/,\n 'service name must be lowercase, start with letter, contain only a-z 0-9 -',\n )\n .refine((n) => !(RESERVED_SERVICE_NAMES as readonly string[]).includes(n), {\n message: `service name conflicts with reserved name (${RESERVED_SERVICE_NAMES.join('/')})`,\n })\n\n/**\n * Single service definition. All commands run from `services/<name>/` cwd.\n *\n * EC-4 fix: `proxy` regex requires NON-EMPTY path after `/` (the `+` quantifier)\n * to reject `/` which would catch-all and conflict with TheoKit's own routing.\n */\nconst ServiceDefinitionSchema = z.object({\n runtime: ServiceRuntimeSchema,\n port: z.number().int().min(1).max(65535),\n proxy: z.string().regex(/^\\/[a-zA-Z0-9\\-_/]+$/, 'proxy must be a non-root path starting with /'),\n dev: z.string().min(1),\n build: z.string().optional(),\n start: z.string().min(1),\n openapi: z.string().url().optional(),\n healthcheck: z.string().regex(/^\\//, 'healthcheck must start with /').default('/health'),\n cors: z.boolean().default(false),\n env: z.record(z.string()).optional(),\n dependsOn: z.array(z.string()).optional(),\n /**\n * EC-25 + ref doc §8: by default the proxy strips upstream Set-Cookie\n * to prevent the polyglot service from issuing cookies that conflict\n * with TheoKit's encrypted session. Set to true to opt-in.\n */\n passSetCookie: z.boolean().default(false),\n})\n\nexport type ServiceDefinition = z.infer<typeof ServiceDefinitionSchema>\nexport type ServicesConfig = Record<string, ServiceDefinition>\n\n/**\n * Topological-order helper used by `dependsOn` cycle detection refine.\n * Returns true iff `graph` is a DAG. Each node's deps must all reference\n * existing nodes; cycles return false.\n */\nfunction isDag(graph: Record<string, readonly string[]>): boolean {\n const WHITE = 0\n const GRAY = 1\n const BLACK = 2\n const colors: Record<string, 0 | 1 | 2> = {}\n for (const node of Object.keys(graph)) colors[node] = WHITE\n\n function visit(node: string): boolean {\n if (colors[node] === GRAY) return false // cycle\n if (colors[node] === BLACK) return true\n colors[node] = GRAY\n for (const dep of graph[node] ?? []) {\n if (!(dep in graph)) return false // missing reference\n if (!visit(dep)) return false\n }\n colors[node] = BLACK\n return true\n }\n\n for (const node of Object.keys(graph)) {\n if (colors[node] === WHITE && !visit(node)) return false\n }\n return true\n}\n\n/**\n * Full services config schema with cross-service refines.\n *\n * EC-1 fix: detect duplicate ports across services.\n * EC-13: empty `dependsOn: []` accepted as no-deps.\n * Self-dep, missing-ref, and cycles rejected via topological check.\n */\nexport const servicesConfigSchema = z\n .record(ServiceNameSchema, ServiceDefinitionSchema)\n .default({})\n // EC-1: duplicate port detection across services\n .refine(\n (s) => {\n const ports = Object.values(s).map((v) => v.port)\n return new Set(ports).size === ports.length\n },\n {\n message: 'duplicate port across services — each service must bind a unique port',\n },\n )\n // duplicate proxy prefix detection\n .refine(\n (s) => {\n const prefixes = Object.values(s).map((v) => v.proxy)\n return new Set(prefixes).size === prefixes.length\n },\n { message: 'duplicate proxy prefix across services' },\n )\n // dependsOn correctness (self-dep, missing reference, cycle)\n .refine(\n (s) => {\n // Build graph\n const graph: Record<string, readonly string[]> = {}\n for (const [name, def] of Object.entries(s)) {\n graph[name] = def.dependsOn ?? []\n }\n // Self-dep: a service mentioning itself is rejected as part of cycle detection\n for (const [name, deps] of Object.entries(graph)) {\n if (deps.includes(name)) return false\n }\n return isDag(graph)\n },\n {\n message: 'invalid dependsOn — must reference existing services, no self-deps, no cycles',\n },\n )\n\nexport type ServicesConfigInput = z.input<typeof servicesConfigSchema>\nexport type ServicesConfigOutput = z.output<typeof servicesConfigSchema>\n","/**\n * Dev orchestration entry point (T2.4).\n *\n * Spawns declared polyglot services, waits for all healthchecks to pass,\n * then signals readiness. The `theokit dev` CLI calls `orchestrateDev`\n * BEFORE starting Vite — Vite only boots after all services healthy.\n *\n * Empty `services: {}` → no-op (Wave 1 BC).\n *\n * Single composable entry that the CLI consumes. Spawn/healthcheck/log\n * primitives live in their own modules; this file ties them together.\n */\nimport type { ChildProcess, SpawnOptions } from 'node:child_process'\nimport { spawn } from 'node:child_process'\nimport { resolve } from 'node:path'\n\nimport type { ServiceDefinition, ServicesConfig } from '../schema/schema.js'\n\nimport { pollHealthcheck } from './healthcheck-poller.js'\nimport { createLogMerger } from './log-merge.js'\nimport { buildSpawnEnv, installLifecycleHandlers } from './process-spawn-helpers.js'\n\nexport interface SpawnedService {\n name: string\n port: number\n process: ChildProcess\n}\n\nexport interface OrchestrateDevOptions {\n cwd: string\n services: ServicesConfig\n /** Defaults to `process.stdout.write.bind(process.stdout)`. */\n write?: (s: string) => void\n /** Test injection — replace child_process.spawn. */\n spawnFn?: typeof spawn\n /** Test injection — replace global fetch (for healthchecks). */\n customFetch?: typeof fetch\n /** Healthcheck timeout per service. Default 30_000. */\n healthcheckTimeoutMs?: number\n /** Whether to install parent lifecycle handlers (EC-7). Default true. */\n installSignalHandlers?: boolean\n}\n\nexport interface OrchestrateDevResult {\n spawned: SpawnedService[]\n /** Whether ALL services passed healthcheck. */\n allHealthy: boolean\n /** Services that timed out (only populated when !allHealthy). */\n unhealthy: string[]\n /** Call to gracefully stop all spawned services. */\n stop: () => Promise<void>\n}\n\nfunction spawnService(\n name: string,\n service: ServiceDefinition,\n cwd: string,\n options: {\n spawnFn: typeof spawn\n onLog: (s: string, stream: 'stdout' | 'stderr', line: string) => void\n },\n): SpawnedService {\n const env = buildSpawnEnv(name, service, process.env)\n const spawnOpts: SpawnOptions = {\n cwd,\n shell: true,\n env,\n stdio: ['ignore', 'pipe', 'pipe'],\n }\n const child = options.spawnFn(service.dev, spawnOpts)\n child.stdout?.setEncoding('utf-8')\n child.stderr?.setEncoding('utf-8')\n child.stdout?.on('data', (chunk: string) => {\n options.onLog(name, 'stdout', chunk)\n })\n child.stderr?.on('data', (chunk: string) => {\n options.onLog(name, 'stderr', chunk)\n })\n return { name, port: service.port, process: child }\n}\n\nasync function stopSpawned(s: SpawnedService): Promise<void> {\n return new Promise<void>((resolve) => {\n if (s.process.killed || s.process.exitCode !== null) {\n resolve()\n return\n }\n const timer = setTimeout(() => {\n s.process.kill('SIGKILL')\n resolve()\n }, 5_000)\n s.process.once('exit', () => {\n clearTimeout(timer)\n resolve()\n })\n s.process.kill('SIGTERM')\n })\n}\n\nexport async function orchestrateDev(\n options: OrchestrateDevOptions,\n): Promise<OrchestrateDevResult> {\n const entries = Object.entries(options.services)\n if (entries.length === 0) {\n return {\n spawned: [],\n allHealthy: true,\n unhealthy: [],\n stop: () => Promise.resolve(),\n }\n }\n\n const write =\n options.write ??\n ((s: string) => {\n process.stdout.write(s)\n })\n const spawnFn = options.spawnFn ?? spawn\n const merger = createLogMerger({ write })\n\n const spawned: SpawnedService[] = entries.map(([name, def]) =>\n spawnService(name, def, resolve(options.cwd, 'services', name), {\n spawnFn,\n onLog: merger.onLog,\n }),\n )\n\n const stop = async (): Promise<void> => {\n await Promise.all(spawned.map(stopSpawned))\n }\n\n if (options.installSignalHandlers !== false) {\n installLifecycleHandlers(process, stop)\n }\n\n // Parallel healthcheck\n const results = await Promise.all(\n entries.map(([name, def]) =>\n pollHealthcheck({\n url: `http://localhost:${String(def.port)}${def.healthcheck}`,\n timeoutMs: options.healthcheckTimeoutMs ?? 30_000,\n intervalMs: 500,\n customFetch: options.customFetch,\n }).then((r) => ({ name, result: r })),\n ),\n )\n\n const unhealthy = results.filter((r) => !r.result.healthy).map((r) => r.name)\n return {\n spawned,\n allHealthy: unhealthy.length === 0,\n unhealthy,\n stop,\n }\n}\n","/**\n * Healthcheck poller (T1.5).\n *\n * Polls `GET <url>` with backoff until 200 OR timeout. Used by `pnpm dev`\n * (T2.4) to gate readiness on declared services being healthy before\n * starting Vite.\n *\n * Invariants:\n * - Returns within `timeoutMs + intervalMs` (no hang)\n * - Never throws (returns `{ healthy: false }` on any error)\n * - `attempts >= 1` always\n * - Respects external AbortSignal (pre-aborted → immediate return, EC-18)\n */\n\nexport interface HealthcheckOptions {\n /** Full URL to poll, e.g. 'http://localhost:8001/health' */\n url: string\n /** Total time budget in ms. Default 30_000. */\n timeoutMs?: number\n /** Sleep between attempts in ms. Default 500. */\n intervalMs?: number\n /** Optional external cancel. Aborted signal causes early return. */\n signal?: AbortSignal\n /** Test injection — replace global fetch. */\n customFetch?: typeof fetch\n}\n\nexport interface HealthcheckResult {\n healthy: boolean\n attempts: number\n durationMs: number\n lastError?: string\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve) => {\n if (signal?.aborted) {\n resolve()\n return\n }\n const t = setTimeout(() => {\n resolve()\n }, ms)\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(t)\n resolve()\n },\n { once: true },\n )\n })\n}\n\nexport async function pollHealthcheck(options: HealthcheckOptions): Promise<HealthcheckResult> {\n const timeoutMs = options.timeoutMs ?? 30_000\n const intervalMs = options.intervalMs ?? 500\n const f = options.customFetch ?? fetch\n const start = Date.now()\n let attempts = 0\n let lastError: string | undefined\n\n // EC-18: signal already aborted → return immediately with at least 1 attempt counted\n if (options.signal?.aborted) {\n return {\n healthy: false,\n attempts: 1,\n durationMs: Date.now() - start,\n lastError: 'aborted',\n }\n }\n\n // Infinite poll loop terminated by status === 200 OR timeout OR abort.\n for (;;) {\n if (options.signal?.aborted) {\n return {\n healthy: false,\n attempts: Math.max(attempts, 1),\n durationMs: Date.now() - start,\n lastError: 'aborted',\n }\n }\n attempts++\n try {\n const res = await f(options.url, { method: 'GET', signal: options.signal })\n if (res.status === 200) {\n return { healthy: true, attempts, durationMs: Date.now() - start }\n }\n lastError = `status ${res.status}`\n } catch (err) {\n lastError = err instanceof Error ? err.message : String(err)\n }\n\n if (Date.now() - start >= timeoutMs) {\n return {\n healthy: false,\n attempts,\n durationMs: Date.now() - start,\n lastError,\n }\n }\n await sleep(intervalMs, options.signal)\n }\n}\n","/**\n * Log merger (T2.3).\n *\n * Combines stdout/stderr from multiple polyglot services into TheoKit's\n * dev terminal, prefixed with `[service-name]`. Parses JSON-line logs\n * (ADR-0015 invariant #5) for pretty-printing; falls back to raw line on\n * non-JSON.\n *\n * Pure / synchronous. The Vite plugin (T2.1) wires this as the `onLog`\n * callback passed to spawnServices.\n */\n\ninterface LogEntry {\n level?: string\n message?: string\n timestamp?: string\n traceparent?: string\n service?: string\n}\n\nexport interface LogMergerOptions {\n write: (s: string) => void\n}\n\nexport interface LogMerger {\n onLog: (service: string, stream: 'stdout' | 'stderr', chunk: string) => void\n}\n\n/**\n * Try to parse a log line as JSON. Returns parsed object on success,\n * undefined on failure (will fall back to raw rendering).\n */\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return v !== null && typeof v === 'object' && !Array.isArray(v)\n}\n\nfunction tryParseJson(line: string): LogEntry | undefined {\n const trimmed = line.trim()\n if (!trimmed.startsWith('{')) return undefined\n try {\n const parsed: unknown = JSON.parse(trimmed)\n if (!isPlainObject(parsed)) return undefined\n const entry: LogEntry = {}\n if (typeof parsed.level === 'string') entry.level = parsed.level\n if (typeof parsed.message === 'string') entry.message = parsed.message\n if (typeof parsed.timestamp === 'string') entry.timestamp = parsed.timestamp\n if (typeof parsed.traceparent === 'string') entry.traceparent = parsed.traceparent\n if (typeof parsed.service === 'string') entry.service = parsed.service\n return entry\n } catch {\n return undefined\n }\n}\n\nfunction renderLine(\n service: string,\n stream: 'stdout' | 'stderr',\n line: string,\n write: (s: string) => void,\n): void {\n if (line.length === 0) return\n\n const prefix = `[${service}]`\n const streamMarker = stream === 'stderr' ? '!' : ' '\n\n const parsed = tryParseJson(line)\n if (parsed) {\n const level = parsed.level ?? 'info'\n const msg = parsed.message ?? line\n write(`${prefix}${streamMarker}${level.toUpperCase()} ${msg}\\n`)\n return\n }\n\n write(`${prefix}${streamMarker}${line}\\n`)\n}\n\nexport function createLogMerger(options: LogMergerOptions): LogMerger {\n return {\n onLog(service, stream, chunk) {\n // Multi-line chunks: split by \\n and render each\n const lines = chunk.split('\\n')\n for (const line of lines) {\n renderLine(service, stream, line, options.write)\n }\n },\n }\n}\n","/**\n * Pure helpers extracted from process-spawn.ts (T2.2) for unit testability.\n *\n * The full spawn orchestration (child_process + healthcheck poll + log\n * merge) lives in process-spawn.ts; this file holds the parts that are\n * safe to test without mocking node:child_process.\n *\n * EC-7: lifecycle handlers prevent orphan children on parent exit/signal.\n * EC-8: auto-injected env vars (THEOKIT_SERVICE_NAME, THEOKIT_SERVICE_PORT).\n */\nimport type { ServiceDefinition } from '../schema/schema.js'\n\n/**\n * Build the env passed to `child_process.spawn`.\n *\n * Precedence (low → high):\n * 1. process.env (the parent's environment)\n * 2. auto-injected THEOKIT_SERVICE_NAME + THEOKIT_SERVICE_PORT\n * 3. service.env (user-provided overrides win)\n */\nexport function buildSpawnEnv(\n name: string,\n service: ServiceDefinition,\n parentEnv: Record<string, string | undefined>,\n): Record<string, string> {\n const env: Record<string, string> = {}\n for (const [k, v] of Object.entries(parentEnv)) {\n if (typeof v === 'string') env[k] = v\n }\n env.THEOKIT_SERVICE_NAME = name\n env.THEOKIT_SERVICE_PORT = String(service.port)\n if (service.env) {\n for (const [k, v] of Object.entries(service.env)) {\n env[k] = v\n }\n }\n return env\n}\n\n/**\n * Format a service name as a log prefix. Deterministic; ANSI codes added\n * by the log-merge layer (T2.3), not here.\n */\nexport function formatLogPrefix(name: string): string {\n return `[${name}]`\n}\n\n/**\n * Install parent-process lifecycle handlers (EC-7).\n *\n * - `exit`: best-effort SIGKILL of all children (synchronous; we cannot await here)\n * - `SIGINT`: graceful stopAllServices then exit 130\n * - `SIGTERM`: graceful stopAllServices then exit 143\n *\n * SIGKILL on the parent is uncatchable (kernel-level); orphan children\n * are documented as a known limit on force-close (EC-27 doc).\n */\nexport function installLifecycleHandlers(proc: NodeJS.Process, stopAll: () => Promise<void>): void {\n proc.on('exit', () => {\n // Best-effort sync notify; cannot await\n })\n proc.on('SIGINT', () => {\n void stopAll().finally(() => {\n proc.exit(130)\n })\n })\n proc.on('SIGTERM', () => {\n void stopAll().finally(() => {\n proc.exit(143)\n })\n })\n}\n","/**\n * Builds a Vite `server.proxy` configuration from TheoKit's\n * declarative `services: {}` config (T2.1).\n *\n * Pure function — no Vite imports, just data shaping. The Vite plugin\n * (services-dev.ts) calls this and merges the result into `vite.config.server.proxy`.\n *\n * Pattern follows Vite proxy reference (referencias/vite/packages/vite/src/node/server/middlewares/proxy.ts):\n * - Each path prefix becomes its own entry\n * - `changeOrigin: true` set by default (matches Vite's string-shortcut behavior)\n * - User-set entries take precedence on prefix collision (we never clobber)\n */\nimport type { ServicesConfig } from '../schema/schema.js'\n\n/**\n * Shape compatible with Vite's `server.proxy` type. We intentionally don't\n * import Vite's `ProxyOptions` so this module stays platform-neutral and\n * unit-testable without Vite.\n */\nexport interface ViteProxyEntry {\n target: string\n changeOrigin: boolean\n rewrite?: (path: string) => string\n}\n\nexport type ViteProxyConfig = Record<string, string | ViteProxyEntry>\n\nexport function buildServicesProxyConfig(\n services: ServicesConfig,\n userProxy: ViteProxyConfig = {},\n): ViteProxyConfig {\n const fromServices: ViteProxyConfig = {}\n for (const [, def] of Object.entries(services)) {\n const prefix = def.proxy\n fromServices[prefix] = {\n target: `http://localhost:${String(def.port)}`,\n changeOrigin: true,\n // Strip the service's `proxy` prefix from the upstream URL so the\n // sidecar receives its own native paths (e.g. `/api/agent/echo` →\n // `/echo`). The sidecar declares routes against its own root path —\n // it doesn't know about the TheoKit proxy prefix.\n rewrite: (path: string) =>\n path.startsWith(prefix) ? path.slice(prefix.length) || '/' : path,\n }\n }\n // User proxy wins on collision (we add services first, then spread user on top)\n return { ...fromServices, ...userProxy }\n}\n","/**\n * TheoCloud adapter scaffolding (T3.5 — Wave 2 stub; full Wave 3).\n *\n * Wave 2 establishes the contract: the adapter CONSUMES `.theo/services.json`\n * (manifest emitted by `theokit build`) and produces TheoCloud deployment\n * artifacts. The artifacts themselves (K8s manifests, Helm charts, etc.) are\n * Wave 3 deliverables — this module provides the read/validate gate so the\n * manifest format is locked NOW.\n *\n * Per ADR-0012 invariant #4, the same `.theo/services.json` consumed by\n * the `node` adapter (docker-compose generator) is the same shape consumed\n * here. No platform-specific fields. The contract is global.\n */\nimport type { ServicesManifest } from './manifest.js'\n\nexport interface TheoCloudAdapterArtifacts {\n /** Manifest schemaVersion the adapter consumed. */\n manifestVersion: 1\n /** Service names that will be deployed. */\n services: string[]\n /** Wave 3 will populate K8s manifests here. */\n k8sManifests?: never\n /** Wave 3 will populate Helm values here. */\n helmValues?: never\n}\n\n/**\n * Wave 2 stub — validates the manifest is consumable. Throws if shape is\n * unexpected (forward-compat guard for Wave 3 development).\n *\n * Wave 3 will replace the body with real K8s manifest emission.\n */\nexport function prepareTheoCloudArtifacts(\n manifest: ServicesManifest | null,\n): TheoCloudAdapterArtifacts {\n if (manifest === null) {\n return { manifestVersion: 1, services: [] }\n }\n // Forward-compat: when Wave 3 evolves the manifest schema, the adapter\n // must bump version handling explicitly.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- defensive: manifest comes from disk\n if (manifest.version !== 1) {\n throw new Error(\n `TheoCloud adapter: unsupported manifest version ${String(manifest.version)}. ` +\n `Wave 2/3 expects schemaVersion 1. Update the adapter before bumping.`,\n )\n }\n return {\n manifestVersion: 1,\n services: manifest.services.map((s) => s.name),\n }\n}\n"],"mappings":"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","names":["resolve","resolve"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/schema.ts"],"sourcesContent":["import { z } from 'zod'\n\nimport { servicesConfigSchema } from '../services/index.js'\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().args(z.unknown()).returns(z.string()),\n ])\n .optional(),\n cookieName: z.string().min(1).optional(),\n }),\n])\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\nexport const loggingSchema = z.object({\n level: z.enum(['debug', 'info', 'warn', 'error', 'silent']).default('info'),\n})\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({}),\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({}),\n routeRules: z.record(z.string(), routeRuleSchema).optional(),\n})\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 * 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 */\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.\n */\nconst headerSafeString = z\n .string()\n .refine((s) => !/[\\r\\n]/.test(s), { message: 'Header value must not contain CR/LF' })\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 */\nexport const 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().args(z.string()).returns(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\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\nexport const theoConfigSchema = z\n .object({\n appDir: z.string().default('app'),\n serverDir: z.string().default('server'),\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('.theo')\n .refine(\n (d) => !/^([A-Za-z]:)?[/\\\\]/.test(d) && !d.startsWith('..'),\n 'distDir must be a relative path inside the project root (e.g., \".theo\")',\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 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 \".theo\" (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.string().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('.theo'),\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\nexport type OpenApiConfig = NonNullable<TheoConfig['openapi']>\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/load-env.ts","../src/config/load-config.ts","../src/config/errors.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'\nimport { pathToFileURL } from 'node:url'\n\nimport { TheoConfigError } from './errors.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 import(pathToFileURL(configPath).href)) as Record<string, unknown>\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 import(pathToFileURL(envPath).href)) as Record<string, unknown>\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"],"mappings":"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","names":["resolve","resolve"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/_internal/atomic-write.ts","../src/server/observability/trace-context-propagation.ts"],"sourcesContent":["/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time atomic write: caller-controlled paths only. No HTTP input\n * reaches these fs calls.\n */\nimport { randomBytes } from 'node:crypto'\nimport { mkdirSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\n\n/**\n * Write `content` to `path` atomically via the tmp + rename pattern.\n *\n * Two concurrent calls to `writeAtomic(path, ...)` are guaranteed to\n * leave `path` containing valid content from ONE of the calls (never\n * truncated, never interleaved). POSIX rename is atomic on the same\n * filesystem.\n *\n * EC-106 (jobs-crons-webhooks-cost-tracking-plan) — shared helper for\n * `.theo/crons.json` and `.theo/jobs.json` manifest writes so a\n * concurrent dev-server scan + build manifest emit never produces\n * partial JSON.\n *\n * @param path destination path\n * @param content bytes (UTF-8 string) to write\n */\nexport function writeAtomic(path: string, content: string): void {\n mkdirSync(dirname(path), { recursive: true })\n // Include a random suffix so two concurrent writes don't trample each\n // other's tmp file. crypto.randomBytes is non-blocking + collision-safe\n // for the tiny entropy we need (8 hex chars = 32 bits).\n const tmp = `${path}.tmp-${process.pid}-${randomBytes(4).toString('hex')}`\n writeFileSync(tmp, content, 'utf8')\n renameSync(tmp, path)\n}\n","import { randomBytes } from 'node:crypto'\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 // randomBytes is overwhelmingly unlikely to produce all-zeros, but we\n // guard anyway — the W3C spec rejects all-zeros and tests assert this.\n for (;;) {\n const hex = randomBytes(bytes).toString('hex')\n if (!/^0+$/.test(hex)) return hex\n }\n}\n"],"mappings":";AAIA,SAAS,mBAAmB;AAC5B,SAAS,WAAW,YAAY,qBAAqB;AACrD,SAAS,eAAe;AAkBjB,SAAS,YAAY,MAAc,SAAuB;AAC/D,YAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAI5C,QAAM,MAAM,GAAG,IAAI,QAAQ,QAAQ,GAAG,IAAI,YAAY,CAAC,EAAE,SAAS,KAAK,CAAC;AACxE,gBAAc,KAAK,SAAS,MAAM;AAClC,aAAW,KAAK,IAAI;AACtB;;;AChCA,SAAS,eAAAA,oBAAmB;AAgC5B,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;AAGxC,aAAS;AACP,UAAM,MAAMC,aAAY,KAAK,EAAE,SAAS,KAAK;AAC7C,QAAI,CAAC,OAAO,KAAK,GAAG,EAAG,QAAO;AAAA,EAChC;AACF;","names":["randomBytes","randomBytes"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/vite-plugin/openapi-emit/emit.ts","../src/vite-plugin/openapi-emit/zod-to-openapi.ts","../src/vite-plugin/openapi-emit/load-routes.ts"],"sourcesContent":["/**\n * In-house `emitOpenApi()` orchestrator (build-time only).\n *\n * Pure transformation: takes a route manifest (already hydrated with Zod\n * schemas extracted from `defineRoute()` config) + the openapi config\n * block, builds an OpenAPI 3.x document, writes `<outDir>/openapi.json`,\n * returns the document for downstream callers (CLI logs, tests).\n *\n * Per G2 plan v1.1 T2.1. Modelled on trpc-openapi's\n * `generateOpenApiDocument` + encore's `Generator.Generate()`.\n *\n * NEVER ship to runtime — devDep-shaped artifact.\n *\n * Path templating: TheoKit's `:param` syntax is converted to OpenAPI's\n * `{param}` per the spec. Env-var override: `THEOKIT_OPENAPI_SERVER_URL`\n * overrides `servers[0].url` without rebuilding the config.\n */\n/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time emit. outDir is a config-controlled relative path. The\n * caller already refused absolute paths via theoConfigSchema.distDir\n * pattern; the openapi.outDir field follows the same convention.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { z } from 'zod'\n\nimport { zodToOpenApiSchema, type ConvertCtx, type OpenApiSchema } from './zod-to-openapi.js'\n\nexport interface OpenApiManifestRoute {\n /** TheoKit-style path with `:param` placeholders (`/users/:id`). */\n routePath: string\n /** Uppercase HTTP methods the route exports (`['GET','POST']`). */\n methods: string[]\n /** Optional `defineRoute({body})` schema. */\n body?: z.ZodType\n /** Optional `defineRoute({query})` schema. */\n query?: z.ZodType\n /** Optional `defineRoute({params})` schema. */\n params?: z.ZodType\n /** Optional `defineRoute({response})` schema. */\n response?: z.ZodType\n}\n\nexport interface OpenApiEmitConfig {\n servers: { url: string; description?: string }[]\n specVersion: '3.1.0' | '3.0.3'\n title: string\n version: string\n outDir: string\n}\n\nexport interface OpenApiOperation {\n operationId?: string\n parameters?: OpenApiParameter[]\n requestBody?: {\n required?: boolean\n content: Record<string, { schema: OpenApiSchema }>\n }\n responses: Record<\n string,\n { description: string; content?: Record<string, { schema: OpenApiSchema }> }\n >\n}\n\nexport interface OpenApiParameter {\n name: string\n in: 'path' | 'query' | 'header' | 'cookie'\n required: boolean\n schema: OpenApiSchema\n description?: string\n}\n\nexport type OpenApiPathItem = Partial<\n Record<'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options', OpenApiOperation>\n>\n\nexport interface OpenApiDocument {\n openapi: '3.1.0' | '3.0.3'\n info: { title: string; version: string }\n servers: { url: string; description?: string }[]\n paths: Record<string, OpenApiPathItem>\n components?: { schemas?: Record<string, OpenApiSchema> }\n}\n\nexport interface EmitOpenApiInput {\n manifest: OpenApiManifestRoute[]\n config: OpenApiEmitConfig\n}\n\nexport interface EmitOpenApiResult {\n document: OpenApiDocument\n path: string\n}\n\nconst METHOD_TO_KEY: Record<string, keyof OpenApiPathItem> = {\n GET: 'get',\n POST: 'post',\n PUT: 'put',\n PATCH: 'patch',\n DELETE: 'delete',\n HEAD: 'head',\n OPTIONS: 'options',\n}\n\n/** Convert `/users/:id/posts/:postId?` → `/users/{id}/posts/{postId}`. */\nexport function templatePath(routePath: string): string {\n // Bounded quantifier (\\w{0,64}) is OSS-safe — TheoKit route param names\n // never exceed 64 chars in practice; cap prevents super-linear backtracking.\n return routePath.replace(/:([A-Za-z_]\\w{0,64})\\??/g, '{$1}')\n}\n\nfunction buildParameters(\n paramsSchema: z.ZodType | undefined,\n querySchema: z.ZodType | undefined,\n ctx: ConvertCtx,\n): OpenApiParameter[] {\n const out: OpenApiParameter[] = []\n if (paramsSchema !== undefined) {\n appendObjectAsParameters(paramsSchema, 'path', out, ctx)\n }\n if (querySchema !== undefined) {\n appendObjectAsParameters(querySchema, 'query', out, ctx)\n }\n return out\n}\n\nfunction appendObjectAsParameters(\n schema: z.ZodType,\n location: 'path' | 'query',\n out: OpenApiParameter[],\n ctx: ConvertCtx,\n): void {\n // We expect an object schema; if it's not, skip silently (caller already\n // validated upstream when scanning defineRoute()).\n const shape = (schema as unknown as { shape?: Record<string, z.ZodType> }).shape\n if (shape === undefined) return\n for (const [name, child] of Object.entries(shape)) {\n const childDef = (child as unknown as { _def: { typeName?: string } })._def\n const optional = childDef.typeName === 'ZodOptional' || childDef.typeName === 'ZodDefault'\n out.push({\n name,\n in: location,\n required: location === 'path' ? true : !optional,\n schema: zodToOpenApiSchema(child, { ctx }),\n })\n }\n}\n\nfunction buildOperation(\n route: OpenApiManifestRoute,\n ctx: ConvertCtx,\n method: string,\n): OpenApiOperation {\n // Bounded sanitizer: two single-pass replacements (no nested quantifiers).\n const sanitized = route.routePath.replace(/[/:\\-{}]/g, '_').replace(/_+/g, '_')\n const operationId = `${method.toLowerCase()}_${sanitized.replace(/^_|_$/g, '')}`\n const op: OpenApiOperation = {\n operationId,\n responses: {\n '200': { description: 'OK' },\n },\n }\n\n const parameters = buildParameters(route.params, route.query, ctx)\n if (parameters.length > 0) op.parameters = parameters\n\n // Body only meaningful for write methods; we still attach if defined so\n // the document is honest about the contract.\n if (route.body !== undefined) {\n op.requestBody = {\n required: true,\n content: {\n 'application/json': { schema: zodToOpenApiSchema(route.body, { ctx }) },\n },\n }\n }\n\n if (route.response !== undefined) {\n op.responses['200'] = {\n description: 'OK',\n content: {\n 'application/json': { schema: zodToOpenApiSchema(route.response, { ctx }) },\n },\n }\n }\n\n return op\n}\n\nexport function emitOpenApi(input: EmitOpenApiInput): EmitOpenApiResult {\n const { manifest, config } = input\n\n const ctx: ConvertCtx = { seen: new Map(), components: {} }\n\n const paths: Record<string, OpenApiPathItem> = {}\n for (const route of manifest) {\n const templatedPath = templatePath(route.routePath)\n const item: OpenApiPathItem = paths[templatedPath] ?? {}\n for (const method of route.methods) {\n // Defensive: manifest emitter normalizes to uppercase, but if a\n // future scanner produces a non-HTTP verb the key lookup yields\n // undefined and we skip silently. TS narrows the indexed type to\n // keyof OpenApiPathItem; the runtime undefined check is honest.\n const key = METHOD_TO_KEY[method.toUpperCase()] as keyof OpenApiPathItem | undefined\n if (key === undefined) continue\n item[key] = buildOperation(route, ctx, method)\n }\n paths[templatedPath] = item\n }\n\n const servers = applyServerOverride(config.servers)\n\n const document: OpenApiDocument = {\n openapi: config.specVersion,\n info: { title: config.title, version: config.version },\n servers,\n paths,\n }\n\n if (Object.keys(ctx.components).length > 0) {\n document.components = { schemas: ctx.components }\n }\n\n mkdirSync(config.outDir, { recursive: true })\n const outPath = join(config.outDir, 'openapi.json')\n writeFileSync(outPath, `${JSON.stringify(document, null, 2)}\\n`, 'utf8')\n\n return { document, path: outPath }\n}\n\nfunction applyServerOverride(\n servers: { url: string; description?: string }[],\n): { url: string; description?: string }[] {\n const override = process.env.THEOKIT_OPENAPI_SERVER_URL\n if (override === undefined || override === '') return servers\n if (servers.length === 0) return [{ url: override }]\n const [first, ...rest] = servers\n return [\n {\n url: override,\n ...(first.description !== undefined ? { description: first.description } : {}),\n },\n ...rest,\n ]\n}\n","/**\n * In-house Zod → OpenAPI 3.x Schema converter (build-time only).\n *\n * Per G2 plan v1.1 ADR D1 + EC-1: installed zod is 3.x (no native\n * `.toJSONSchema()`). This module is the PRIMARY conversion path.\n * Algorithm modelled on encore's `pkg/clientgen/openapi/schema.go`:\n * recursive descent + seen-map for cycle detection (named refs).\n *\n * Pure function: no I/O, no module loading. Caller extracts the Zod\n * schemas from `defineRoute({body, query, params})` and passes them\n * here. Returned `OpenApiSchema` is a structural subset of the OpenAPI\n * 3.0/3.1 Schema Object — fields populated as needed.\n *\n * NEVER ship to runtime — devDep-shaped artifact.\n *\n * Unsupported Zod constructs (z.function(), z.promise()) throw a\n * `ZodToOpenApiError` with a descriptive message so the caller can\n * surface the offending route + advise the user.\n */\nimport type { z } from 'zod'\n\nexport interface OpenApiSchema {\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object' | 'null'\n format?: string\n items?: OpenApiSchema\n properties?: Record<string, OpenApiSchema>\n required?: string[]\n additionalProperties?: boolean | OpenApiSchema\n oneOf?: OpenApiSchema[]\n anyOf?: OpenApiSchema[]\n allOf?: OpenApiSchema[]\n discriminator?: { propertyName: string; mapping?: Record<string, string> }\n enum?: unknown[]\n nullable?: boolean\n description?: string\n $ref?: string\n // OpenAPI 3.1 (JSON Schema 2020-12) allows `type: [..., 'null']`; for now\n // we stick with 3.0-compatible `nullable: true`. Caller can transform at\n // emit time if specVersion === '3.1.0'.\n}\n\nexport interface ConvertCtx {\n /** Seen-map: zod schema reference → component name (for $ref cycle detection). */\n seen: Map<z.ZodType, string>\n /** Output bucket for named component schemas. */\n components: Record<string, OpenApiSchema>\n}\n\nexport interface ConvertOptions {\n /**\n * Optional context carried across recursive calls. Pass the SAME ctx to\n * every `zodToOpenApiSchema` invocation in one emit pass so cycle\n * detection works across multiple routes.\n */\n ctx?: ConvertCtx\n /**\n * If provided, the schema is registered under `components.schemas[name]`\n * and the returned value is `{ $ref: '#/components/schemas/<name>' }`.\n * Use this for top-level recursive types where the consumer (e.g.,\n * OpenAPI document builder) wants named schemas instead of inlined ones.\n */\n name?: string\n}\n\nexport class ZodToOpenApiError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ZodToOpenApiError'\n }\n}\n\nexport function zodToOpenApiSchema(schema: z.ZodType, options: ConvertOptions = {}): OpenApiSchema {\n const ctx: ConvertCtx = options.ctx ?? { seen: new Map(), components: {} }\n\n const name = options.name\n if (name !== undefined) {\n // Top-level named schema — register placeholder BEFORE recursing, then\n // patch the slot with the computed body. This avoids infinite recursion\n // for self-referential types (encore schema.go:289 pattern).\n if (Object.prototype.hasOwnProperty.call(ctx.components, name)) {\n return { $ref: `#/components/schemas/${name}` }\n }\n ctx.seen.set(schema, name)\n ctx.components[name] = {} // placeholder\n const body = convert(schema, ctx)\n ctx.components[name] = body\n return { $ref: `#/components/schemas/${name}` }\n }\n\n return convert(schema, ctx)\n}\n\n// eslint-disable-next-line complexity -- switch-based dispatch on Zod typeName; splitting hides intent\nfunction convert(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n // Cycle: if we've seen this exact schema reference before, emit $ref.\n const existing = ctx.seen.get(schema)\n if (existing !== undefined) {\n return { $ref: `#/components/schemas/${existing}` }\n }\n\n const def = (schema as unknown as { _def: { typeName?: string } })._def\n const typeName = def.typeName ?? ''\n\n switch (typeName) {\n case 'ZodString':\n return convertString(schema)\n case 'ZodNumber':\n return convertNumber(schema)\n case 'ZodBoolean':\n return { type: 'boolean' }\n case 'ZodLiteral':\n return convertLiteral(schema)\n case 'ZodEnum':\n return convertEnum(schema)\n case 'ZodArray':\n return convertArray(schema, ctx)\n case 'ZodObject':\n return convertObject(schema, ctx)\n case 'ZodUnion':\n return convertUnion(schema, ctx)\n case 'ZodDiscriminatedUnion':\n return convertDiscriminatedUnion(schema, ctx)\n case 'ZodOptional':\n // Optional-as-property is handled at object level; here we unwrap.\n return convert((schema as unknown as { _def: { innerType: z.ZodType } })._def.innerType, ctx)\n case 'ZodNullable': {\n const inner = convert(\n (schema as unknown as { _def: { innerType: z.ZodType } })._def.innerType,\n ctx,\n )\n return { ...inner, nullable: true }\n }\n case 'ZodEffects':\n case 'ZodTransform':\n // Transforms change runtime output, but the WIRE shape is the input.\n return convert((schema as unknown as { _def: { schema: z.ZodType } })._def.schema, ctx)\n case 'ZodDefault':\n return convert((schema as unknown as { _def: { innerType: z.ZodType } })._def.innerType, ctx)\n case 'ZodLazy': {\n const getter = (schema as unknown as { _def: { getter: () => z.ZodType } })._def.getter\n return convert(getter(), ctx)\n }\n case 'ZodRecord': {\n const valueType = (schema as unknown as { _def: { valueType: z.ZodType } })._def.valueType\n return { type: 'object', additionalProperties: convert(valueType, ctx) }\n }\n case 'ZodAny':\n case 'ZodUnknown':\n return {} // no constraint\n case 'ZodNull':\n return { type: 'null' }\n case 'ZodFunction':\n throw new ZodToOpenApiError(\n 'Unsupported Zod type: z.function() cannot be represented in OpenAPI Schema. Remove from the route schema.',\n )\n case 'ZodPromise':\n throw new ZodToOpenApiError(\n 'Unsupported Zod type: z.promise() cannot be represented in OpenAPI Schema. Unwrap the value before passing to defineRoute.',\n )\n default:\n throw new ZodToOpenApiError(\n `Unsupported Zod type: ${typeName || '(unknown)'}. Open an issue if this construct should be supported.`,\n )\n }\n}\n\ninterface StringCheck {\n kind: string\n}\n\nfunction convertString(schema: z.ZodType): OpenApiSchema {\n const def = (schema as unknown as { _def: { checks?: StringCheck[] } })._def\n const checks = def.checks ?? []\n const out: OpenApiSchema = { type: 'string' }\n for (const c of checks) {\n if (c.kind === 'email') out.format = 'email'\n else if (c.kind === 'uuid') out.format = 'uuid'\n else if (c.kind === 'url') out.format = 'uri'\n else if (c.kind === 'datetime') out.format = 'date-time'\n }\n return out\n}\n\ninterface NumberCheck {\n kind: string\n}\n\nfunction convertNumber(schema: z.ZodType): OpenApiSchema {\n const def = (schema as unknown as { _def: { checks?: NumberCheck[] } })._def\n const checks = def.checks ?? []\n const isInt = checks.some((c) => c.kind === 'int')\n return { type: isInt ? 'integer' : 'number' }\n}\n\nfunction convertLiteral(schema: z.ZodType): OpenApiSchema {\n const value = (schema as unknown as { _def: { value: unknown } })._def.value\n const typed = literalTypeOf(value)\n if (typed === null) {\n // Null literal\n return { type: 'null', enum: [null] }\n }\n return { type: typed, enum: [value] }\n}\n\nfunction literalTypeOf(value: unknown): OpenApiSchema['type'] | null {\n if (value === null) return null\n if (typeof value === 'string') return 'string'\n if (typeof value === 'number') return Number.isInteger(value) ? 'integer' : 'number'\n if (typeof value === 'boolean') return 'boolean'\n return 'string' // fallback for symbol/etc.\n}\n\nfunction convertEnum(schema: z.ZodType): OpenApiSchema {\n const values = (schema as unknown as { _def: { values: readonly string[] } })._def.values\n return { type: 'string', enum: [...values] }\n}\n\nfunction convertArray(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const inner = (schema as unknown as { _def: { type: z.ZodType } })._def.type\n return { type: 'array', items: convert(inner, ctx) }\n}\n\nfunction convertObject(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const shape = (schema as unknown as { shape: Record<string, z.ZodType> }).shape\n const properties: Record<string, OpenApiSchema> = {}\n const required: string[] = []\n for (const [key, child] of Object.entries(shape)) {\n properties[key] = convert(child, ctx)\n const childDef = (child as unknown as { _def: { typeName?: string } })._def\n const isOptional = childDef.typeName === 'ZodOptional' || childDef.typeName === 'ZodDefault'\n if (!isOptional) required.push(key)\n }\n const out: OpenApiSchema = {\n type: 'object',\n properties,\n additionalProperties: false,\n }\n if (required.length > 0) out.required = required\n return out\n}\n\nfunction convertUnion(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const options = (schema as unknown as { _def: { options: z.ZodType[] } })._def.options\n return { oneOf: options.map((o) => convert(o, ctx)) }\n}\n\nfunction convertDiscriminatedUnion(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const def = (\n schema as unknown as {\n _def: { discriminator: string; options: z.ZodType[] }\n }\n )._def\n return {\n oneOf: def.options.map((o) => convert(o, ctx)),\n discriminator: { propertyName: def.discriminator },\n }\n}\n","/**\n * Build-time route loader for OpenAPI emit.\n *\n * Takes the G1 manifest (filePath + routePath + methods) and hydrates each\n * route's Zod schemas by dynamically importing the module. `defineRoute`\n * is an identity function, so the imported config exposes `body/query/\n * params/response` directly without any AST gymnastics.\n *\n * Supports both export shapes:\n * 1. `export const POST = defineRoute({...})` (per-method named exports)\n * 2. `export default defineRoute({...})` (single-export legacy shape)\n *\n * Per G2 plan v1.1 T2.2. Uses Vite's `ssrLoadModule` because route files\n * are TS at build time — Node's native loader doesn't transpile.\n */\nimport { resolve } from 'node:path'\n\nimport type { z } from 'zod'\n\nimport type { ManifestRoute } from '../../server/scan/manifest.js'\n\nimport type { OpenApiManifestRoute } from './emit.js'\n\ninterface RouteConfigShape {\n body?: z.ZodType\n query?: z.ZodType\n params?: z.ZodType\n response?: z.ZodType\n}\n\ninterface ViteLikeServer {\n ssrLoadModule: (id: string) => Promise<Record<string, unknown>>\n close: () => Promise<void>\n}\n\ninterface DefaultLoader {\n load: (absPath: string) => Promise<Record<string, unknown>>\n dispose: () => Promise<void>\n}\n\n/** Method names recognized as per-route named exports (UPPERCASE). */\nconst HTTP_METHOD_KEYS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const\n\nexport interface LoadRoutesOptions {\n serverDir: string\n routes: ManifestRoute[]\n /** Injectable for tests; defaults to a fresh Vite SSR dev server. */\n loadModule?: (absPath: string) => Promise<Record<string, unknown>>\n}\n\n/**\n * Hydrate manifest routes with Zod schemas extracted from their modules.\n *\n * Returns one `OpenApiManifestRoute` per (file × method) tuple. If a route\n * file declares multiple methods (`GET` + `POST`), each method gets its\n * own entry with the schemas from that method's `defineRoute()` call.\n *\n * Routes that fail to load are skipped with a console warning — the emit\n * should be best-effort, not a hard build failure.\n *\n * The default Vite loader is created once per call and disposed in the\n * `finally` block so the underlying server is released even when route\n * loading throws.\n */\nexport async function loadRoutesForOpenApi(\n options: LoadRoutesOptions,\n): Promise<OpenApiManifestRoute[]> {\n const { serverDir, routes } = options\n let loadModule = options.loadModule\n let dispose: (() => Promise<void>) | undefined\n if (loadModule === undefined) {\n const created = await createDefaultLoader(serverDir)\n loadModule = created.load\n dispose = created.dispose\n }\n\n const out: OpenApiManifestRoute[] = []\n try {\n for (const r of routes) {\n const abs = resolve(serverDir, r.filePath)\n let mod: Record<string, unknown>\n try {\n mod = await loadModule(abs)\n } catch (err) {\n console.warn(\n `[openapi-emit] Skipping ${r.filePath}: load failed (${(err as Error).message})`,\n )\n continue\n }\n\n const methods = r.methods ?? HTTP_METHOD_KEYS.filter((m) => mod[m] !== undefined)\n if (methods.length === 0) {\n // Fall back to default export when no method-named exports detected.\n const def = mod.default\n if (def !== undefined && def !== null) {\n out.push({ routePath: r.routePath, methods: ['GET'], ...extractSchemas(def) })\n }\n continue\n }\n\n for (const method of methods) {\n const handler = mod[method] ?? mod.default\n if (handler === undefined || handler === null) continue\n out.push({ routePath: r.routePath, methods: [method], ...extractSchemas(handler) })\n }\n }\n } finally {\n if (dispose !== undefined) {\n await dispose()\n }\n }\n return out\n}\n\nfunction extractSchemas(handlerExport: unknown): RouteConfigShape {\n if (typeof handlerExport !== 'object' || handlerExport === null) return {}\n const cfg = handlerExport as RouteConfigShape\n const out: RouteConfigShape = {}\n if (cfg.body !== undefined) out.body = cfg.body\n if (cfg.query !== undefined) out.query = cfg.query\n if (cfg.params !== undefined) out.params = cfg.params\n if (cfg.response !== undefined) out.response = cfg.response\n return out\n}\n\n/**\n * Default loader: spin up a minimal Vite SSR dev server (no HMR, no\n * middlewares) just to use its `ssrLoadModule`. Vite handles TS, ESM, and\n * import resolution for free.\n *\n * Returns `{load, dispose}` — the caller owns the lifecycle and MUST\n * call `dispose()` (typically in a `finally`) so the server is closed.\n */\nasync function createDefaultLoader(serverDir: string): Promise<DefaultLoader> {\n // Vite is a peerDep in build flows; import dynamically.\n const { createServer } = await import('vite')\n const server = (await createServer({\n root: serverDir,\n configFile: false,\n server: { middlewareMode: true },\n appType: 'custom',\n logLevel: 'silent',\n })) as unknown as ViteLikeServer\n\n const swallow = (): void => {\n /* eat close errors — best-effort cleanup */\n }\n return {\n load: async (absPath) => server.ssrLoadModule(absPath),\n dispose: async () => {\n await server.close().catch(swallow)\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/vite-plugin/openapi-emit/emit.ts","../src/vite-plugin/openapi-emit/zod-to-openapi.ts","../src/vite-plugin/openapi-emit/load-routes.ts","../src/vite-plugin/openapi-emit/dev-emit.ts"],"sourcesContent":["/**\n * In-house `emitOpenApi()` orchestrator (build-time only).\n *\n * Pure transformation: takes a route manifest (already hydrated with Zod\n * schemas extracted from `defineRoute()` config) + the openapi config\n * block, builds an OpenAPI 3.x document, writes `<outDir>/openapi.json`,\n * returns the document for downstream callers (CLI logs, tests).\n *\n * Per G2 plan v1.1 T2.1. Modelled on trpc-openapi's\n * `generateOpenApiDocument` + encore's `Generator.Generate()`.\n *\n * NEVER ship to runtime — devDep-shaped artifact.\n *\n * Path templating: TheoKit's `:param` syntax is converted to OpenAPI's\n * `{param}` per the spec. Env-var override: `THEOKIT_OPENAPI_SERVER_URL`\n * overrides `servers[0].url` without rebuilding the config.\n */\n/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time emit. outDir is a config-controlled relative path. The\n * caller already refused absolute paths via theoConfigSchema.distDir\n * pattern; the openapi.outDir field follows the same convention.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { z } from 'zod'\n\nimport { zodToOpenApiSchema, type ConvertCtx, type OpenApiSchema } from './zod-to-openapi.js'\n\nexport interface OpenApiManifestRoute {\n /** TheoKit-style path with `:param` placeholders (`/users/:id`). */\n routePath: string\n /** Uppercase HTTP methods the route exports (`['GET','POST']`). */\n methods: string[]\n /** Optional `defineRoute({body})` schema. */\n body?: z.ZodType\n /** Optional `defineRoute({query})` schema. */\n query?: z.ZodType\n /** Optional `defineRoute({params})` schema. */\n params?: z.ZodType\n /** Optional `defineRoute({response})` schema. */\n response?: z.ZodType\n}\n\nexport interface OpenApiEmitConfig {\n servers: { url: string; description?: string }[]\n specVersion: '3.1.0' | '3.0.3'\n title: string\n version: string\n outDir: string\n}\n\nexport interface OpenApiOperation {\n operationId?: string\n parameters?: OpenApiParameter[]\n requestBody?: {\n required?: boolean\n content: Record<string, { schema: OpenApiSchema }>\n }\n responses: Record<\n string,\n { description: string; content?: Record<string, { schema: OpenApiSchema }> }\n >\n}\n\nexport interface OpenApiParameter {\n name: string\n in: 'path' | 'query' | 'header' | 'cookie'\n required: boolean\n schema: OpenApiSchema\n description?: string\n}\n\nexport type OpenApiPathItem = Partial<\n Record<'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options', OpenApiOperation>\n>\n\nexport interface OpenApiDocument {\n openapi: '3.1.0' | '3.0.3'\n info: { title: string; version: string }\n servers: { url: string; description?: string }[]\n paths: Record<string, OpenApiPathItem>\n components?: { schemas?: Record<string, OpenApiSchema> }\n}\n\nexport interface EmitOpenApiInput {\n manifest: OpenApiManifestRoute[]\n config: OpenApiEmitConfig\n}\n\nexport interface EmitOpenApiResult {\n document: OpenApiDocument\n path: string\n}\n\nconst METHOD_TO_KEY: Record<string, keyof OpenApiPathItem> = {\n GET: 'get',\n POST: 'post',\n PUT: 'put',\n PATCH: 'patch',\n DELETE: 'delete',\n HEAD: 'head',\n OPTIONS: 'options',\n}\n\n/** Convert `/users/:id/posts/:postId?` → `/users/{id}/posts/{postId}`. */\nexport function templatePath(routePath: string): string {\n // Bounded quantifier (\\w{0,64}) is OSS-safe — TheoKit route param names\n // never exceed 64 chars in practice; cap prevents super-linear backtracking.\n return routePath.replace(/:([A-Za-z_]\\w{0,64})\\??/g, '{$1}')\n}\n\nfunction buildParameters(\n paramsSchema: z.ZodType | undefined,\n querySchema: z.ZodType | undefined,\n ctx: ConvertCtx,\n): OpenApiParameter[] {\n const out: OpenApiParameter[] = []\n if (paramsSchema !== undefined) {\n appendObjectAsParameters(paramsSchema, 'path', out, ctx)\n }\n if (querySchema !== undefined) {\n appendObjectAsParameters(querySchema, 'query', out, ctx)\n }\n return out\n}\n\nfunction appendObjectAsParameters(\n schema: z.ZodType,\n location: 'path' | 'query',\n out: OpenApiParameter[],\n ctx: ConvertCtx,\n): void {\n // We expect an object schema; if it's not, skip silently (caller already\n // validated upstream when scanning defineRoute()).\n const shape = (schema as unknown as { shape?: Record<string, z.ZodType> }).shape\n if (shape === undefined) return\n for (const [name, child] of Object.entries(shape)) {\n const childDef = (child as unknown as { _def: { typeName?: string } })._def\n const optional = childDef.typeName === 'ZodOptional' || childDef.typeName === 'ZodDefault'\n out.push({\n name,\n in: location,\n required: location === 'path' ? true : !optional,\n schema: zodToOpenApiSchema(child, { ctx }),\n })\n }\n}\n\nfunction buildOperation(\n route: OpenApiManifestRoute,\n ctx: ConvertCtx,\n method: string,\n): OpenApiOperation {\n // Bounded sanitizer: two single-pass replacements (no nested quantifiers).\n const sanitized = route.routePath.replace(/[/:\\-{}]/g, '_').replace(/_+/g, '_')\n const operationId = `${method.toLowerCase()}_${sanitized.replace(/^_|_$/g, '')}`\n const op: OpenApiOperation = {\n operationId,\n responses: {\n '200': { description: 'OK' },\n },\n }\n\n const parameters = buildParameters(route.params, route.query, ctx)\n if (parameters.length > 0) op.parameters = parameters\n\n // Body only meaningful for write methods; we still attach if defined so\n // the document is honest about the contract.\n if (route.body !== undefined) {\n op.requestBody = {\n required: true,\n content: {\n 'application/json': { schema: zodToOpenApiSchema(route.body, { ctx }) },\n },\n }\n }\n\n if (route.response !== undefined) {\n op.responses['200'] = {\n description: 'OK',\n content: {\n 'application/json': { schema: zodToOpenApiSchema(route.response, { ctx }) },\n },\n }\n }\n\n return op\n}\n\nexport function emitOpenApi(input: EmitOpenApiInput): EmitOpenApiResult {\n const { manifest, config } = input\n\n const ctx: ConvertCtx = { seen: new Map(), components: {} }\n\n const paths: Record<string, OpenApiPathItem> = {}\n for (const route of manifest) {\n const templatedPath = templatePath(route.routePath)\n const item: OpenApiPathItem = paths[templatedPath] ?? {}\n for (const method of route.methods) {\n // Defensive: manifest emitter normalizes to uppercase, but if a\n // future scanner produces a non-HTTP verb the key lookup yields\n // undefined and we skip silently. TS narrows the indexed type to\n // keyof OpenApiPathItem; the runtime undefined check is honest.\n const key = METHOD_TO_KEY[method.toUpperCase()] as keyof OpenApiPathItem | undefined\n if (key === undefined) continue\n item[key] = buildOperation(route, ctx, method)\n }\n paths[templatedPath] = item\n }\n\n const servers = applyServerOverride(config.servers)\n\n const document: OpenApiDocument = {\n openapi: config.specVersion,\n info: { title: config.title, version: config.version },\n servers,\n paths,\n }\n\n if (Object.keys(ctx.components).length > 0) {\n document.components = { schemas: ctx.components }\n }\n\n mkdirSync(config.outDir, { recursive: true })\n const outPath = join(config.outDir, 'openapi.json')\n writeFileSync(outPath, `${JSON.stringify(document, null, 2)}\\n`, 'utf8')\n\n return { document, path: outPath }\n}\n\nfunction applyServerOverride(\n servers: { url: string; description?: string }[],\n): { url: string; description?: string }[] {\n const override = process.env.THEOKIT_OPENAPI_SERVER_URL\n if (override === undefined || override === '') return servers\n if (servers.length === 0) return [{ url: override }]\n const [first, ...rest] = servers\n return [\n {\n url: override,\n ...(first.description !== undefined ? { description: first.description } : {}),\n },\n ...rest,\n ]\n}\n","/**\n * In-house Zod → OpenAPI 3.x Schema converter (build-time only).\n *\n * Per G2 plan v1.1 ADR D1 + EC-1: installed zod is 3.x (no native\n * `.toJSONSchema()`). This module is the PRIMARY conversion path.\n * Algorithm modelled on encore's `pkg/clientgen/openapi/schema.go`:\n * recursive descent + seen-map for cycle detection (named refs).\n *\n * Pure function: no I/O, no module loading. Caller extracts the Zod\n * schemas from `defineRoute({body, query, params})` and passes them\n * here. Returned `OpenApiSchema` is a structural subset of the OpenAPI\n * 3.0/3.1 Schema Object — fields populated as needed.\n *\n * NEVER ship to runtime — devDep-shaped artifact.\n *\n * Unsupported Zod constructs (z.function(), z.promise()) throw a\n * `ZodToOpenApiError` with a descriptive message so the caller can\n * surface the offending route + advise the user.\n */\nimport type { z } from 'zod'\n\nexport interface OpenApiSchema {\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object' | 'null'\n format?: string\n items?: OpenApiSchema\n properties?: Record<string, OpenApiSchema>\n required?: string[]\n additionalProperties?: boolean | OpenApiSchema\n oneOf?: OpenApiSchema[]\n anyOf?: OpenApiSchema[]\n allOf?: OpenApiSchema[]\n discriminator?: { propertyName: string; mapping?: Record<string, string> }\n enum?: unknown[]\n nullable?: boolean\n description?: string\n $ref?: string\n // OpenAPI 3.1 (JSON Schema 2020-12) allows `type: [..., 'null']`; for now\n // we stick with 3.0-compatible `nullable: true`. Caller can transform at\n // emit time if specVersion === '3.1.0'.\n}\n\nexport interface ConvertCtx {\n /** Seen-map: zod schema reference → component name (for $ref cycle detection). */\n seen: Map<z.ZodType, string>\n /** Output bucket for named component schemas. */\n components: Record<string, OpenApiSchema>\n}\n\nexport interface ConvertOptions {\n /**\n * Optional context carried across recursive calls. Pass the SAME ctx to\n * every `zodToOpenApiSchema` invocation in one emit pass so cycle\n * detection works across multiple routes.\n */\n ctx?: ConvertCtx\n /**\n * If provided, the schema is registered under `components.schemas[name]`\n * and the returned value is `{ $ref: '#/components/schemas/<name>' }`.\n * Use this for top-level recursive types where the consumer (e.g.,\n * OpenAPI document builder) wants named schemas instead of inlined ones.\n */\n name?: string\n}\n\nexport class ZodToOpenApiError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ZodToOpenApiError'\n }\n}\n\nexport function zodToOpenApiSchema(schema: z.ZodType, options: ConvertOptions = {}): OpenApiSchema {\n const ctx: ConvertCtx = options.ctx ?? { seen: new Map(), components: {} }\n\n const name = options.name\n if (name !== undefined) {\n // Top-level named schema — register placeholder BEFORE recursing, then\n // patch the slot with the computed body. This avoids infinite recursion\n // for self-referential types (encore schema.go:289 pattern).\n if (Object.prototype.hasOwnProperty.call(ctx.components, name)) {\n return { $ref: `#/components/schemas/${name}` }\n }\n ctx.seen.set(schema, name)\n ctx.components[name] = {} // placeholder\n const body = convert(schema, ctx)\n ctx.components[name] = body\n return { $ref: `#/components/schemas/${name}` }\n }\n\n return convert(schema, ctx)\n}\n\n// eslint-disable-next-line complexity -- switch-based dispatch on Zod typeName; splitting hides intent\nfunction convert(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n // Cycle: if we've seen this exact schema reference before, emit $ref.\n const existing = ctx.seen.get(schema)\n if (existing !== undefined) {\n return { $ref: `#/components/schemas/${existing}` }\n }\n\n const def = (schema as unknown as { _def: { typeName?: string } })._def\n const typeName = def.typeName ?? ''\n\n switch (typeName) {\n case 'ZodString':\n return convertString(schema)\n case 'ZodNumber':\n return convertNumber(schema)\n case 'ZodBoolean':\n return { type: 'boolean' }\n case 'ZodLiteral':\n return convertLiteral(schema)\n case 'ZodEnum':\n return convertEnum(schema)\n case 'ZodArray':\n return convertArray(schema, ctx)\n case 'ZodObject':\n return convertObject(schema, ctx)\n case 'ZodUnion':\n return convertUnion(schema, ctx)\n case 'ZodDiscriminatedUnion':\n return convertDiscriminatedUnion(schema, ctx)\n case 'ZodOptional':\n // Optional-as-property is handled at object level; here we unwrap.\n return convert((schema as unknown as { _def: { innerType: z.ZodType } })._def.innerType, ctx)\n case 'ZodNullable': {\n const inner = convert(\n (schema as unknown as { _def: { innerType: z.ZodType } })._def.innerType,\n ctx,\n )\n return { ...inner, nullable: true }\n }\n case 'ZodEffects':\n case 'ZodTransform':\n // Transforms change runtime output, but the WIRE shape is the input.\n return convert((schema as unknown as { _def: { schema: z.ZodType } })._def.schema, ctx)\n case 'ZodDefault':\n return convert((schema as unknown as { _def: { innerType: z.ZodType } })._def.innerType, ctx)\n case 'ZodLazy': {\n const getter = (schema as unknown as { _def: { getter: () => z.ZodType } })._def.getter\n return convert(getter(), ctx)\n }\n case 'ZodRecord': {\n const valueType = (schema as unknown as { _def: { valueType: z.ZodType } })._def.valueType\n return { type: 'object', additionalProperties: convert(valueType, ctx) }\n }\n case 'ZodAny':\n case 'ZodUnknown':\n return {} // no constraint\n case 'ZodNull':\n return { type: 'null' }\n case 'ZodFunction':\n throw new ZodToOpenApiError(\n 'Unsupported Zod type: z.function() cannot be represented in OpenAPI Schema. Remove from the route schema.',\n )\n case 'ZodPromise':\n throw new ZodToOpenApiError(\n 'Unsupported Zod type: z.promise() cannot be represented in OpenAPI Schema. Unwrap the value before passing to defineRoute.',\n )\n default:\n throw new ZodToOpenApiError(\n `Unsupported Zod type: ${typeName || '(unknown)'}. Open an issue if this construct should be supported.`,\n )\n }\n}\n\ninterface StringCheck {\n kind: string\n}\n\nfunction convertString(schema: z.ZodType): OpenApiSchema {\n const def = (schema as unknown as { _def: { checks?: StringCheck[] } })._def\n const checks = def.checks ?? []\n const out: OpenApiSchema = { type: 'string' }\n for (const c of checks) {\n if (c.kind === 'email') out.format = 'email'\n else if (c.kind === 'uuid') out.format = 'uuid'\n else if (c.kind === 'url') out.format = 'uri'\n else if (c.kind === 'datetime') out.format = 'date-time'\n }\n return out\n}\n\ninterface NumberCheck {\n kind: string\n}\n\nfunction convertNumber(schema: z.ZodType): OpenApiSchema {\n const def = (schema as unknown as { _def: { checks?: NumberCheck[] } })._def\n const checks = def.checks ?? []\n const isInt = checks.some((c) => c.kind === 'int')\n return { type: isInt ? 'integer' : 'number' }\n}\n\nfunction convertLiteral(schema: z.ZodType): OpenApiSchema {\n const value = (schema as unknown as { _def: { value: unknown } })._def.value\n const typed = literalTypeOf(value)\n if (typed === null) {\n // Null literal\n return { type: 'null', enum: [null] }\n }\n return { type: typed, enum: [value] }\n}\n\nfunction literalTypeOf(value: unknown): OpenApiSchema['type'] | null {\n if (value === null) return null\n if (typeof value === 'string') return 'string'\n if (typeof value === 'number') return Number.isInteger(value) ? 'integer' : 'number'\n if (typeof value === 'boolean') return 'boolean'\n return 'string' // fallback for symbol/etc.\n}\n\nfunction convertEnum(schema: z.ZodType): OpenApiSchema {\n const values = (schema as unknown as { _def: { values: readonly string[] } })._def.values\n return { type: 'string', enum: [...values] }\n}\n\nfunction convertArray(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const inner = (schema as unknown as { _def: { type: z.ZodType } })._def.type\n return { type: 'array', items: convert(inner, ctx) }\n}\n\nfunction convertObject(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const shape = (schema as unknown as { shape: Record<string, z.ZodType> }).shape\n const properties: Record<string, OpenApiSchema> = {}\n const required: string[] = []\n for (const [key, child] of Object.entries(shape)) {\n properties[key] = convert(child, ctx)\n const childDef = (child as unknown as { _def: { typeName?: string } })._def\n const isOptional = childDef.typeName === 'ZodOptional' || childDef.typeName === 'ZodDefault'\n if (!isOptional) required.push(key)\n }\n const out: OpenApiSchema = {\n type: 'object',\n properties,\n additionalProperties: false,\n }\n if (required.length > 0) out.required = required\n return out\n}\n\nfunction convertUnion(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const options = (schema as unknown as { _def: { options: z.ZodType[] } })._def.options\n return { oneOf: options.map((o) => convert(o, ctx)) }\n}\n\nfunction convertDiscriminatedUnion(schema: z.ZodType, ctx: ConvertCtx): OpenApiSchema {\n const def = (\n schema as unknown as {\n _def: { discriminator: string; options: z.ZodType[] }\n }\n )._def\n return {\n oneOf: def.options.map((o) => convert(o, ctx)),\n discriminator: { propertyName: def.discriminator },\n }\n}\n","/**\n * Build-time route loader for OpenAPI emit.\n *\n * Takes the G1 manifest (filePath + routePath + methods) and hydrates each\n * route's Zod schemas by dynamically importing the module. `defineRoute`\n * is an identity function, so the imported config exposes `body/query/\n * params/response` directly without any AST gymnastics.\n *\n * Supports both export shapes:\n * 1. `export const POST = defineRoute({...})` (per-method named exports)\n * 2. `export default defineRoute({...})` (single-export legacy shape)\n *\n * Per G2 plan v1.1 T2.2. Uses Vite's `ssrLoadModule` because route files\n * are TS at build time — Node's native loader doesn't transpile.\n */\nimport { resolve } from 'node:path'\n\nimport type { z } from 'zod'\n\nimport type { ManifestRoute } from '../../server/scan/manifest.js'\n\nimport type { OpenApiManifestRoute } from './emit.js'\n\ninterface RouteConfigShape {\n body?: z.ZodType\n query?: z.ZodType\n params?: z.ZodType\n response?: z.ZodType\n}\n\ninterface ViteLikeServer {\n ssrLoadModule: (id: string) => Promise<Record<string, unknown>>\n close: () => Promise<void>\n}\n\ninterface DefaultLoader {\n load: (absPath: string) => Promise<Record<string, unknown>>\n dispose: () => Promise<void>\n}\n\n/** Method names recognized as per-route named exports (UPPERCASE). */\nconst HTTP_METHOD_KEYS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const\n\nexport interface LoadRoutesOptions {\n serverDir: string\n routes: ManifestRoute[]\n /** Injectable for tests; defaults to a fresh Vite SSR dev server. */\n loadModule?: (absPath: string) => Promise<Record<string, unknown>>\n}\n\n/**\n * Hydrate manifest routes with Zod schemas extracted from their modules.\n *\n * Returns one `OpenApiManifestRoute` per (file × method) tuple. If a route\n * file declares multiple methods (`GET` + `POST`), each method gets its\n * own entry with the schemas from that method's `defineRoute()` call.\n *\n * Routes that fail to load are skipped with a console warning — the emit\n * should be best-effort, not a hard build failure.\n *\n * The default Vite loader is created once per call and disposed in the\n * `finally` block so the underlying server is released even when route\n * loading throws.\n */\nexport async function loadRoutesForOpenApi(\n options: LoadRoutesOptions,\n): Promise<OpenApiManifestRoute[]> {\n const { serverDir, routes } = options\n let loadModule = options.loadModule\n let dispose: (() => Promise<void>) | undefined\n if (loadModule === undefined) {\n const created = await createDefaultLoader(serverDir)\n loadModule = created.load\n dispose = created.dispose\n }\n\n const out: OpenApiManifestRoute[] = []\n try {\n for (const r of routes) {\n const abs = resolve(serverDir, r.filePath)\n let mod: Record<string, unknown>\n try {\n mod = await loadModule(abs)\n } catch (err) {\n console.warn(\n `[openapi-emit] Skipping ${r.filePath}: load failed (${(err as Error).message})`,\n )\n continue\n }\n\n const methods = r.methods ?? HTTP_METHOD_KEYS.filter((m) => mod[m] !== undefined)\n if (methods.length === 0) {\n // Fall back to default export when no method-named exports detected.\n const def = mod.default\n if (def !== undefined && def !== null) {\n out.push({ routePath: r.routePath, methods: ['GET'], ...extractSchemas(def) })\n }\n continue\n }\n\n for (const method of methods) {\n const handler = mod[method] ?? mod.default\n if (handler === undefined || handler === null) continue\n out.push({ routePath: r.routePath, methods: [method], ...extractSchemas(handler) })\n }\n }\n } finally {\n if (dispose !== undefined) {\n await dispose()\n }\n }\n return out\n}\n\nfunction extractSchemas(handlerExport: unknown): RouteConfigShape {\n if (typeof handlerExport !== 'object' || handlerExport === null) return {}\n const cfg = handlerExport as RouteConfigShape\n const out: RouteConfigShape = {}\n if (cfg.body !== undefined) out.body = cfg.body\n if (cfg.query !== undefined) out.query = cfg.query\n if (cfg.params !== undefined) out.params = cfg.params\n if (cfg.response !== undefined) out.response = cfg.response\n return out\n}\n\n/**\n * Default loader: spin up a minimal Vite SSR dev server (no HMR, no\n * middlewares) just to use its `ssrLoadModule`. Vite handles TS, ESM, and\n * import resolution for free.\n *\n * Returns `{load, dispose}` — the caller owns the lifecycle and MUST\n * call `dispose()` (typically in a `finally`) so the server is closed.\n */\nasync function createDefaultLoader(serverDir: string): Promise<DefaultLoader> {\n // Vite is a peerDep in build flows; import dynamically.\n const { createServer } = await import('vite')\n const server = (await createServer({\n root: serverDir,\n configFile: false,\n server: { middlewareMode: true },\n appType: 'custom',\n logLevel: 'silent',\n })) as unknown as ViteLikeServer\n\n const swallow = (): void => {\n /* eat close errors — best-effort cleanup */\n }\n return {\n load: async (absPath) => server.ssrLoadModule(absPath),\n dispose: async () => {\n await server.close().catch(swallow)\n },\n }\n}\n","/**\n * Dev-mode OpenAPI emit helper for `theokit dev`.\n *\n * Per P#3 plan v1.3 T1.1 (ADRs D3 + D4 + EC-8). Called once on `theokit dev`\n * boot AND on every chokidar 'change'/'add'/'unlink' watcher event for\n * route files when `config.openapi !== undefined`. Re-runs G2's\n * `emitOpenApi()` orchestrator to keep `<distDir>/openapi.json` always\n * fresh in dev.\n *\n * EC-8 absorbed (single-flight guard): if a previous invocation is still\n * awaiting `loadRoutesForOpenApi` (Vite SSR loader can hang on circular\n * imports or syntax errors), skip the new call and emit a `console.warn`\n * so watcher events don't pile up + dev server doesn't deadlock.\n *\n * Best-effort: ALL errors caught + warned. Never throws out of the\n * exported function (would crash Vite dev's chokidar handler).\n *\n * NEVER ship to runtime — dev-only artifact gated on `config.openapi`.\n */\nimport { generateManifest } from '../../server/scan/manifest.js'\n\nimport { emitOpenApi } from './emit.js'\nimport { loadRoutesForOpenApi } from './load-routes.js'\n\ninterface DevEmitConfig {\n servers: { url: string; description?: string }[]\n specVersion: '3.1.0' | '3.0.3'\n title: string\n version: string\n}\n\nlet inFlight = false\n\nexport async function reEmitOpenApi(\n serverDir: string,\n distDir: string,\n openApiConfig: DevEmitConfig,\n): Promise<void> {\n if (inFlight) {\n console.warn(\n '[openapi-emit] previous emit still running; skipping watcher event (EC-8 single-flight guard)',\n )\n return\n }\n inFlight = true\n try {\n const manifest = generateManifest(serverDir)\n const hydrated = await loadRoutesForOpenApi({ serverDir, routes: manifest.routes })\n emitOpenApi({\n manifest: hydrated,\n config: { ...openApiConfig, outDir: distDir },\n })\n } catch (err) {\n console.warn(`[openapi-emit] re-emit failed: ${(err as Error).message}`)\n } finally {\n inFlight = false\n }\n}\n\n/** Test seam — resets the inFlight flag between tests. NOT for production use. */\nexport function _resetInFlightForTests(): void {\n inFlight = false\n}\n"],"mappings":"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","names":[]}