theokit 0.43.7 → 0.43.12

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 (230) hide show
  1. package/dist/{actions-virtual-module-N7GKUS3D.js → actions-virtual-module-HG66SZ7T.js} +8 -8
  2. package/dist/actions-virtual-module-HG66SZ7T.js.map +1 -0
  3. package/dist/{actions-virtual-module-LD3YKWIX.js → actions-virtual-module-RSFRPJQZ.js} +7 -7
  4. package/dist/actions-virtual-module-RSFRPJQZ.js.map +1 -0
  5. package/dist/{add-W6FNTAFS.js → add-3VLFUPF4.js} +1 -1
  6. package/dist/add-3VLFUPF4.js.map +1 -0
  7. package/dist/{agent-U35G3WNE.js → agent-OXRRKB55.js} +5 -5
  8. package/dist/{agents-typed-client-NJ73Z6XY.js → agents-typed-client-X56CQ6FX.js} +1 -1
  9. package/dist/agents-typed-client-X56CQ6FX.js.map +1 -0
  10. package/dist/{agents-typed-client-CHMVW7MK.js → agents-typed-client-ZP7BKJB3.js} +1 -1
  11. package/dist/agents-typed-client-ZP7BKJB3.js.map +1 -0
  12. package/dist/{app-typed-client-6YZRDAPY.js → app-typed-client-GDF2OMJ2.js} +8 -8
  13. package/dist/app-typed-client-GDF2OMJ2.js.map +1 -0
  14. package/dist/{app-typed-client-V77SVU2O.js → app-typed-client-USLAMN7X.js} +7 -7
  15. package/dist/app-typed-client-USLAMN7X.js.map +1 -0
  16. package/dist/{aws-lambda-7GSCNLPY.js → aws-lambda-473QCOL6.js} +3 -3
  17. package/dist/{body-parser-web-MUWBKZ3F.js → body-parser-web-NNEJGX6Y.js} +1 -1
  18. package/dist/body-parser-web-NNEJGX6Y.js.map +1 -0
  19. package/dist/{body-parser-web-FV5HWCY3.js → body-parser-web-TIOTXPDW.js} +1 -1
  20. package/dist/body-parser-web-TIOTXPDW.js.map +1 -0
  21. package/dist/{build-BYLQZJT2.js → build-MQHIJROR.js} +11 -11
  22. package/dist/{build-BYLQZJT2.js.map → build-MQHIJROR.js.map} +1 -1
  23. package/dist/{build-request-body-preview-EOP2Y4F3.js → build-request-body-preview-FVBQ7LCE.js} +1 -1
  24. package/dist/build-request-body-preview-FVBQ7LCE.js.map +1 -0
  25. package/dist/{build-request-body-preview-QMWD2IXK.js → build-request-body-preview-XPZ2GYMG.js} +1 -1
  26. package/dist/build-request-body-preview-XPZ2GYMG.js.map +1 -0
  27. package/dist/{bun-KP2KES6S.js → bun-OQUCL3XW.js} +3 -3
  28. package/dist/{check-PD2FTKMM.js → check-45NKUVSQ.js} +1 -1
  29. package/dist/check-45NKUVSQ.js.map +1 -0
  30. package/dist/{chunk-FRUEDJFX.js → chunk-226KMIGZ.js} +3 -3
  31. package/dist/{chunk-FRUEDJFX.js.map → chunk-226KMIGZ.js.map} +1 -1
  32. package/dist/{chunk-U3NTEK46.js → chunk-26ECIX74.js} +2 -2
  33. package/dist/{chunk-FEDSPOY6.js → chunk-2WH6SD3C.js} +6 -6
  34. package/dist/chunk-2WH6SD3C.js.map +1 -0
  35. package/dist/{chunk-JAIKGP3Q.js → chunk-47VNWTL4.js} +1 -1
  36. package/dist/chunk-47VNWTL4.js.map +1 -0
  37. package/dist/{chunk-D7ZH7DTG.js → chunk-4B2ZMX45.js} +1 -1
  38. package/dist/chunk-4B2ZMX45.js.map +1 -0
  39. package/dist/{chunk-IHJZPQEF.js → chunk-4HAU7AJM.js} +3 -3
  40. package/dist/chunk-4HAU7AJM.js.map +1 -0
  41. package/dist/{chunk-IPC5UREF.js → chunk-575PAX5L.js} +17 -17
  42. package/dist/chunk-575PAX5L.js.map +1 -0
  43. package/dist/{chunk-X2VVCJ4V.js → chunk-65EFIUDD.js} +1 -1
  44. package/dist/chunk-65EFIUDD.js.map +1 -0
  45. package/dist/{chunk-GY5Q27BJ.js → chunk-6FK7FKY6.js} +1 -1
  46. package/dist/{chunk-GY5Q27BJ.js.map → chunk-6FK7FKY6.js.map} +1 -1
  47. package/dist/{chunk-GSO77FSM.js → chunk-6OXCZMW3.js} +45 -47
  48. package/dist/chunk-6OXCZMW3.js.map +1 -0
  49. package/dist/{chunk-P37RZRFV.js → chunk-A7JBF5FO.js} +1 -1
  50. package/dist/chunk-A7JBF5FO.js.map +1 -0
  51. package/dist/{chunk-AFVTEAES.js → chunk-CJNMJUHE.js} +2 -2
  52. package/dist/{chunk-AXVFVMLM.js → chunk-DJFMAWH5.js} +8 -4
  53. package/dist/chunk-DJFMAWH5.js.map +1 -0
  54. package/dist/{chunk-2ZX4J4SX.js → chunk-DQVBL2G4.js} +58 -56
  55. package/dist/chunk-DQVBL2G4.js.map +1 -0
  56. package/dist/{chunk-GW5H4KB4.js → chunk-FX72VHAE.js} +3 -3
  57. package/dist/{chunk-5AVPWHUE.js → chunk-HGUZWG2C.js} +7 -4
  58. package/dist/chunk-HGUZWG2C.js.map +1 -0
  59. package/dist/{chunk-UNLG36Z5.js → chunk-IE6C4KZX.js} +10 -5
  60. package/dist/chunk-IE6C4KZX.js.map +1 -0
  61. package/dist/{chunk-QWBXUZAX.js → chunk-JIL74SFK.js} +4 -4
  62. package/dist/chunk-JIL74SFK.js.map +1 -0
  63. package/dist/{chunk-KI7OWQUX.js → chunk-L2S2R3TI.js} +63 -20
  64. package/dist/chunk-L2S2R3TI.js.map +1 -0
  65. package/dist/{chunk-L4GCEMNW.js → chunk-LNVMHQ2Z.js} +2 -2
  66. package/dist/{chunk-SPJNVWOK.js → chunk-N2D5AVRR.js} +2 -3
  67. package/dist/chunk-N2D5AVRR.js.map +1 -0
  68. package/dist/{chunk-UO7WS32S.js → chunk-OI6DK6ZJ.js} +3 -3
  69. package/dist/chunk-OI6DK6ZJ.js.map +1 -0
  70. package/dist/{chunk-RMU7EBRO.js → chunk-OP7QCTR5.js} +2 -2
  71. package/dist/{chunk-RMU7EBRO.js.map → chunk-OP7QCTR5.js.map} +1 -1
  72. package/dist/{chunk-GUUWDMR2.js → chunk-OVHW23YC.js} +2 -2
  73. package/dist/{chunk-NQRNDPZJ.js → chunk-OXCALO3W.js} +3 -3
  74. package/dist/{chunk-45C3WUQ7.js → chunk-QPVXGC7O.js} +1 -1
  75. package/dist/chunk-QPVXGC7O.js.map +1 -0
  76. package/dist/{chunk-FOZIR3TG.js → chunk-SMP2T335.js} +2 -2
  77. package/dist/{chunk-M6NMS5LR.js → chunk-TDNNBLGW.js} +1 -1
  78. package/dist/chunk-TDNNBLGW.js.map +1 -0
  79. package/dist/{chunk-WFNLNIJX.js → chunk-VPISAMXU.js} +2 -2
  80. package/dist/{chunk-5PU65T5W.js → chunk-XZ6B2Y2R.js} +1 -1
  81. package/dist/chunk-XZ6B2Y2R.js.map +1 -0
  82. package/dist/cli/index.js +15 -15
  83. package/dist/client/index.d.ts +1 -1
  84. package/dist/client/index.js +20 -25
  85. package/dist/client/index.js.map +1 -1
  86. package/dist/{cloudflare-C6E5SPAE.js → cloudflare-4YT5CK3P.js} +3 -3
  87. package/dist/{controller-swc-transform-URELVCBM.js → controller-swc-transform-JJRMTSDY.js} +1 -1
  88. package/dist/controller-swc-transform-JJRMTSDY.js.map +1 -0
  89. package/dist/{controller-swc-transform-XV3ETSE3.js → controller-swc-transform-LUJ4VAZJ.js} +1 -1
  90. package/dist/controller-swc-transform-LUJ4VAZJ.js.map +1 -0
  91. package/dist/{db-3UNAMSFK.js → db-IVVCQE5Z.js} +1 -2
  92. package/dist/db-IVVCQE5Z.js.map +1 -0
  93. package/dist/{deno-deploy-RFZN56X4.js → deno-deploy-YYN6BNLF.js} +3 -3
  94. package/dist/{dev-PS2NGT6I.js → dev-WQ4LWCAW.js} +13 -13
  95. package/dist/{dev-emit-2DL3MCLM.js → dev-emit-HLGJK3PP.js} +3 -3
  96. package/dist/dev-emit-HLGJK3PP.js.map +1 -0
  97. package/dist/{dev-emit-XVTJXZGA.js → dev-emit-J7V6GWSK.js} +6 -6
  98. package/dist/devtools/entry.js +43 -15
  99. package/dist/devtools/entry.js.map +1 -1
  100. package/dist/{dispatcher-63LBXYLE.js → dispatcher-DLKIXYNO.js} +2 -2
  101. package/dist/{dispatcher-EJHL6JMJ.js → dispatcher-KMZBGMM5.js} +1 -1
  102. package/dist/dispatcher-KMZBGMM5.js.map +1 -0
  103. package/dist/{generate-5X4LG77M.js → generate-GXWPUVS7.js} +4 -5
  104. package/dist/generate-GXWPUVS7.js.map +1 -0
  105. package/dist/index.js +9 -9
  106. package/dist/{info-2OOXFTJX.js → info-75U6GCMD.js} +4 -4
  107. package/dist/info-75U6GCMD.js.map +1 -0
  108. package/dist/{internal-api-LFW7R65K.js → internal-api-DV3H5NNV.js} +7 -9
  109. package/dist/{internal-api-FBFV265J.js → internal-api-JFORKYLR.js} +8 -10
  110. package/dist/{load-config-3EAQTXPH.js → load-config-XP7NSSA7.js} +4 -4
  111. package/dist/{mcp-ML4QK5ON.js → mcp-FF3NTCHB.js} +6 -6
  112. package/dist/mcp-FF3NTCHB.js.map +1 -0
  113. package/dist/{netlify-PMLHVPN4.js → netlify-2WZUQYI3.js} +3 -3
  114. package/dist/node-CMAYKDCM.js +10 -0
  115. package/dist/{openapi-2HVGJMSN.js → openapi-ZPXYRAM2.js} +9 -9
  116. package/dist/openapi-ZPXYRAM2.js.map +1 -0
  117. package/dist/registry-72YH7ZJM.js +23 -0
  118. package/dist/registry-72YH7ZJM.js.map +1 -0
  119. package/dist/{router-TLEAOFID.js → router-6MAACS25.js} +1 -2
  120. package/dist/router-6MAACS25.js.map +1 -0
  121. package/dist/{routes-XNS3UM3B.js → routes-ZVDKABXZ.js} +6 -6
  122. package/dist/schema-FBOTN46F.js +22 -0
  123. package/dist/server/agent/index.js +1 -1
  124. package/dist/server/cost/index.js +1 -1
  125. package/dist/server/cron/index.js +2 -2
  126. package/dist/server/http/index.js +3 -3
  127. package/dist/server/index.js +11 -11
  128. package/dist/server/jobs/index.js +3 -3
  129. package/dist/server/observability/index.d.ts +1 -38
  130. package/dist/server/observability/index.js +2 -2
  131. package/dist/server/scan/index.js +2 -2
  132. package/dist/{server-routes-hmr-VZXOP5YT.js → server-routes-hmr-4W5L2MKN.js} +1 -1
  133. package/dist/server-routes-hmr-4W5L2MKN.js.map +1 -0
  134. package/dist/{server-routes-hmr-PBHSKCQJ.js → server-routes-hmr-RI7SYNT2.js} +1 -1
  135. package/dist/server-routes-hmr-RI7SYNT2.js.map +1 -0
  136. package/dist/{services-json-Y3XODNB5.js → services-json-7ZXJ4CIS.js} +1 -1
  137. package/dist/services-json-7ZXJ4CIS.js.map +1 -0
  138. package/dist/{services-typed-client-IETY2SAK.js → services-typed-client-AU6DKXAO.js} +2 -2
  139. package/dist/services-typed-client-AU6DKXAO.js.map +1 -0
  140. package/dist/{services-typed-client-32KMTTXR.js → services-typed-client-EO4RFNTZ.js} +2 -2
  141. package/dist/services-typed-client-EO4RFNTZ.js.map +1 -0
  142. package/dist/{start-YLR2SFHU.js → start-2U3FUCJX.js} +12 -12
  143. package/dist/start-2U3FUCJX.js.map +1 -0
  144. package/dist/{static-MB2CD5Y3.js → static-25H5K42R.js} +3 -3
  145. package/dist/{static-MB2CD5Y3.js.map → static-25H5K42R.js.map} +1 -1
  146. package/dist/{theo-cloud-DQRP6S6M.js → theo-cloud-JL2KXHIS.js} +2 -2
  147. package/dist/{upgrade-readiness-ACGW44JC.js → upgrade-readiness-77P6VNB4.js} +1 -1
  148. package/dist/upgrade-readiness-77P6VNB4.js.map +1 -0
  149. package/dist/{vercel-J6G7ZHYQ.js → vercel-FP3C6LN6.js} +3 -3
  150. package/dist/vite-plugin/index.js +9 -9
  151. package/dist/{vite-plugin-6VVU6PPC.js → vite-plugin-D2NTPZNC.js} +13 -13
  152. package/package.json +4 -7
  153. package/dist/actions-virtual-module-LD3YKWIX.js.map +0 -1
  154. package/dist/actions-virtual-module-N7GKUS3D.js.map +0 -1
  155. package/dist/add-W6FNTAFS.js.map +0 -1
  156. package/dist/agents-typed-client-CHMVW7MK.js.map +0 -1
  157. package/dist/agents-typed-client-NJ73Z6XY.js.map +0 -1
  158. package/dist/app-typed-client-6YZRDAPY.js.map +0 -1
  159. package/dist/app-typed-client-V77SVU2O.js.map +0 -1
  160. package/dist/body-parser-web-FV5HWCY3.js.map +0 -1
  161. package/dist/body-parser-web-MUWBKZ3F.js.map +0 -1
  162. package/dist/build-request-body-preview-EOP2Y4F3.js.map +0 -1
  163. package/dist/build-request-body-preview-QMWD2IXK.js.map +0 -1
  164. package/dist/check-PD2FTKMM.js.map +0 -1
  165. package/dist/chunk-2ZX4J4SX.js.map +0 -1
  166. package/dist/chunk-45C3WUQ7.js.map +0 -1
  167. package/dist/chunk-5AVPWHUE.js.map +0 -1
  168. package/dist/chunk-5PU65T5W.js.map +0 -1
  169. package/dist/chunk-AXVFVMLM.js.map +0 -1
  170. package/dist/chunk-D7ZH7DTG.js.map +0 -1
  171. package/dist/chunk-FEDSPOY6.js.map +0 -1
  172. package/dist/chunk-GSO77FSM.js.map +0 -1
  173. package/dist/chunk-IHJZPQEF.js.map +0 -1
  174. package/dist/chunk-IPC5UREF.js.map +0 -1
  175. package/dist/chunk-JAIKGP3Q.js.map +0 -1
  176. package/dist/chunk-KI7OWQUX.js.map +0 -1
  177. package/dist/chunk-M6NMS5LR.js.map +0 -1
  178. package/dist/chunk-P37RZRFV.js.map +0 -1
  179. package/dist/chunk-QWBXUZAX.js.map +0 -1
  180. package/dist/chunk-SPJNVWOK.js.map +0 -1
  181. package/dist/chunk-UNLG36Z5.js.map +0 -1
  182. package/dist/chunk-UO7WS32S.js.map +0 -1
  183. package/dist/chunk-X2VVCJ4V.js.map +0 -1
  184. package/dist/controller-swc-transform-URELVCBM.js.map +0 -1
  185. package/dist/controller-swc-transform-XV3ETSE3.js.map +0 -1
  186. package/dist/db-3UNAMSFK.js.map +0 -1
  187. package/dist/dev-emit-2DL3MCLM.js.map +0 -1
  188. package/dist/dispatcher-EJHL6JMJ.js.map +0 -1
  189. package/dist/generate-5X4LG77M.js.map +0 -1
  190. package/dist/info-2OOXFTJX.js.map +0 -1
  191. package/dist/mcp-ML4QK5ON.js.map +0 -1
  192. package/dist/node-BPJ3Z4DT.js +0 -10
  193. package/dist/openapi-2HVGJMSN.js.map +0 -1
  194. package/dist/registry-FKPH7XEL.js +0 -24
  195. package/dist/registry-FKPH7XEL.js.map +0 -1
  196. package/dist/router-TLEAOFID.js.map +0 -1
  197. package/dist/schema-LYOLNHZ7.js +0 -30
  198. package/dist/server-routes-hmr-PBHSKCQJ.js.map +0 -1
  199. package/dist/server-routes-hmr-VZXOP5YT.js.map +0 -1
  200. package/dist/services-json-Y3XODNB5.js.map +0 -1
  201. package/dist/services-typed-client-32KMTTXR.js.map +0 -1
  202. package/dist/services-typed-client-IETY2SAK.js.map +0 -1
  203. package/dist/start-YLR2SFHU.js.map +0 -1
  204. package/dist/upgrade-readiness-ACGW44JC.js.map +0 -1
  205. /package/dist/{agent-U35G3WNE.js.map → agent-OXRRKB55.js.map} +0 -0
  206. /package/dist/{aws-lambda-7GSCNLPY.js.map → aws-lambda-473QCOL6.js.map} +0 -0
  207. /package/dist/{bun-KP2KES6S.js.map → bun-OQUCL3XW.js.map} +0 -0
  208. /package/dist/{chunk-U3NTEK46.js.map → chunk-26ECIX74.js.map} +0 -0
  209. /package/dist/{chunk-AFVTEAES.js.map → chunk-CJNMJUHE.js.map} +0 -0
  210. /package/dist/{chunk-GW5H4KB4.js.map → chunk-FX72VHAE.js.map} +0 -0
  211. /package/dist/{chunk-L4GCEMNW.js.map → chunk-LNVMHQ2Z.js.map} +0 -0
  212. /package/dist/{chunk-GUUWDMR2.js.map → chunk-OVHW23YC.js.map} +0 -0
  213. /package/dist/{chunk-NQRNDPZJ.js.map → chunk-OXCALO3W.js.map} +0 -0
  214. /package/dist/{chunk-FOZIR3TG.js.map → chunk-SMP2T335.js.map} +0 -0
  215. /package/dist/{chunk-WFNLNIJX.js.map → chunk-VPISAMXU.js.map} +0 -0
  216. /package/dist/{cloudflare-C6E5SPAE.js.map → cloudflare-4YT5CK3P.js.map} +0 -0
  217. /package/dist/{deno-deploy-RFZN56X4.js.map → deno-deploy-YYN6BNLF.js.map} +0 -0
  218. /package/dist/{dev-PS2NGT6I.js.map → dev-WQ4LWCAW.js.map} +0 -0
  219. /package/dist/{dev-emit-XVTJXZGA.js.map → dev-emit-J7V6GWSK.js.map} +0 -0
  220. /package/dist/{dispatcher-63LBXYLE.js.map → dispatcher-DLKIXYNO.js.map} +0 -0
  221. /package/dist/{internal-api-FBFV265J.js.map → internal-api-DV3H5NNV.js.map} +0 -0
  222. /package/dist/{internal-api-LFW7R65K.js.map → internal-api-JFORKYLR.js.map} +0 -0
  223. /package/dist/{load-config-3EAQTXPH.js.map → load-config-XP7NSSA7.js.map} +0 -0
  224. /package/dist/{netlify-PMLHVPN4.js.map → netlify-2WZUQYI3.js.map} +0 -0
  225. /package/dist/{node-BPJ3Z4DT.js.map → node-CMAYKDCM.js.map} +0 -0
  226. /package/dist/{routes-XNS3UM3B.js.map → routes-ZVDKABXZ.js.map} +0 -0
  227. /package/dist/{schema-LYOLNHZ7.js.map → schema-FBOTN46F.js.map} +0 -0
  228. /package/dist/{theo-cloud-DQRP6S6M.js.map → theo-cloud-JL2KXHIS.js.map} +0 -0
  229. /package/dist/{vercel-J6G7ZHYQ.js.map → vercel-FP3C6LN6.js.map} +0 -0
  230. /package/dist/{vite-plugin-6VVU6PPC.js.map → vite-plugin-D2NTPZNC.js.map} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  generateCaddyfile,
5
5
  generateComposeYaml,
6
6
  readManifest
7
- } from "./chunk-45C3WUQ7.js";
7
+ } from "./chunk-QPVXGC7O.js";
8
8
 
9
9
  // src/adapters/node.ts
10
10
  import { writeFileSync } from "fs";
@@ -62,4 +62,4 @@ var nodeAdapter = {
62
62
  export {
63
63
  nodeAdapter
64
64
  };
65
- //# sourceMappingURL=chunk-FOZIR3TG.js.map
65
+ //# sourceMappingURL=chunk-SMP2T335.js.map
@@ -88,4 +88,4 @@ export {
88
88
  getApprovalRegistry,
89
89
  resolveProvider
90
90
  };
91
- //# sourceMappingURL=chunk-M6NMS5LR.js.map
91
+ //# sourceMappingURL=chunk-TDNNBLGW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/agent/provider-resolver.ts","../src/server/agent/approval-registry.ts"],"sourcesContent":["/**\n * Provider Resolver — Strategy + Registry pattern (FAANG-grade).\n *\n * Inspiração: Dapr Conversation Registry (`dapr/pkg/components/conversation/registry.go`)\n * + Encore Manager provider array (`encore/runtimes/go/pubsub/manager_internal.go`).\n *\n * Princípio: provider routing é responsabilidade do FRAMEWORK, não do consumer.\n * Consumer template usa `model: { id: 'gpt-4o-mini' }` puro — sem conditionals.\n *\n * Wire protocol: OpenAI Chat Completions (universal — implementado por todos\n * os providers: OpenRouter, Groq, Mistral, Together, Anthropic via proxy, etc).\n *\n * Resolução por prioridade (FIRST match wins):\n * 1. OPENROUTER_API_KEY → baseUrl=openrouter.ai (gateway multi-modelo)\n * 2. OPENAI_API_KEY → baseUrl=api.openai.com\n * 3. ANTHROPIC_API_KEY → direct Anthropic (Messages API, não OpenAI-compat)\n *\n * Escape hatch: `options.apiKey` explícito SOBREPÕE auto-resolution\n * (consumer pode forçar provider específico se quiser).\n */\n\n/**\n * Provider configuration descriptor — Registry entry shape.\n *\n * @public\n */\nexport interface ProviderDescriptor {\n /** Stable name used internally — não exposto no wire. */\n name: string\n /** Environment variable that holds the API key for this provider. */\n envKey: string\n /** Base URL for the provider's OpenAI-compatible (or native) API. */\n baseUrl: string\n /** Resolution priority (lower = higher priority). FIRST match wins. */\n priority: number\n}\n\n/**\n * Resolved provider configuration — output of `resolveProvider()`.\n *\n * @public\n */\nexport interface ResolvedProvider {\n name: string\n apiKey: string\n baseUrl: string\n}\n\n/**\n * Default provider registry. Order = priority (first = highest).\n *\n * Adding a new provider:\n * 1. Append entry below (or register via `registerProvider()`).\n * 2. Set `envKey` matching the user's env var convention.\n * 3. Set `baseUrl` to the OpenAI-compat endpoint (or native if not compat).\n * 4. Provider name used in telemetry/logs only — never wire-exposed.\n */\nconst DEFAULT_REGISTRY: ProviderDescriptor[] = [\n {\n name: 'openrouter',\n envKey: 'OPENROUTER_API_KEY',\n baseUrl: 'https://openrouter.ai/api/v1',\n priority: 1,\n },\n {\n name: 'openai',\n envKey: 'OPENAI_API_KEY',\n baseUrl: 'https://api.openai.com/v1',\n priority: 2,\n },\n {\n name: 'anthropic',\n envKey: 'ANTHROPIC_API_KEY',\n baseUrl: 'https://api.anthropic.com',\n priority: 3,\n },\n]\n\n/**\n * Runtime registry — copy of DEFAULT_REGISTRY mutable via registerProvider().\n * Sorted by priority on every resolve (stable, O(n log n) — n <= ~10 providers).\n */\nconst registry: ProviderDescriptor[] = [...DEFAULT_REGISTRY]\n\n/**\n * Register a new provider (Registry pattern — runtime extension point).\n * Useful for self-hosted endpoints or custom providers without touching theokit src.\n *\n * @example\n * registerProvider({\n * name: 'self-hosted',\n * envKey: 'SELF_HOSTED_API_KEY',\n * baseUrl: 'https://llm.internal.acme.com/v1',\n * priority: 0, // highest priority\n * })\n *\n * @public\n */\nexport function registerProvider(descriptor: ProviderDescriptor): void {\n // Idempotent — replace existing by name.\n const idx = registry.findIndex((p) => p.name === descriptor.name)\n if (idx >= 0) registry[idx] = descriptor\n else registry.push(descriptor)\n}\n\n/**\n * Reset registry to DEFAULT_REGISTRY (test-only / dev escape hatch).\n *\n * @public\n */\nexport function resetProviderRegistry(): void {\n registry.length = 0\n registry.push(...DEFAULT_REGISTRY)\n}\n\n/**\n * Get current registry snapshot (read-only — inspection).\n *\n * @public\n */\nexport function listProviders(): readonly ProviderDescriptor[] {\n return [...registry].sort((a, b) => a.priority - b.priority)\n}\n\n/**\n * Resolve provider from env vars by priority. FIRST env var found wins.\n *\n * @returns ResolvedProvider with apiKey + baseUrl + name\n * @throws Error if NO provider env var is set (actionable message)\n *\n * @public\n */\nexport function resolveProvider(): ResolvedProvider {\n const sorted = [...registry].sort((a, b) => a.priority - b.priority)\n for (const desc of sorted) {\n const apiKey = process.env[desc.envKey]\n if (apiKey && apiKey.length > 0) {\n return {\n name: desc.name,\n apiKey,\n baseUrl: desc.baseUrl,\n }\n }\n }\n // No env var found — emit actionable error.\n const envKeys = sorted.map((p) => p.envKey).join(' OR ')\n throw new Error(\n `No LLM provider API key found in environment. Set one of: ${envKeys}. ` +\n `Get a free OpenRouter key at https://openrouter.ai/keys (recommended — one key, many models).`,\n )\n}\n\n/**\n * Try to resolve — does NOT throw. Returns null if no provider available.\n * Useful for graceful degradation (e.g., mock mode).\n *\n * @public\n */\nexport function tryResolveProvider(): ResolvedProvider | null {\n try {\n return resolveProvider()\n } catch {\n return null\n }\n}\n","/**\n * M4 (theokit-ai-first) — the in-process HITL approval registry.\n *\n * The HITL plugin's `awaitApproval` calls `register(approvalId)` and awaits the returned Promise\n * (this is what genuinely PAUSES the SDK run — the SDK `pre_tool_call` hook is awaited). The\n * approve route calls `resolve(approvalId, approved)` to settle it. A per-approval timeout settles\n * the Promise deterministically per the `@HumanInTheLoop` `onTimeout` policy so a hung approval\n * never leaks the paused stream.\n *\n * Single-process contract (ADR 0038 / plan Drawback 2): a multi-instance deploy needs a shared\n * registry — the interface is injectable so a durable impl (Redis, etc.) slots in without touching\n * the harness. We do NOT build a durable store now (YAGNI).\n */\n// The timeout policy vocabulary is owned by the `@HumanInTheLoop` decorator (DRY / G12) — reuse it\n// rather than re-declaring the union, so the two can never drift.\nimport type { TimeoutAction } from '@theokit/agents'\n\nexport interface RegisterOptions {\n /** Milliseconds before the approval auto-settles per `onTimeout`. */\n timeoutMs: number\n /**\n * What a timeout means. Only `'proceed'` auto-approves; `'abort'` and `'retry'` both deny — the\n * registry does NOT implement retry semantics (a timed-out `'retry'` is a deny, not a re-prompt).\n */\n onTimeout: TimeoutAction\n /** M14 — the gated tool name, surfaced by `list()` (optional; absent for legacy callers). */\n toolName?: string\n /** M14 — the approval question, surfaced by `list()` (optional). */\n question?: string\n /**\n * M20 — an optional JSON-schema descriptor of the custom payload the approver may attach. Carried\n * verbatim into `list()` + the `approval_required` event so the UI knows what to collect. Kept as\n * a plain JSON object (not a live Zod schema) so the registry stays serializable and SDK-free.\n */\n payloadSchema?: Record<string, unknown>\n}\n\n/**\n * M20 — a settled HITL decision. `approved` is the allow/deny bit (backward-compatible with the\n * legacy boolean); `reason` + `payload` are the optional approver-attached extras that surface to\n * the model (on denial, via the veto message) and to the app/UI.\n */\nexport interface ApprovalDecision {\n approved: boolean\n reason?: string\n payload?: unknown\n}\n\n/** M14 — a pending approval as surfaced by {@link ApprovalRegistry.list}. */\nexport interface PendingApproval {\n approvalId: string\n toolName?: string\n question?: string\n /** Epoch millis when the pending approval auto-settles (registeredAt + timeoutMs). */\n expiresAt: number\n /** M20 — the declared custom-payload schema, if the gated tool declares one. */\n payloadSchema?: Record<string, unknown>\n}\n\nexport interface ApprovalRegistry {\n /**\n * Register a pending approval; the returned Promise settles with the full {@link ApprovalDecision}\n * on `resolve` or timeout (M20 — was a bare boolean pre-M20).\n */\n register(approvalId: string, opts: RegisterOptions): Promise<ApprovalDecision>\n /**\n * Settle a pending approval. Accepts a full {@link ApprovalDecision} OR a bare boolean (coerced to\n * `{ approved }` — backward-compatible). Returns false if the id is unknown or already settled.\n */\n resolve(approvalId: string, decision: boolean | ApprovalDecision): boolean\n /** M14 — list the currently-pending approvals (process-wide; single-process contract). */\n list(): PendingApproval[]\n}\n\ninterface Pending {\n settle: (decision: ApprovalDecision) => void\n timer: ReturnType<typeof setTimeout>\n info: PendingApproval\n}\n\n/**\n * The one process-wide registry the stream mount (`mountAgent`) and the approve route share.\n *\n * The in-process impl holds LIVE Promise resolvers in memory — the approval a request awaits and\n * the approval the route resolves MUST be the same object, so a single instance per process is not\n * a convenience but a correctness requirement. Lazily created; a durable/multi-instance deploy\n * swaps this accessor for a shared-store impl (ADR 0038 / plan Drawback 2) without touching callers.\n * Tests use {@link createInProcessApprovalRegistry} directly — never this singleton.\n */\nlet serverRegistry: ApprovalRegistry | undefined\nexport function getApprovalRegistry(): ApprovalRegistry {\n serverRegistry ??= createInProcessApprovalRegistry()\n return serverRegistry\n}\n\nexport function createInProcessApprovalRegistry(): ApprovalRegistry {\n const pending = new Map<string, Pending>()\n\n return {\n register(approvalId, opts) {\n return new Promise<ApprovalDecision>((resolve) => {\n const settle = (decision: ApprovalDecision): void => {\n const entry = pending.get(approvalId)\n if (!entry) return\n clearTimeout(entry.timer)\n pending.delete(approvalId)\n resolve(decision)\n }\n // 'proceed' → allow on timeout; 'abort'/'retry' → deny on timeout.\n const timer = setTimeout(() => {\n settle({ approved: opts.onTimeout === 'proceed' })\n }, opts.timeoutMs)\n const info: PendingApproval = {\n approvalId,\n toolName: opts.toolName,\n question: opts.question,\n expiresAt: Date.now() + opts.timeoutMs,\n ...(opts.payloadSchema !== undefined ? { payloadSchema: opts.payloadSchema } : {}),\n }\n pending.set(approvalId, { settle, timer, info })\n })\n },\n resolve(approvalId, decision) {\n const entry = pending.get(approvalId)\n if (!entry) return false\n // M20 — coerce the legacy bare-boolean form to a decision object.\n entry.settle(typeof decision === 'boolean' ? { approved: decision } : decision)\n return true\n },\n list() {\n return [...pending.values()].map((p) => p.info)\n },\n }\n}\n"],"mappings":";;;;AAyDA,IAAM,mBAAyC;AAAA,EAC7C;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AACF;AAMA,IAAM,WAAiC,CAAC,GAAG,gBAAgB;AAkDpD,SAAS,kBAAoC;AAClD,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AACnE,aAAW,QAAQ,QAAQ;AACzB,UAAM,SAAS,QAAQ,IAAI,KAAK,MAAM;AACtC,QAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,aAAO;AAAA,QACL,MAAM,KAAK;AAAA,QACX;AAAA,QACA,SAAS,KAAK;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,MAAM;AACvD,QAAM,IAAI;AAAA,IACR,6DAA6D,OAAO;AAAA,EAEtE;AACF;;;AC7DA,IAAI;AACG,SAAS,sBAAwC;AACtD,qBAAmB,gCAAgC;AACnD,SAAO;AACT;AAEO,SAAS,kCAAoD;AAClE,QAAM,UAAU,oBAAI,IAAqB;AAEzC,SAAO;AAAA,IACL,SAAS,YAAY,MAAM;AACzB,aAAO,IAAI,QAA0B,CAAC,YAAY;AAChD,cAAM,SAAS,CAAC,aAAqC;AACnD,gBAAM,QAAQ,QAAQ,IAAI,UAAU;AACpC,cAAI,CAAC,MAAO;AACZ,uBAAa,MAAM,KAAK;AACxB,kBAAQ,OAAO,UAAU;AACzB,kBAAQ,QAAQ;AAAA,QAClB;AAEA,cAAM,QAAQ,WAAW,MAAM;AAC7B,iBAAO,EAAE,UAAU,KAAK,cAAc,UAAU,CAAC;AAAA,QACnD,GAAG,KAAK,SAAS;AACjB,cAAM,OAAwB;AAAA,UAC5B;AAAA,UACA,UAAU,KAAK;AAAA,UACf,UAAU,KAAK;AAAA,UACf,WAAW,KAAK,IAAI,IAAI,KAAK;AAAA,UAC7B,GAAI,KAAK,kBAAkB,SAAY,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;AAAA,QAClF;AACA,gBAAQ,IAAI,YAAY,EAAE,QAAQ,OAAO,KAAK,CAAC;AAAA,MACjD,CAAC;AAAA,IACH;AAAA,IACA,QAAQ,YAAY,UAAU;AAC5B,YAAM,QAAQ,QAAQ,IAAI,UAAU;AACpC,UAAI,CAAC,MAAO,QAAO;AAEnB,YAAM,OAAO,OAAO,aAAa,YAAY,EAAE,UAAU,SAAS,IAAI,QAAQ;AAC9E,aAAO;AAAA,IACT;AAAA,IACA,OAAO;AACL,aAAO,CAAC,GAAG,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,IAChD;AAAA,EACF;AACF;","names":[]}
@@ -179,7 +179,7 @@ function randomRequestId() {
179
179
  function broadcastToDevtoolsCore(info, headers, stashedBody) {
180
180
  void Promise.all([
181
181
  import("./broadcast-4SX7R5XE.js"),
182
- import("./build-request-body-preview-EOP2Y4F3.js")
182
+ import("./build-request-body-preview-FVBQ7LCE.js")
183
183
  ]).then(([{ broadcastRequest }, { buildRequestBodyPreview }]) => {
184
184
  const bodyInfo = buildRequestBodyPreview(stashedBody);
185
185
  broadcastRequest({
@@ -326,4 +326,4 @@ export {
326
326
  _resetWarnOnceForTests,
327
327
  warnOnce
328
328
  };
329
- //# sourceMappingURL=chunk-WFNLNIJX.js.map
329
+ //# sourceMappingURL=chunk-VPISAMXU.js.map
@@ -112,4 +112,4 @@ export {
112
112
  CHANNEL_AGENT_STREAM,
113
113
  dispatcher
114
114
  };
115
- //# sourceMappingURL=chunk-5PU65T5W.js.map
115
+ //# sourceMappingURL=chunk-XZ6B2Y2R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/devtools/shared.ts","../src/devtools/bridge/dispatcher.ts"],"sourcesContent":["/**\n * Devtools — shared types.\n *\n * NEVER use dangerouslySetInnerHTML in any devtools component — see plan EC-20.\n */\n\nexport type DevtoolsPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'\nexport type DevtoolsTab =\n | 'requests'\n | 'routes'\n | 'agents'\n | 'actions'\n | 'errors'\n | 'csrf-readiness'\n | 'settings'\nexport type DevtoolsTheme = 'light' | 'dark' | 'system'\n\nexport interface RequestRecord {\n id: string\n traceId: string\n method: string\n path: string\n status: number\n durationMs: number\n startedAt: number\n csrfWarn?: { code: string; docsUrl: string }\n headers?: Record<string, string>\n bodyPreview?: string\n bodyLength?: number\n bodyTruncated?: boolean\n}\n\nexport interface ErrorRecord {\n id: string\n type: 'console' | 'unhandled' | 'csrf.warn'\n message: string\n stack?: string\n code?: string\n docsUrl?: string\n timestamp: number\n}\n\nexport interface CsrfWarnPayload {\n event: 'csrf.warn'\n code: string\n docsUrl: string\n method: string\n path: string\n reason: string\n}\n\nexport interface RouteInfo {\n path: string\n absoluteFilePath: string\n layoutChain: string[]\n hasLoading: boolean\n hasError: boolean\n hasNotFound: boolean\n}\n\nexport interface RouteManifest {\n routes: RouteInfo[]\n}\n\n/**\n * Per-agent-run telemetry surfaced to the Agents devtools tab.\n *\n * Emitted by `trackAgentRun` (server-side) via the dispatcher in dev mode;\n * prod tree-shakes the entire wire (v1.1 EC-4 `__IS_DEV` IIFE guard).\n * Type lives here (devtools/shared) since both producer (server/cost) and\n * consumer (AgentsTab) need the shape; following architecture v3 ADR-0001\n * rule \"shared types in core/contracts\" is the canonical home — for this\n * one we keep it in devtools/shared to minimize churn in core/contracts/.\n */\nexport interface AgentRunRecord {\n id: string\n timestamp: number\n userId: string\n model: string\n tokensInput: number\n tokensOutput: number\n costUsd: number\n status: 'finished' | 'error' | 'aborted'\n}\n\n/**\n * T5.1 — Per-action-call telemetry surfaced to the Actions devtools tab.\n *\n * Emitted by `action-execute.ts` (server-side) via the dispatcher in dev\n * mode; prod tree-shakes the wire (mirrors AgentRunRecord pattern).\n * Field-level error pins consume `error.fields` directly when status='error'\n * (per plan ADR D6).\n */\nexport interface ActionCallRecord {\n id: string\n timestamp: number\n name: string\n input: unknown\n output?: unknown\n error?: {\n code: string\n message: string\n fields?: Record<string, string[]>\n issues?: unknown[]\n }\n durationMs: number\n status: 'success' | 'error'\n}\n\nexport interface DevtoolsState {\n open: boolean\n visible: boolean\n position: DevtoolsPosition\n theme: DevtoolsTheme\n activeTab: DevtoolsTab\n requests: RequestRecord[]\n errors: ErrorRecord[]\n agentRuns: AgentRunRecord[]\n actionCalls: ActionCallRecord[]\n routeManifest: RouteManifest | null\n activeRoutePath: string | null\n activeChain: string[]\n agentStreamEvents: AgentStreamRecord[]\n}\n\nexport type DevtoolsAction =\n | { type: 'TOGGLE_PANEL' }\n | { type: 'TOGGLE_VISIBLE' }\n | { type: 'SET_TAB'; tab: DevtoolsTab }\n | { type: 'SET_POSITION'; position: DevtoolsPosition }\n | { type: 'SET_THEME'; theme: DevtoolsTheme }\n | { type: 'REQUEST_ADD'; request: RequestRecord }\n | { type: 'ERROR_ADD'; error: ErrorRecord }\n | { type: 'CSRF_WARN'; payload: CsrfWarnPayload }\n | { type: 'MANIFEST_UPDATED'; manifest: RouteManifest }\n | { type: 'ROUTE_MATCHED'; path: string; chain: string[] }\n | { type: 'AGENT_RUN_ADD'; run: AgentRunRecord }\n | { type: 'ACTION_CALL_ADD'; record: ActionCallRecord }\n | { type: 'RESET_REQUESTS' }\n | { type: 'RESET_ERRORS' }\n | { type: 'RESET_AGENT_RUNS' }\n | { type: 'RESET_ACTION_CALLS' }\n | { type: 'AGENT_STREAM_EVENT'; event: AgentStreamRecord }\n | { type: 'RESET_AGENT_STREAM' }\n\nexport const RING_BUFFER_CAP = 50\nexport const MAX_QUEUE_SIZE = 100\nexport const STORAGE_VERSION = 2\n\nexport const initialState: DevtoolsState = {\n open: false,\n visible: true,\n position: 'bottom-right',\n theme: 'dark',\n activeTab: 'requests',\n requests: [],\n errors: [],\n agentRuns: [],\n actionCalls: [],\n routeManifest: null,\n activeRoutePath: null,\n activeChain: [],\n agentStreamEvents: [],\n}\n\nexport const CHANNEL_REQUEST = 'theo:devtools:request' as const\nexport const CHANNEL_ERROR = 'theo:devtools:error' as const\nexport const CHANNEL_CSRF_WARN = 'theo:devtools:csrf.warn' as const\nexport const CHANNEL_MANIFEST = 'theo:devtools:manifest' as const\nexport const CHANNEL_ROUTE_MATCHED = 'theo:devtools:route-matched' as const\nexport const CHANNEL_AGENT_STREAM = 'theo:devtools:agent.stream' as const\n\nexport interface AgentStreamRecord {\n runId: string\n agentName: string\n type: string\n content?: string\n toolName?: string\n timestamp: number\n}\n","/**\n * T2.1 — Devtools dispatcher with pre-mount event queue.\n *\n * Pattern: events emitted from anywhere (server WS, browser console.error,\n * dispatcher.onCsrfWarn) can fire BEFORE the React tree mounts. Each call\n * either dispatches immediately (when `setDispatch` registered a dispatch\n * fn) or queues until React is ready, then flushes on first mount.\n *\n * EC-23: queue capped at MAX_QUEUE_SIZE (FIFO eviction).\n * EC-24: setDispatch is idempotent — flush only on NULL → non-null\n * transition (StrictMode re-mount safe).\n *\n * NEVER use dangerouslySetInnerHTML in any devtools component — see plan EC-20.\n */\nimport {\n type ActionCallRecord,\n type AgentRunRecord,\n type AgentStreamRecord,\n type CsrfWarnPayload,\n type DevtoolsAction,\n type ErrorRecord,\n MAX_QUEUE_SIZE,\n type RequestRecord,\n type RouteManifest,\n} from '../shared.js'\n\ntype Dispatch = (action: DevtoolsAction) => void\ntype QueuedItem = (d: Dispatch) => void\n\nlet _dispatch: Dispatch | null = null\nconst _queue: QueuedItem[] = []\n\nfunction queuable<Args extends unknown[]>(\n fn: (d: Dispatch, ...args: Args) => void,\n): (...args: Args) => void {\n return (...args: Args) => {\n if (_dispatch) {\n try {\n fn(_dispatch, ...args)\n } catch (err) {\n // EC-25: an error inside reducer-bound dispatch path MUST NOT bubble\n // to the original event source (e.g. logger / HMR callback / global\n // error handler). Log and continue.\n\n console.error('[theo devtools] dispatch failed', err)\n }\n } else {\n // EC-23: cap queue, FIFO-evict if full\n if (_queue.length >= MAX_QUEUE_SIZE) _queue.shift()\n _queue.push((d) => {\n fn(d, ...args)\n })\n }\n }\n}\n\nfunction flushQueue(): void {\n while (_queue.length) {\n const fn = _queue.shift()\n if (!fn || !_dispatch) break\n try {\n fn(_dispatch)\n } catch (err) {\n console.error('[theo devtools] queued event failed', err)\n }\n }\n}\n\nexport const dispatcher = {\n onRequest: queuable((d: Dispatch, req: RequestRecord) => {\n d({ type: 'REQUEST_ADD', request: req })\n }),\n onError: queuable((d: Dispatch, err: ErrorRecord) => {\n d({ type: 'ERROR_ADD', error: err })\n }),\n onCsrfWarn: queuable((d: Dispatch, payload: CsrfWarnPayload) => {\n d({ type: 'CSRF_WARN', payload })\n }),\n onManifestUpdated: queuable((d: Dispatch, manifest: RouteManifest) => {\n d({ type: 'MANIFEST_UPDATED', manifest })\n }),\n onRouteMatched: queuable((d: Dispatch, path: string, chain: string[]) => {\n d({ type: 'ROUTE_MATCHED', path, chain })\n }),\n onAgentRun: queuable((d: Dispatch, run: AgentRunRecord) => {\n d({ type: 'AGENT_RUN_ADD', run })\n }),\n onActionCall: queuable((d: Dispatch, record: ActionCallRecord) => {\n d({ type: 'ACTION_CALL_ADD', record })\n }),\n onAgentStreamEvent: queuable((d: Dispatch, event: AgentStreamRecord) => {\n d({ type: 'AGENT_STREAM_EVENT', event })\n }),\n\n /**\n * Wire React's dispatch function in. Idempotent (EC-24): only the\n * NULL → non-null transition flushes the queue; subsequent non-null\n * sets just replace the reference (used for StrictMode re-mount).\n */\n setDispatch(d: Dispatch | null): void {\n const prev = _dispatch\n _dispatch = d\n if (d && !prev) flushQueue()\n },\n\n /** Testing helper — clear queue + dispatch reference between tests. */\n _reset(): void {\n _dispatch = null\n _queue.length = 0\n },\n\n /** Testing helper — observe queue length. */\n _queueLength(): number {\n return _queue.length\n },\n}\n\nexport type Dispatcher = typeof dispatcher\n"],"mappings":";AAiJO,IAAM,kBAAkB;AACxB,IAAM,iBAAiB;AACvB,IAAM,kBAAkB;AAExB,IAAM,eAA8B;AAAA,EACzC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AAAA,EACX,UAAU,CAAC;AAAA,EACX,QAAQ,CAAC;AAAA,EACT,WAAW,CAAC;AAAA,EACZ,aAAa,CAAC;AAAA,EACd,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,aAAa,CAAC;AAAA,EACd,mBAAmB,CAAC;AACtB;AAEO,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AACtB,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AACzB,IAAM,wBAAwB;AAC9B,IAAM,uBAAuB;;;AC7IpC,IAAI,YAA6B;AACjC,IAAM,SAAuB,CAAC;AAE9B,SAAS,SACP,IACyB;AACzB,SAAO,IAAI,SAAe;AACxB,QAAI,WAAW;AACb,UAAI;AACF,WAAG,WAAW,GAAG,IAAI;AAAA,MACvB,SAAS,KAAK;AAKZ,gBAAQ,MAAM,mCAAmC,GAAG;AAAA,MACtD;AAAA,IACF,OAAO;AAEL,UAAI,OAAO,UAAU,eAAgB,QAAO,MAAM;AAClD,aAAO,KAAK,CAAC,MAAM;AACjB,WAAG,GAAG,GAAG,IAAI;AAAA,MACf,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,SAAS,aAAmB;AAC1B,SAAO,OAAO,QAAQ;AACpB,UAAM,KAAK,OAAO,MAAM;AACxB,QAAI,CAAC,MAAM,CAAC,UAAW;AACvB,QAAI;AACF,SAAG,SAAS;AAAA,IACd,SAAS,KAAK;AACZ,cAAQ,MAAM,uCAAuC,GAAG;AAAA,IAC1D;AAAA,EACF;AACF;AAEO,IAAM,aAAa;AAAA,EACxB,WAAW,SAAS,CAAC,GAAa,QAAuB;AACvD,MAAE,EAAE,MAAM,eAAe,SAAS,IAAI,CAAC;AAAA,EACzC,CAAC;AAAA,EACD,SAAS,SAAS,CAAC,GAAa,QAAqB;AACnD,MAAE,EAAE,MAAM,aAAa,OAAO,IAAI,CAAC;AAAA,EACrC,CAAC;AAAA,EACD,YAAY,SAAS,CAAC,GAAa,YAA6B;AAC9D,MAAE,EAAE,MAAM,aAAa,QAAQ,CAAC;AAAA,EAClC,CAAC;AAAA,EACD,mBAAmB,SAAS,CAAC,GAAa,aAA4B;AACpE,MAAE,EAAE,MAAM,oBAAoB,SAAS,CAAC;AAAA,EAC1C,CAAC;AAAA,EACD,gBAAgB,SAAS,CAAC,GAAa,MAAc,UAAoB;AACvE,MAAE,EAAE,MAAM,iBAAiB,MAAM,MAAM,CAAC;AAAA,EAC1C,CAAC;AAAA,EACD,YAAY,SAAS,CAAC,GAAa,QAAwB;AACzD,MAAE,EAAE,MAAM,iBAAiB,IAAI,CAAC;AAAA,EAClC,CAAC;AAAA,EACD,cAAc,SAAS,CAAC,GAAa,WAA6B;AAChE,MAAE,EAAE,MAAM,mBAAmB,OAAO,CAAC;AAAA,EACvC,CAAC;AAAA,EACD,oBAAoB,SAAS,CAAC,GAAa,UAA6B;AACtE,MAAE,EAAE,MAAM,sBAAsB,MAAM,CAAC;AAAA,EACzC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOD,YAAY,GAA0B;AACpC,UAAM,OAAO;AACb,gBAAY;AACZ,QAAI,KAAK,CAAC,KAAM,YAAW;AAAA,EAC7B;AAAA;AAAA,EAGA,SAAe;AACb,gBAAY;AACZ,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,eAAuB;AACrB,WAAO,OAAO;AAAA,EAChB;AACF;","names":[]}
package/dist/cli/index.js CHANGED
@@ -5,12 +5,12 @@ import "tsx/esm";
5
5
  import cac from "cac";
6
6
  var cli = cac("theokit");
7
7
  cli.command("dev", "Start development server").option("--port <port>", "Port number").action(async (options) => {
8
- const { devCommand } = await import("../dev-PS2NGT6I.js");
8
+ const { devCommand } = await import("../dev-WQ4LWCAW.js");
9
9
  await devCommand({ port: options.port ? Number(options.port) : void 0 });
10
10
  });
11
11
  cli.command("build", "Build for production").option("--target <target>", "Deploy target (node, vercel, cloudflare)").action(async (options) => {
12
12
  try {
13
- const { buildCommand } = await import("../build-BYLQZJT2.js");
13
+ const { buildCommand } = await import("../build-MQHIJROR.js");
14
14
  await buildCommand({ target: options.target });
15
15
  } catch (err) {
16
16
  const msg = err instanceof Error ? err.message : String(err);
@@ -22,7 +22,7 @@ cli.command("build", "Build for production").option("--target <target>", "Deploy
22
22
  });
23
23
  cli.command("start", "Start production server").option("--port <port>", "Port number").action(async (options) => {
24
24
  try {
25
- const { startCommand } = await import("../start-YLR2SFHU.js");
25
+ const { startCommand } = await import("../start-2U3FUCJX.js");
26
26
  await startCommand({ port: options.port ? Number(options.port) : void 0 });
27
27
  } catch (err) {
28
28
  const msg = err instanceof Error ? err.message : String(err);
@@ -37,7 +37,7 @@ cli.command(
37
37
  "Scaffold a route, action, page, ws, controller, agent, toolbox, workflow, eval, sandbox, schedule, memory, or resource (resource accepts field:type args)"
38
38
  ).action(async (type, name, fields) => {
39
39
  try {
40
- const { generateCommand } = await import("../generate-5X4LG77M.js");
40
+ const { generateCommand } = await import("../generate-GXWPUVS7.js");
41
41
  await generateCommand(type, name, fields.length > 0 ? fields : void 0);
42
42
  } catch (err) {
43
43
  const msg = err instanceof Error ? err.message : String(err);
@@ -52,7 +52,7 @@ cli.command(
52
52
  "Run an agent in the terminal (stream + tool calls + approval)"
53
53
  ).action(async (name, message) => {
54
54
  try {
55
- const { agentCommand } = await import("../agent-U35G3WNE.js");
55
+ const { agentCommand } = await import("../agent-OXRRKB55.js");
56
56
  const { sawError } = await agentCommand(name, message);
57
57
  if (sawError) process.exit(1);
58
58
  } catch (err) {
@@ -65,7 +65,7 @@ cli.command(
65
65
  });
66
66
  cli.command("mcp <agent>", "Serve an agent as an MCP server over stdio (for desktop MCP clients)").action(async (agent) => {
67
67
  try {
68
- const { mcpCommand } = await import("../mcp-ML4QK5ON.js");
68
+ const { mcpCommand } = await import("../mcp-FF3NTCHB.js");
69
69
  await mcpCommand(agent);
70
70
  } catch (err) {
71
71
  const msg = err instanceof Error ? err.message : String(err);
@@ -77,7 +77,7 @@ cli.command("mcp <agent>", "Serve an agent as an MCP server over stdio (for desk
77
77
  });
78
78
  cli.command("routes", "List all routes, actions, and WebSocket endpoints").action(async () => {
79
79
  try {
80
- const { routesCommand } = await import("../routes-XNS3UM3B.js");
80
+ const { routesCommand } = await import("../routes-ZVDKABXZ.js");
81
81
  await routesCommand();
82
82
  } catch (err) {
83
83
  const msg = err instanceof Error ? err.message : String(err);
@@ -103,22 +103,22 @@ cli.command("check", "Run typecheck + scan + (optional) eslint").option(
103
103
  `);
104
104
  process.exit(1);
105
105
  }
106
- const { upgradeReadinessCommand } = await import("../upgrade-readiness-ACGW44JC.js");
106
+ const { upgradeReadinessCommand } = await import("../upgrade-readiness-77P6VNB4.js");
107
107
  await upgradeReadinessCommand({
108
108
  json: Boolean(options.json),
109
109
  allowWarnings: Boolean(options.allowWarnings)
110
110
  });
111
111
  return;
112
112
  }
113
- const { checkCommand } = await import("../check-PD2FTKMM.js");
113
+ const { checkCommand } = await import("../check-45NKUVSQ.js");
114
114
  await checkCommand();
115
115
  });
116
116
  cli.command("add <package>", "Install a known TheoKit adapter or plugin (whitelist-only)").action(async (pkg) => {
117
- const { addCommand } = await import("../add-W6FNTAFS.js");
117
+ const { addCommand } = await import("../add-3VLFUPF4.js");
118
118
  await addCommand(pkg);
119
119
  });
120
120
  cli.command("info", "Print environment info (runtime, config, routes)").action(async () => {
121
- const { infoCommand } = await import("../info-2OOXFTJX.js");
121
+ const { infoCommand } = await import("../info-75U6GCMD.js");
122
122
  await infoCommand();
123
123
  });
124
124
  cli.command(
@@ -126,7 +126,7 @@ cli.command(
126
126
  "Generate <distDir>/openapi.json from route schemas (opt-in via config.openapi)"
127
127
  ).option("--dry-run", "Print the document to stdout without writing to disk (EC-3)").action(async (options) => {
128
128
  try {
129
- const { openapiCommand } = await import("../openapi-2HVGJMSN.js");
129
+ const { openapiCommand } = await import("../openapi-ZPXYRAM2.js");
130
130
  await openapiCommand({ dryRun: Boolean(options.dryRun) });
131
131
  } catch (err) {
132
132
  const msg = err instanceof Error ? err.message : String(err);
@@ -142,7 +142,7 @@ cli.command(
142
142
  ).option("--dry-run", "Print the migration plan but do not touch the filesystem").option("--force", "Skip the dev-server port pre-flight check (CI / non-TTY)").option("--name <slug>", "Explicit project name (DNS-1123). Services-json migrate only.").action(async (kind, options) => {
143
143
  try {
144
144
  if (kind === "router") {
145
- const { routerMigrateCommand } = await import("../router-TLEAOFID.js");
145
+ const { routerMigrateCommand } = await import("../router-6MAACS25.js");
146
146
  await routerMigrateCommand({
147
147
  dryRun: Boolean(options.dryRun),
148
148
  force: Boolean(options.force)
@@ -150,7 +150,7 @@ cli.command(
150
150
  return;
151
151
  }
152
152
  if (kind === "services-json-v1-to-v2" || kind === "services-json") {
153
- const { servicesJsonMigrateCommand } = await import("../services-json-Y3XODNB5.js");
153
+ const { servicesJsonMigrateCommand } = await import("../services-json-7ZXJ4CIS.js");
154
154
  await servicesJsonMigrateCommand({
155
155
  dryRun: Boolean(options.dryRun),
156
156
  name: options.name
@@ -185,7 +185,7 @@ cli.command("docker", "Generate Dockerfile for production").option("--force", "O
185
185
  });
186
186
  cli.command("db <action>", "Database commands: migrate (push schema), generate (SQL files), seed").action(async (action) => {
187
187
  try {
188
- const { dbCommandCli } = await import("../db-3UNAMSFK.js");
188
+ const { dbCommandCli } = await import("../db-IVVCQE5Z.js");
189
189
  dbCommandCli(action);
190
190
  } catch (err) {
191
191
  const msg = err instanceof Error ? err.message : String(err);
@@ -224,7 +224,7 @@ interface LinkProps extends LinkProps$1 {
224
224
  * <Link to="/settings" prefetch="none">Settings</Link>
225
225
  * ```
226
226
  */
227
- declare function Link({ prefetch, to, onMouseEnter, onFocus, ...rest }: LinkProps): react.JSX.Element;
227
+ declare function Link({ prefetch, to, onMouseEnter, onFocus, ...rest }: Readonly<LinkProps>): react.JSX.Element;
228
228
 
229
229
  /**
230
230
  * <Metadata> — SEO-ready head tags from a single component.
@@ -322,9 +322,9 @@ function injectParams(path, params) {
322
322
  }
323
323
  return path;
324
324
  }
325
- return path.replace(/:(?:\.\.\.)?([A-Za-z_][A-Za-z0-9_]*)/g, (_match, key) => {
325
+ return path.replace(/:(?:\.\.\.)?([A-Za-z_]\w*)/g, (_match, key) => {
326
326
  const value = params[key];
327
- if (value === void 0 || value === null || value === "") {
327
+ if (value === "") {
328
328
  throw new TheoFetchError(0, {
329
329
  error: {
330
330
  code: "MISSING_PARAM",
@@ -355,13 +355,13 @@ function makeProxy(ctx) {
355
355
  const segmentsWithDynamic = ctx.segments.map(
356
356
  (seg) => Object.prototype.hasOwnProperty.call(opts.params, seg) ? `:${seg}` : seg
357
357
  );
358
- finalPath = injectParams(
359
- `${ctx.baseUrl}/${segmentsWithDynamic.join("/")}`,
360
- opts.params
361
- );
358
+ finalPath = injectParams(`${ctx.baseUrl}/${segmentsWithDynamic.join("/")}`, opts.params);
362
359
  }
363
360
  const { params: _ignored, ...rest } = opts ?? {};
364
- const init = { method: key.toUpperCase(), ...rest };
361
+ const init = {
362
+ method: key.toUpperCase(),
363
+ ...rest
364
+ };
365
365
  return ctx.fetchImpl(finalPath, init);
366
366
  };
367
367
  }
@@ -449,10 +449,8 @@ function useAgent(binding, options = {}) {
449
449
  }
450
450
 
451
451
  // src/client/link.tsx
452
- import {
453
- Link as RouterLink
454
- } from "react-router";
455
452
  import { useRef as useRef2, useCallback, useEffect } from "react";
453
+ import { Link as RouterLink } from "react-router";
456
454
  import { jsx } from "react/jsx-runtime";
457
455
  var prefetched = /* @__PURE__ */ new Set();
458
456
  function injectPrefetch(href) {
@@ -466,9 +464,15 @@ function injectPrefetch(href) {
466
464
  }
467
465
  function resolveTo(to) {
468
466
  if (typeof to === "string") return to;
469
- return to?.pathname ?? "";
467
+ return to.pathname ?? "";
470
468
  }
471
- function Link({ prefetch = "intent", to, onMouseEnter, onFocus, ...rest }) {
469
+ function Link({
470
+ prefetch = "intent",
471
+ to,
472
+ onMouseEnter,
473
+ onFocus,
474
+ ...rest
475
+ }) {
472
476
  const ref = useRef2(null);
473
477
  const handleIntent = useCallback(
474
478
  (event) => {
@@ -476,11 +480,9 @@ function Link({ prefetch = "intent", to, onMouseEnter, onFocus, ...rest }) {
476
480
  injectPrefetch(resolveTo(to));
477
481
  }
478
482
  if (event.type === "mouseenter" && onMouseEnter) {
479
- ;
480
483
  onMouseEnter(event);
481
484
  }
482
485
  if (event.type === "focus" && onFocus) {
483
- ;
484
486
  onFocus(event);
485
487
  }
486
488
  },
@@ -500,18 +502,11 @@ function Link({ prefetch = "intent", to, onMouseEnter, onFocus, ...rest }) {
500
502
  // prefetch slightly before visible
501
503
  );
502
504
  observer.observe(ref.current);
503
- return () => observer.disconnect();
505
+ return () => {
506
+ observer.disconnect();
507
+ };
504
508
  }, [prefetch, to]);
505
- return /* @__PURE__ */ jsx(
506
- RouterLink,
507
- {
508
- ref,
509
- to,
510
- onMouseEnter: handleIntent,
511
- onFocus: handleIntent,
512
- ...rest
513
- }
514
- );
509
+ return /* @__PURE__ */ jsx(RouterLink, { ref, to, onMouseEnter: handleIntent, onFocus: handleIntent, ...rest });
515
510
  }
516
511
 
517
512
  // src/client/metadata.tsx
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/theo-fetch.ts","../../src/client/batch.ts","../../src/client/batch-transport.ts","../../src/client/app-client.ts","../../src/client/use-agent.ts","../../src/client/agent-handle.ts","../../src/client/link.tsx","../../src/client/metadata.tsx","../../src/client/image.tsx","../../src/client/mcp-app-host.ts"],"sourcesContent":["import superjson from 'superjson'\nimport type { z } from 'zod'\n\nimport type { TheoErrorCode, TheoErrorEnvelope } from '../core/contracts/error-envelope.js'\n\nimport { getGlobalBatcher } from './batch-transport.js'\n\n// --- Transformer (T1.3) ---\n\n/**\n * Module-scoped flag preventing the transformer-mismatch warning from\n * firing more than once per session (EC-6).\n */\nlet mismatchWarned = false\n\n/** Test-only helper to reset the warned flag between assertions. */\nexport function __resetMismatchWarningForTests(): void {\n mismatchWarned = false\n}\n\n/**\n * Deserialize a fetch response body according to the negotiated transformer.\n *\n * `serverTransformerName` comes from the `x-theo-transformer` response header\n * (null when absent — server is using the default JSON path).\n * `clientTransformerName` is the transformer the client was built with\n * (typically injected via a Vite virtual module; falls back to `'json'`).\n *\n * Mismatch fires a single console.warn and falls back to JSON.parse (EC-5/EC-6).\n */\nexport function deserializeFetchResponse(\n raw: string,\n serverTransformerName: string | null,\n clientTransformerName: string,\n): unknown {\n // `raw` is typed `string`, but stay defensive: callers pass `await response.text()`\n // which can be empty.\n if (raw === '') {\n return null\n }\n\n const serverEffective = serverTransformerName ?? 'json'\n if (serverEffective !== clientTransformerName && !mismatchWarned) {\n mismatchWarned = true\n console.warn(\n `[theokit] transformer mismatch: server=${serverEffective}, client=${clientTransformerName}. Falling back to JSON.parse.`,\n )\n }\n\n if (serverEffective === 'superjson' && clientTransformerName === 'superjson') {\n const wrapped = JSON.parse(raw) as Parameters<typeof superjson.deserialize>[0]\n return superjson.deserialize(wrapped)\n }\n\n // Default path (json) or mismatch fallback\n return JSON.parse(raw)\n}\n\n// --- Utility Types ---\n\n/** Infer the response type from a route's handler return */\nexport type InferResponse<T> = T extends { handler: (...args: never[]) => infer R }\n ? Awaited<R>\n : unknown\n\n/** Extract the query Zod schema type, handling optional properties */\ntype ExtractQuery<T> = T extends { query?: infer Q } ? (Q extends z.ZodType ? Q : never) : never\n\n/** Extract the body Zod schema type, handling optional properties */\ntype ExtractBody<T> = T extends { body?: infer B } ? (B extends z.ZodType ? B : never) : never\n\n/** Infer query type from a route's query Zod schema */\nexport type InferQuery<T> = [ExtractQuery<T>] extends [never]\n ? undefined\n : ExtractQuery<T> extends z.ZodUndefined\n ? undefined\n : z.infer<ExtractQuery<T>>\n\n/** Infer body type from a route's body Zod schema */\nexport type InferBody<T> = [ExtractBody<T>] extends [never]\n ? undefined\n : ExtractBody<T> extends z.ZodUndefined\n ? undefined\n : z.infer<ExtractBody<T>>\n\n/** Build the options type based on what schemas the route has */\nexport type TheoFetchOptions<T> = Omit<RequestInit, 'body' | 'method'> &\n (InferQuery<T> extends undefined ? { query?: never } : { query: InferQuery<T> }) &\n (InferBody<T> extends undefined ? { body?: never } : { body: InferBody<T> })\n\n// --- Error Class ---\n\n/**\n * G5 T2.1 — extract a TheoErrorEnvelope from a response body. Supports both\n * the new envelope-at-root shape (`{ code, message, ext?, ... }`, blueprint\n * Recommendations § concrete shape) and the legacy nested shape\n * (`{ error: { code, message, issues? } }`, G3 SerializedActionResult).\n *\n * Falls back to `INTERNAL_SERVER_ERROR` with a synthetic message when the\n * body shape is unrecognized. Pure; no I/O.\n */\nfunction extractEnvelope(status: number, body: unknown): TheoErrorEnvelope {\n if (!body || typeof body !== 'object') {\n return { code: 'INTERNAL_SERVER_ERROR', message: `HTTP ${String(status)}` }\n }\n const obj = body as Record<string, unknown>\n // New shape — envelope at root\n if (typeof obj.code === 'string' && typeof obj.message === 'string') {\n return {\n code: obj.code as TheoErrorCode,\n message: obj.message,\n cause: obj.cause,\n meta: obj.meta as Record<string, unknown> | undefined,\n ext: obj.ext,\n }\n }\n // Legacy shape — { error: { code, message, ... } }\n if (obj.error && typeof obj.error === 'object') {\n const nested = obj.error as Record<string, unknown>\n return {\n code:\n typeof nested.code === 'string' ? (nested.code as TheoErrorCode) : 'INTERNAL_SERVER_ERROR',\n message: typeof nested.message === 'string' ? nested.message : `HTTP ${String(status)}`,\n }\n }\n return { code: 'INTERNAL_SERVER_ERROR', message: `HTTP ${String(status)}` }\n}\n\n/**\n * Pull a single string field from an object, returning undefined if missing\n * or non-string. Helper for `extractLegacyFields` to stay under the\n * complexity ceiling.\n */\nfunction strField(obj: Record<string, unknown> | null, key: string): string | undefined {\n const v = obj?.[key]\n return typeof v === 'string' ? v : undefined\n}\n\n/**\n * Pull the canonical {message, code, issues} from either an envelope-at-root\n * body or the legacy { error: {...} } body. Pure.\n */\nfunction extractLegacyFields(\n status: number,\n body: unknown,\n): { message: string; code?: string; issues?: unknown[] } {\n if (!body || typeof body !== 'object') {\n return { message: `HTTP ${String(status)}` }\n }\n const obj = body as Record<string, unknown>\n const nested =\n obj.error && typeof obj.error === 'object' ? (obj.error as Record<string, unknown>) : null\n const issues = Array.isArray(nested?.issues) ? nested.issues : undefined\n return {\n message: strField(obj, 'message') ?? strField(nested, 'message') ?? `HTTP ${String(status)}`,\n code: strField(obj, 'code') ?? strField(nested, 'code'),\n issues,\n }\n}\n\nexport class TheoFetchError extends Error {\n status: number\n code?: string\n issues?: unknown[]\n /**\n * G5 T2.1 — canonical envelope view of the server-side error. Use this in\n * consumer code that wants to switch on a typed TheoErrorCode instead of\n * coupling to the legacy `.status` / `.code` flat fields.\n */\n readonly envelope: TheoErrorEnvelope\n\n constructor(status: number, body?: unknown) {\n const legacy = extractLegacyFields(status, body)\n super(legacy.message)\n this.name = 'TheoFetchError'\n this.status = status\n this.code = legacy.code\n this.issues = legacy.issues\n this.envelope = extractEnvelope(status, body)\n }\n}\n\n/**\n * Serialize a query-param value to a string. Handles primitives, dates,\n * and falls back to JSON for arrays/objects. Avoids the\n * `[object Object]` foot-gun that `no-base-to-string` warns against.\n */\nfunction stringifyQueryValue(value: unknown): string {\n if (value === null) return 'null'\n if (value instanceof Date) return value.toISOString()\n switch (typeof value) {\n case 'string':\n return value\n case 'number':\n case 'boolean':\n case 'bigint':\n return String(value)\n default:\n return JSON.stringify(value)\n }\n}\n\n// --- Main Function ---\n\ninterface TheoFetchInternalOptions {\n method?: string\n query?: Record<string, unknown>\n body?: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\n/**\n * Resolve the request origin per the documented fallback hierarchy. Pure\n * helper extracted to keep `theoFetch` under the complexity ceiling.\n * 1. `globalThis.location.origin` (browser)\n * 2. `globalThis.__THEO_ORIGIN__` (build-time literal)\n * 3. `process.env.THEO_ORIGIN` (escape hatch)\n * 4. `http://localhost` (placeholder for URL parsing — the URL is built\n * relative so only pathname+search ever flows to the wire)\n */\nfunction resolveRequestOrigin(): string {\n const g = globalThis as { location?: { origin?: string }; __THEO_ORIGIN__?: string }\n const fromEnv = typeof process !== 'undefined' ? process.env.THEO_ORIGIN : undefined\n return g.location?.origin ?? g.__THEO_ORIGIN__ ?? fromEnv ?? 'http://localhost'\n}\n\nfunction buildFetchUrl(path: string, query: Record<string, unknown> | undefined): URL {\n const fetchUrl = new URL(path, resolveRequestOrigin())\n if (!query) return fetchUrl\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined) {\n fetchUrl.searchParams.set(k, stringifyQueryValue(v))\n }\n }\n return fetchUrl\n}\n\n/**\n * Normalize `HeadersInit` (Headers / `[string, string][]` / Record) into a\n * single plain `Record<string, string>`. Plain-object output is required\n * by callers that introspect headers via index access (test fixtures use\n * `(init.headers as Record<string, string>)['Content-Type']`).\n */\nfunction normalizeHeaders(input: HeadersInit | undefined): Record<string, string> {\n const out: Record<string, string> = {}\n if (!input) return out\n if (input instanceof Headers) {\n input.forEach((value, key) => {\n out[key] = value\n })\n return out\n }\n if (Array.isArray(input)) {\n for (const [key, value] of input) out[key] = value\n return out\n }\n for (const [key, value] of Object.entries(input)) {\n out[key] = value\n }\n return out\n}\n\nfunction buildRequestInit(opts: TheoFetchInternalOptions): RequestInit {\n const init: RequestInit = {}\n if (opts.method !== undefined) init.method = opts.method\n if (opts.signal !== undefined) init.signal = opts.signal\n\n const headers = normalizeHeaders(opts.headers)\n init.headers = headers\n\n if (opts.body !== undefined) {\n init.body = JSON.stringify(opts.body)\n headers['Content-Type'] = 'application/json'\n }\n\n // Phase 5 — Auto-attach `X-Theo-Action: 1` for state-mutating methods so\n // the framework's CSRF check passes when servers run in `strict` mode.\n // Safe methods (GET/HEAD/OPTIONS) skip the header to keep them cacheable.\n const method = (opts.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS') {\n headers['X-Theo-Action'] = '1'\n }\n return init\n}\n\nasync function tryBatcher(\n url: string,\n options: TheoFetchInternalOptions,\n): Promise<{ matched: true; result: unknown } | { matched: false }> {\n const batcher = getGlobalBatcher()\n if (!batcher) return { matched: false }\n try {\n const result = await batcher.dispatch({\n path: url,\n method: options.method ?? 'GET',\n query: options.query,\n body: options.body,\n })\n return { matched: true, result }\n } catch {\n // Batcher failure: fall through to direct fetch (graceful degrade).\n return { matched: false }\n }\n}\n\nexport async function theoFetch<T>(\n url: string,\n options?: TheoFetchOptions<T>,\n): Promise<InferResponse<T>> {\n const internal = (options ?? {}) as unknown as TheoFetchInternalOptions\n\n // T1.5 — Transparent batching when globalThis.__THEO_BATCHING__ is truthy.\n const batchAttempt = await tryBatcher(url, internal)\n if (batchAttempt.matched) {\n return batchAttempt.result as InferResponse<T>\n }\n\n const fetchUrl = buildFetchUrl(url, internal.query)\n const init = buildRequestInit(internal)\n const response = await fetch(fetchUrl.toString(), init)\n\n if (!response.ok) {\n let errorBody: unknown\n try {\n errorBody = await response.json()\n } catch {\n // Non-JSON error response\n }\n throw new TheoFetchError(response.status, errorBody)\n }\n\n // Handle 204 No Content (EC-1)\n if (response.status === 204) {\n return null as InferResponse<T>\n }\n\n // Check for empty body\n const contentLength = response.headers.get('content-length')\n if (contentLength === '0') {\n return null as InferResponse<T>\n }\n\n // T1.3 — transformer-aware deserialization\n const serverTransformerName = response.headers.get('x-theo-transformer')\n const clientTransformerName = resolveClientTransformerName()\n const text = await response.text()\n return deserializeFetchResponse(\n text,\n serverTransformerName,\n clientTransformerName,\n ) as InferResponse<T>\n}\n\n/**\n * Read the client-configured transformer name. Default `'json'`.\n *\n * In a Vite build, this is overridden by virtual module\n * `/@theo/runtime-config` which sets `globalThis.__THEO_TRANSFORMER__`.\n * Outside Vite (Node SSR, tests) the default applies.\n */\nfunction resolveClientTransformerName(): string {\n const g = globalThis as { __THEO_TRANSFORMER__?: string }\n return g.__THEO_TRANSFORMER__ ?? 'json'\n}\n","/**\n * T5.1 — client-side microtask batching.\n *\n * Collects all `dispatch` calls within the same microtask and sends them as a\n * single HTTP POST to the configured transport. Each caller's promise resolves\n * with its own result; one failed item does not break the others (per-item\n * error isolation).\n *\n * Designed as a transport-agnostic primitive so unit tests do not require\n * network access. The default transport (fetch to `/api/__theo_batch__`)\n * lives alongside this module but is created by the consumer (e.g., theoFetch).\n */\n\nexport interface BatchRequest {\n path: string\n method: string\n query?: Record<string, unknown>\n body?: unknown\n headers?: Record<string, string>\n}\n\nexport type BatchResponse =\n | { index: number; data: unknown }\n | { index: number; error: { message: string; code?: string } }\n\nexport type BatchTransport = (requests: BatchRequest[]) => Promise<BatchResponse[]>\n\nexport interface BatcherOptions {\n transport: BatchTransport\n /** Maximum batch size before flushing into multiple parallel batches. */\n max?: number\n}\n\nexport interface Batcher {\n dispatch(req: BatchRequest): Promise<unknown>\n}\n\ninterface PendingCall {\n req: BatchRequest\n resolve: (value: unknown) => void\n reject: (reason: unknown) => void\n}\n\nexport function createBatcher(options: BatcherOptions): Batcher {\n const max = options.max ?? 32\n let queue: PendingCall[] = []\n let flushScheduled = false\n\n function flush(): void {\n flushScheduled = false\n const current = queue\n queue = []\n if (current.length === 0) return\n\n // Split into chunks respecting max\n const chunks: PendingCall[][] = []\n for (let i = 0; i < current.length; i += max) {\n chunks.push(current.slice(i, i + max))\n }\n\n for (const chunk of chunks) {\n const payload: BatchRequest[] = chunk.map((p) => p.req)\n options\n .transport(payload)\n .then((results) => {\n for (let i = 0; i < chunk.length; i++) {\n // `results[i]` could be undefined at runtime when the transport\n // returns fewer entries than the chunk; TypeScript's strict\n // typing without `noUncheckedIndexedAccess` does not surface\n // this, so we hand-narrow.\n const result = results.length > i ? results[i] : undefined\n if (result === undefined) {\n chunk[i].reject(new Error(`Batch transport returned no result for index ${i}`))\n continue\n }\n if ('error' in result) {\n const err = new Error(result.error.message)\n ;(err as { code?: string }).code = result.error.code\n chunk[i].reject(err)\n } else {\n chunk[i].resolve(result.data)\n }\n }\n })\n .catch((err: unknown) => {\n for (const item of chunk) item.reject(err)\n })\n }\n }\n\n return {\n dispatch(req: BatchRequest): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n queue.push({ req, resolve, reject })\n if (!flushScheduled) {\n flushScheduled = true\n queueMicrotask(flush)\n }\n })\n },\n }\n}\n","/**\n * T1.5 — Default HTTP transport for the client batcher.\n *\n * Wraps `fetch` to POST `/api/__theo_batch__` with the collected requests\n * and return the array of per-item results.\n */\n\nimport {\n createBatcher,\n type BatchTransport,\n type Batcher,\n type BatchRequest,\n type BatchResponse,\n} from './batch.js'\n\nconst BATCH_ENDPOINT = '/api/__theo_batch__'\n\nexport interface CreateBatchTransportOptions {\n /** Override fetch (default: globalThis.fetch). Used by tests. */\n fetchImpl?: typeof fetch\n /** Override endpoint (default '/api/__theo_batch__'). */\n endpoint?: string\n}\n\nexport function createBatchTransport(options: CreateBatchTransportOptions = {}): BatchTransport {\n const fetchImpl = options.fetchImpl ?? fetch\n const endpoint = options.endpoint ?? BATCH_ENDPOINT\n return async (requests: BatchRequest[]): Promise<BatchResponse[]> => {\n const response = await fetchImpl(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ requests }),\n })\n if (!response.ok) {\n throw new Error(`Batch transport returned ${response.status}`)\n }\n const payload = (await response.json()) as { results?: BatchResponse[] }\n if (!Array.isArray(payload.results)) {\n throw new Error('Batch response missing results array')\n }\n // Map results to indexed BatchResponse shape (server already returns the right form)\n return payload.results.map((item, index) => {\n if ('error' in item) {\n return { index, error: (item as { error: { message: string; code?: string } }).error }\n }\n return { index, data: (item as { data: unknown }).data }\n })\n }\n}\n\n// --- EC-7: singleton batcher per page, lazy-instantiated ---\n\nlet globalBatcher: Batcher | undefined\n\n/** Test-only — reset the module-scope singleton between assertions. */\nexport function __resetGlobalBatcherForTests(): void {\n globalBatcher = undefined\n}\n\n/**\n * Returns the global batcher singleton when `globalThis.__THEO_BATCHING__` is\n * truthy; undefined otherwise. Lazy-instantiated on first call.\n */\nexport function getGlobalBatcher(): Batcher | undefined {\n const g = globalThis as { __THEO_BATCHING__?: boolean }\n if (!g.__THEO_BATCHING__) return undefined\n globalBatcher ??= createBatcher({ transport: createBatchTransport() })\n return globalBatcher\n}\n","/**\n * Phase 3 of G1 (g1-client-codegen-plan.md):\n *\n * `createAppClient(baseUrl?, fetchImpl?)` returns a Proxy that walks property\n * access (`client.posts.id.get(...)`) into a `theoFetch` invocation against\n * `{baseUrl}/posts/{params.id}` with method `GET`.\n *\n * Type safety is delivered by the `.d.ts` file emitted in Phase 2 — this\n * runtime is structurally untyped. Power users may use `theoFetch` directly\n * when they need to escape the Proxy facade.\n *\n * Edge cases absorbed:\n * - EC-1 (thenable trap): `then` / `catch` / `finally` / `toJSON` / `Symbol.*`\n * return `undefined` so that accidental `await client.posts` resolves to a\n * plain Proxy value (it is NOT thenable) instead of looping.\n * - EC-7 (abort signal): `opts.signal` is spread through to the underlying\n * fetchImpl unchanged — verified in unit tests.\n *\n * Bundle target: ≤ 2KB gzipped.\n */\n\nimport { theoFetch, TheoFetchError } from './theo-fetch.js'\nimport type { TheoFetchOptions } from './theo-fetch.js'\nimport { HTTP_METHOD_LOWERCASE } from '../core/contracts/http-methods.js'\n\nconst HTTP_METHODS_SET = new Set(HTTP_METHOD_LOWERCASE)\n\n/**\n * Keys that JavaScript runtime / inspectors / Promise resolution probe\n * unconditionally. Returning `undefined` for these keeps the Proxy from\n * pretending to be a thenable / iterable / serializable thing.\n */\nconst NON_INTERCEPT_KEYS = new Set([\n 'then',\n 'catch',\n 'finally',\n 'toJSON',\n 'toString',\n 'valueOf',\n 'constructor',\n 'prototype',\n])\n\ntype FetchImpl = typeof theoFetch\n\ninterface CallOptions {\n params?: Record<string, string | number>\n query?: Record<string, unknown>\n body?: unknown\n signal?: AbortSignal\n headers?: HeadersInit\n // arbitrary RequestInit fields (mode, credentials, cache, etc.)\n [k: string]: unknown\n}\n\nfunction injectParams(path: string, params?: Record<string, string | number>): string {\n if (!params) {\n if (/:(?:\\.\\.\\.)?[A-Za-z_]/.test(path)) {\n throw new TheoFetchError(0, {\n error: {\n code: 'MISSING_PARAM',\n message: `Route ${path} requires params but none were provided. Pass them via opts.params, e.g. client.posts.get({ params: { id: '123' } }).`,\n },\n })\n }\n return path\n }\n return path.replace(/:(?:\\.\\.\\.)?([A-Za-z_][A-Za-z0-9_]*)/g, (_match, key: string) => {\n const value = params[key]\n if (value === undefined || value === null || value === '') {\n throw new TheoFetchError(0, {\n error: {\n code: 'MISSING_PARAM',\n message: `Param '${key}' is required for path '${path}' but was missing/empty.`,\n },\n })\n }\n return encodeURIComponent(String(value))\n })\n}\n\ninterface ProxyContext {\n segments: string[]\n baseUrl: string\n fetchImpl: FetchImpl\n}\n\nfunction makeProxy(ctx: ProxyContext): unknown {\n const handler: ProxyHandler<() => void> = {\n get(_target, key) {\n if (typeof key !== 'string') return undefined\n if (NON_INTERCEPT_KEYS.has(key)) return undefined\n if (HTTP_METHODS_SET.has(key)) {\n return async (opts?: CallOptions) => {\n if (ctx.segments.length === 0) {\n throw new TheoFetchError(0, {\n error: {\n code: 'INVALID_PATH',\n message: `client.${key}() called without a route segment. Use client.<resource>.${key}(...) instead.`,\n },\n })\n }\n let finalPath = `${ctx.baseUrl}/${ctx.segments.join('/')}`\n if (opts?.params) {\n // Build a path with `:name` placeholders re-inserted from segments\n // whose name matches a key in opts.params (treat as dynamic).\n const segmentsWithDynamic = ctx.segments.map((seg) =>\n Object.prototype.hasOwnProperty.call(opts.params, seg) ? `:${seg}` : seg,\n )\n finalPath = injectParams(\n `${ctx.baseUrl}/${segmentsWithDynamic.join('/')}`,\n opts.params,\n )\n }\n const { params: _ignored, ...rest } = opts ?? {}\n const init = { method: key.toUpperCase(), ...rest } as unknown as TheoFetchOptions<unknown>\n return ctx.fetchImpl(finalPath, init)\n }\n }\n // Continue traversal — append segment to the path.\n return makeProxy({ ...ctx, segments: [...ctx.segments, key] })\n },\n apply() {\n return Promise.reject(\n new TheoFetchError(0, {\n error: {\n code: 'INVALID_CALL',\n message:\n 'client(...) is not callable. Use client.<resource>.<method>(opts?) — e.g. client.posts.get().',\n },\n }),\n )\n },\n }\n return new Proxy(() => undefined, handler)\n}\n\nexport interface CreateAppClientOptions {\n /** Base URL for the API. Defaults to `/api`. */\n baseUrl?: string\n /** Test-only fetch override. Production callers should not pass this. */\n fetchImpl?: FetchImpl\n}\n\nexport function createAppClient<TAppClient = unknown>(\n baseUrlOrOptions?: string | CreateAppClientOptions,\n legacyFetchImpl?: FetchImpl,\n): TAppClient {\n let baseUrl = '/api'\n let fetchImpl: FetchImpl = theoFetch\n if (typeof baseUrlOrOptions === 'string') {\n baseUrl = baseUrlOrOptions || '/api'\n } else if (baseUrlOrOptions && typeof baseUrlOrOptions === 'object') {\n if (baseUrlOrOptions.baseUrl) baseUrl = baseUrlOrOptions.baseUrl\n if (baseUrlOrOptions.fetchImpl) fetchImpl = baseUrlOrOptions.fetchImpl\n }\n // Legacy 2nd-arg fetchImpl overrides regardless of 1st-arg shape (test seam).\n if (legacyFetchImpl) fetchImpl = legacyFetchImpl\n // Strip trailing slash for predictable joining.\n if (baseUrl.length > 1 && baseUrl.endsWith('/')) baseUrl = baseUrl.slice(0, -1)\n return makeProxy({ segments: [], baseUrl, fetchImpl }) as TAppClient\n}\n","import type { UIMessage } from 'ai'\nimport { useMemo, useRef, useSyncExternalStore } from 'react'\n\nimport { AgentClient, type UseAgentStatus } from './agent-client.js'\nimport { type AgentHandle, isAgentHandle } from './agent-handle.js'\nimport { HttpTransport } from './http-transport.js'\nimport type { AgentTransport, ApprovalDecision, RequestContext } from './transport.js'\n\n/**\n * M2 (theokit-ai-first) / M41 (ADR-0050) — `useAgent`, the ONE typed client hook for the\n * `agents/*.ts` convention, unified across surfaces.\n *\n * Pass an endpoint path (web) OR an {@link AgentTransport} (terminal/desktop). A string is wrapped in\n * an {@link HttpTransport} (exact back-compat with the pre-M41 fetch+SSE hook); an `InProcessTransport`\n * drives the SAME hook in a single process. The hook is a thin binding over the framework-agnostic\n * {@link AgentClient} store via React's native `useSyncExternalStore` (no test-DOM dependency). The\n * generated `@theo/agents` module types `send` to the agent's `input` schema — inferred end-to-end\n * from the server `defineAgent({ input })` with ZERO manual wiring.\n */\nexport type { UseAgentStatus }\n\nexport interface UseAgentReturn<TInput = unknown, TToolNames extends string = string> {\n /** The CURRENT turn's assistant messages (per-turn; reset each `send`). Back-compat since M41. */\n messages: UIMessage[]\n /**\n * M46 — the full conversation to render: committed turns + the current turn's user + in-flight\n * assistant, accumulated across sends with stable ids. Prefer this over hand-rolling a transcript\n * from `messages`. Same shape on every surface (web/desktop/TUI) — it lives in the core store.\n */\n thread: UIMessage[]\n status: UseAgentStatus\n /** The last error, or `undefined`. */\n error: Error | undefined\n /** Send a request; opens a new stream. Typed to the agent's `input` schema. */\n send: (input: TInput) => void\n /** Abort an in-flight stream. */\n abort: () => void\n /** Clear messages + error, back to idle. */\n reset: () => void\n /** Settle a paused HITL approval (HTTP `POST /approve/<id>` for web; the inline callback in-process). */\n approve: (approvalId: string, decision: ApprovalDecision) => Promise<void>\n /** Resume an interrupted stream (M37 durable transport for web; a no-op in-process). */\n reconnect: () => void\n /**\n * The union of tool names this agent can emit (M8), carried end-to-end from the `agent()` builder's\n * accumulated tool-name type through the generated `@theo/agents` client. Type-only witness (never\n * populated at runtime). Resolves to the literal union for builder agents, `string` otherwise.\n */\n readonly __toolNames?: TToolNames\n}\n\nexport interface UseAgentOptions {\n /**\n * Extra request headers (e.g., auth) — applied when a string path builds an `HttpTransport`. Read on\n * EVERY request, so a value that changes across renders (a rotating JWT) is never sent stale.\n */\n headers?: Record<string, string>\n /** Override fetch (primarily for tests) — captured when a string path builds an `HttpTransport`. */\n fetch?: typeof fetch\n /**\n * M43 — per-request context attached uniformly to EVERY transport (`headers` → HTTP request headers;\n * `metadata` → the in-process runner / Tauri invoke). A value OR a resolver evaluated on every\n * send/reconnect, so a rotating token/tenant is never stale.\n */\n context?: RequestContext | (() => RequestContext | undefined)\n}\n\n/**\n * Bind to an agent by endpoint path (`/api/agents/<name>`), by a typed {@link AgentHandle} (M47 — the\n * generated `chat` handle; kills the magic string + duplicated input type), or by an explicit\n * {@link AgentTransport}. Prefer the generated `useAgent` from `@theo/agents` (typed by agent name or\n * handle); this base accepts all three. The store is created once per binding identity — memoize a\n * transport before passing it.\n */\nexport function useAgent<TInput = unknown>(\n binding: string | AgentHandle<TInput> | AgentTransport,\n options: UseAgentOptions = {},\n): UseAgentReturn<TInput> {\n // Track the latest options so the built HttpTransport reads current headers per request (dynamic\n // auth is never stale) without rebuilding the store — which would drop in-flight messages.\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n // A handle resolves to its HTTP path; a string is already a path — both build an HttpTransport. A\n // transport is used as-is. `api` is undefined only for a transport binding.\n let api: string | undefined\n if (typeof binding === 'string') api = binding\n else if (isAgentHandle(binding)) api = binding.path\n // Identity is the binding (a handle's path OR a transport instance) — a stable key for the memo.\n const bindingIdentity = api ?? binding\n\n const client = useMemo(\n () =>\n new AgentClient<TInput>(\n api !== undefined\n ? new HttpTransport({\n api,\n headers: () => optionsRef.current.headers,\n fetch: optionsRef.current.fetch,\n })\n : (binding as AgentTransport),\n // M43 — resolve context live from the ref each send/reconnect (never stale). A value or a resolver.\n () => {\n const ctx = optionsRef.current.context\n return typeof ctx === 'function' ? ctx() : ctx\n },\n ),\n // bindingIdentity captures api/binding; options resolve live via optionsRef (rebuild would drop messages).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [bindingIdentity],\n )\n\n const state = useSyncExternalStore(client.subscribe, client.getSnapshot, client.getSnapshot)\n\n return {\n messages: state.messages,\n thread: state.thread,\n status: state.status,\n error: state.error,\n send: client.send,\n abort: client.abort,\n reset: client.reset,\n approve: client.approve,\n reconnect: client.reconnect,\n }\n}\n","import { ChannelTransport, type ChannelPushSource } from './channel-transport.js'\nimport { InProcessTransport, type InProcessRunner } from './in-process-transport.js'\n\n/**\n * M47 (ADR-M47-2) — a typed, client-safe handle for an exposed agent.\n *\n * It carries ONLY the HTTP `path` at runtime plus phantom `input`/`toolNames` types (never populated) — so\n * `useAgent(chat)` / `createAgentClient(chat…)` bind with NO magic string (the path is generated from the\n * `@Expose` exposure, not hand-typed) and NO duplicated input type (the input type flows through the phantom\n * generic, inferred from the agent's `.input()`). This mirrors tRPC/Hono's type-only handle: the client\n * pulls the agent's TYPE via `import type`, never its server runtime. The generated `@theo/agents` module\n * emits one `export const <name> = agentHandle('/api/agents/<name>')` per agent, typed with the phantoms.\n */\nexport interface AgentHandle<TInput = unknown, TToolNames extends string = string> {\n /** The agent's HTTP endpoint path (e.g. `/api/agents/chat`). The only serializable/runtime-bearing field. */\n readonly path: string\n /**\n * M47 — bind this agent in-process (TUI / single-process): wraps the app's runner in an\n * {@link InProcessTransport}. `useAgent(chat.inProcess(run))` drives the SAME agent without HTTP.\n */\n inProcess(run: InProcessRunner): InProcessTransport\n /**\n * M47 — bind this agent over a push channel (Tauri desktop webview): wraps the source in a\n * {@link ChannelTransport}. `createAgentClient(chat.channel(source))` drives the SAME agent.\n */\n channel(source: ChannelPushSource): ChannelTransport\n /** Phantom — the agent's `input` type, carried for `useAgent(handle).send` inference. Never populated. */\n readonly __input?: TInput\n /** Phantom — the agent's tool-name union, carried end-to-end. Never populated. */\n readonly __toolNames?: TToolNames\n}\n\n/**\n * Build an {@link AgentHandle} from an agent's HTTP path. Types are supplied by the caller/codegen. The\n * `inProcess`/`channel` binders are methods (dropped by `JSON.stringify`, so the `{ path }` core stays\n * serializable + client-safe) that produce the M41 transports for the non-web surfaces.\n */\nexport function agentHandle<TInput = unknown, TToolNames extends string = string>(\n path: string,\n): AgentHandle<TInput, TToolNames> {\n return {\n path,\n inProcess: (run) => new InProcessTransport({ run }),\n channel: (source) => new ChannelTransport({ source }),\n }\n}\n\n/** Narrow an unknown binding to an {@link AgentHandle} (has a string `path`, is not a transport). */\nexport function isAgentHandle(value: unknown): value is AgentHandle {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { path?: unknown }).path === 'string' &&\n typeof (value as { sendMessages?: unknown }).sendMessages !== 'function'\n )\n}\n","/**\n * <Link> — React Router Link with route prefetching.\n *\n * Wraps react-router's <Link> with prefetch behavior:\n * - `intent` (default): prefetch on hover + focus (~200ms before click)\n * - `viewport`: prefetch when visible (IntersectionObserver)\n * - `none`: no prefetch (same as plain react-router Link)\n *\n * Uses `<link rel=\"prefetch\">` (not modulepreload) because route paths\n * can be prefetched directly — no Vite manifest resolution needed (EC-1).\n */\nimport {\n Link as RouterLink,\n type LinkProps as RouterLinkProps,\n} from 'react-router'\nimport { useRef, useCallback, useEffect } from 'react'\n\nexport type PrefetchBehavior = 'none' | 'intent' | 'viewport'\n\nexport interface LinkProps extends RouterLinkProps {\n /** Prefetch strategy. Default: 'intent' (on hover + focus). */\n prefetch?: PrefetchBehavior\n}\n\n/** Deduplication — each URL prefetched at most once per session. */\nconst prefetched = new Set<string>()\n\nfunction injectPrefetch(href: string): void {\n // EC-2: SSR guard — document unavailable on server\n if (typeof document === 'undefined') return\n if (prefetched.has(href)) return\n prefetched.add(href)\n\n const link = document.createElement('link')\n link.rel = 'prefetch'\n link.href = href\n document.head.appendChild(link)\n}\n\nfunction resolveTo(to: LinkProps['to']): string {\n if (typeof to === 'string') return to\n return to?.pathname ?? ''\n}\n\n/**\n * TheoKit Link — drop-in replacement for react-router Link with prefetch.\n *\n * @example\n * ```tsx\n * import { Link } from 'theokit/client'\n *\n * <Link to=\"/contacts\">Contacts</Link>\n * <Link to=\"/dashboard\" prefetch=\"viewport\">Dashboard</Link>\n * <Link to=\"/settings\" prefetch=\"none\">Settings</Link>\n * ```\n */\nexport function Link({ prefetch = 'intent', to, onMouseEnter, onFocus, ...rest }: LinkProps) {\n const ref = useRef<HTMLAnchorElement>(null)\n\n const handleIntent = useCallback(\n (event: React.MouseEvent<HTMLAnchorElement> | React.FocusEvent<HTMLAnchorElement>) => {\n if (prefetch === 'intent') {\n injectPrefetch(resolveTo(to))\n }\n // Forward original handlers\n if (event.type === 'mouseenter' && onMouseEnter) {\n ;(onMouseEnter as React.MouseEventHandler<HTMLAnchorElement>)(event as React.MouseEvent<HTMLAnchorElement>)\n }\n if (event.type === 'focus' && onFocus) {\n ;(onFocus as React.FocusEventHandler<HTMLAnchorElement>)(event as React.FocusEvent<HTMLAnchorElement>)\n }\n },\n [prefetch, to, onMouseEnter, onFocus],\n )\n\n // Viewport mode: IntersectionObserver\n useEffect(() => {\n if (prefetch !== 'viewport' || !ref.current) return\n if (typeof IntersectionObserver === 'undefined') return // SSR guard\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n injectPrefetch(resolveTo(to))\n observer.disconnect()\n }\n },\n { rootMargin: '200px' }, // prefetch slightly before visible\n )\n observer.observe(ref.current)\n return () => observer.disconnect()\n }, [prefetch, to])\n\n return (\n <RouterLink\n ref={ref}\n to={to}\n onMouseEnter={handleIntent}\n onFocus={handleIntent}\n {...rest}\n />\n )\n}\n","/**\n * <Metadata> — SEO-ready head tags from a single component.\n *\n * Uses React 19's native <title>/<meta>/<link> hoisting to <head>.\n * No build-time extraction needed — works in SSR and client.\n *\n * @example\n * ```tsx\n * import { Metadata } from 'theokit/client'\n *\n * export default function ContactsPage() {\n * return (\n * <>\n * <Metadata\n * title=\"Contacts | My CRM\"\n * description=\"Manage your contacts\"\n * ogImage=\"/og/contacts.png\"\n * canonical=\"https://mycrm.com/contacts\"\n * />\n * <h1>Contacts</h1>\n * </>\n * )\n * }\n * ```\n */\n\nexport interface MetadataProps {\n title?: string\n description?: string\n canonical?: string\n ogTitle?: string\n ogDescription?: string\n ogImage?: string\n ogType?: string\n ogUrl?: string\n twitterCard?: 'summary' | 'summary_large_image'\n /** Custom meta tags rendered as children */\n children?: React.ReactNode\n}\n\nexport function Metadata(props: MetadataProps) {\n const ogTitle = props.ogTitle ?? props.title\n const ogDesc = props.ogDescription ?? props.description\n\n return (\n <>\n {props.title && <title>{props.title}</title>}\n {props.description && <meta name=\"description\" content={props.description} />}\n {props.canonical && <link rel=\"canonical\" href={props.canonical} />}\n {ogTitle && <meta property=\"og:title\" content={ogTitle} />}\n {ogDesc && <meta property=\"og:description\" content={ogDesc} />}\n {props.ogImage && <meta property=\"og:image\" content={props.ogImage} />}\n {props.ogType && <meta property=\"og:type\" content={props.ogType} />}\n {props.ogUrl && <meta property=\"og:url\" content={props.ogUrl} />}\n {props.twitterCard && <meta name=\"twitter:card\" content={props.twitterCard} />}\n {props.children}\n </>\n )\n}\n","/**\n * <Image> — optimized image component with lazy loading.\n *\n * Renders a standard <img> with:\n * - loading=\"lazy\" by default (eager with priority={true})\n * - decoding=\"async\" for non-blocking decode\n * - width/height for CLS prevention\n * - srcSet/sizes forwarded for responsive images\n *\n * No CDN, no Sharp, no build-time optimization — pure HTML attributes\n * that deliver 80% of the performance value at zero complexity.\n *\n * @example\n * ```tsx\n * import { Image } from 'theokit/client'\n *\n * <Image src=\"/team.jpg\" alt=\"Team photo\" width={800} height={600} />\n * <Image src=\"/hero.jpg\" alt=\"Hero\" priority />\n * <Image\n * src=\"/product.jpg\"\n * alt=\"Product\"\n * width={400}\n * height={300}\n * srcSet=\"/product-400.jpg 400w, /product-800.jpg 800w\"\n * sizes=\"(max-width: 768px) 100vw, 400px\"\n * />\n * ```\n */\n\nexport interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n /** Image source URL (required). */\n src: string\n /** Alt text for accessibility (required). */\n alt: string\n /** If true, loading=\"eager\" — use for above-the-fold images. */\n priority?: boolean\n}\n\nexport function Image({ priority, loading, decoding, ...props }: ImageProps) {\n return (\n <img\n loading={loading ?? (priority ? 'eager' : 'lazy')}\n decoding={decoding ?? 'async'}\n {...props}\n />\n )\n}\n","/**\n * M30 (ADR-0041) — client host for MCP App `ui://` resources.\n *\n * Renders a tool's `ui://` HTML in a SANDBOXED iframe and bridges a capability-scoped guest API over\n * `postMessage`. Security is load-bearing:\n * - the iframe is `sandbox=\"allow-scripts\"` ONLY — NOT `allow-same-origin`, so the guest runs at a\n * null origin and cannot touch the parent DOM, cookies, or storage;\n * - the host only honors messages whose `source` is the iframe's own `contentWindow`;\n * - the guest API is a fixed, capability-scoped vocabulary (`callServerTool`, `sendMessage`) — any\n * other message type is ignored.\n */\n\n/** The guest → host message vocabulary (capability-scoped). */\nexport type GuestMessage =\n | { type: 'callServerTool'; id: string; tool: string; args?: unknown }\n | { type: 'sendMessage'; text: string }\n\n/** Callbacks the host wires for the guest API. */\nexport interface McpAppHostOptions {\n /** Guest asked to call a server tool — return its result (posted back to the guest by id). */\n onCallServerTool: (tool: string, args: unknown) => unknown\n /** Guest emitted a chat message to the host app. */\n onSendMessage?: (text: string) => void\n}\n\n/**\n * Pure bridge: interpret one guest message and (for `callServerTool`) post the result back via\n * `post`. Exported for unit testing without a DOM. Unknown message shapes are ignored — the guest\n * API is capability-scoped, not an open RPC surface.\n */\nexport function createGuestMessageHandler(\n opts: McpAppHostOptions,\n post: (message: unknown) => void,\n): (data: unknown) => Promise<void> {\n return async (data: unknown): Promise<void> => {\n if (typeof data !== 'object' || data === null) return\n const msg = data as Partial<GuestMessage> & { type?: string }\n if (\n msg.type === 'callServerTool' &&\n typeof msg.id === 'string' &&\n typeof msg.tool === 'string'\n ) {\n const result = await opts.onCallServerTool(msg.tool, msg.args)\n post({ type: 'callServerTool:result', id: msg.id, result })\n return\n }\n if (msg.type === 'sendMessage' && typeof (msg as { text?: unknown }).text === 'string') {\n opts.onSendMessage?.((msg as { text: string }).text)\n }\n }\n}\n\n/** Handle returned by {@link mountMcpApp}. */\nexport interface McpAppHandle {\n iframe: HTMLIFrameElement\n /** Remove the message listener and the iframe. */\n dispose: () => void\n}\n\n/** The sandbox tokens the guest iframe is allowed — scripts only, NEVER `allow-same-origin`. */\nexport const MCP_APP_SANDBOX = 'allow-scripts'\n\n/**\n * Mount an MCP App resource's HTML in a sandboxed iframe inside `container`, wiring the guest API.\n * The HTML comes from `resources/read` (see `mcp-app-resources.ts`). Returns a handle to dispose.\n */\nexport function mountMcpApp(\n container: HTMLElement,\n resource: { html: string },\n opts: McpAppHostOptions,\n): McpAppHandle {\n const iframe = container.ownerDocument.createElement('iframe')\n // Security: scripts only, null origin. Do NOT add allow-same-origin.\n iframe.setAttribute('sandbox', MCP_APP_SANDBOX)\n iframe.srcdoc = resource.html\n container.appendChild(iframe)\n\n const post = (message: unknown): void => {\n // The guest is a sandboxed srcdoc iframe (allow-scripts, NO allow-same-origin) → its origin is\n // the opaque string \"null\", which cannot be used as a reliable targetOrigin. '*' is the only\n // valid target for a null-origin sandboxed guest; the sandbox (no navigation, no same-origin)\n // is what prevents a cross-origin leak, not the targetOrigin string.\n // eslint-disable-next-line sonarjs/post-message -- sandboxed null-origin iframe: '*' is correct\n iframe.contentWindow?.postMessage(message, '*')\n }\n const handle = createGuestMessageHandler(opts, post)\n\n const onMessage = (event: MessageEvent): void => {\n // Only trust messages from THIS iframe's guest window.\n if (event.source !== iframe.contentWindow) return\n void handle(event.data)\n }\n const view = container.ownerDocument.defaultView\n view?.addEventListener('message', onMessage)\n\n return {\n iframe,\n dispose: () => {\n view?.removeEventListener('message', onMessage)\n iframe.remove()\n },\n }\n}\n"],"mappings":"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","names":["useRef","jsx","jsx"]}
1
+ {"version":3,"sources":["../../src/client/theo-fetch.ts","../../src/client/batch.ts","../../src/client/batch-transport.ts","../../src/client/app-client.ts","../../src/client/use-agent.ts","../../src/client/agent-handle.ts","../../src/client/link.tsx","../../src/client/metadata.tsx","../../src/client/image.tsx","../../src/client/mcp-app-host.ts"],"sourcesContent":["import superjson from 'superjson'\nimport type { z } from 'zod'\n\nimport type { TheoErrorCode, TheoErrorEnvelope } from '../core/contracts/error-envelope.js'\n\nimport { getGlobalBatcher } from './batch-transport.js'\n\n// --- Transformer (T1.3) ---\n\n/**\n * Module-scoped flag preventing the transformer-mismatch warning from\n * firing more than once per session (EC-6).\n */\nlet mismatchWarned = false\n\n/** Test-only helper to reset the warned flag between assertions. */\nexport function __resetMismatchWarningForTests(): void {\n mismatchWarned = false\n}\n\n/**\n * Deserialize a fetch response body according to the negotiated transformer.\n *\n * `serverTransformerName` comes from the `x-theo-transformer` response header\n * (null when absent — server is using the default JSON path).\n * `clientTransformerName` is the transformer the client was built with\n * (typically injected via a Vite virtual module; falls back to `'json'`).\n *\n * Mismatch fires a single console.warn and falls back to JSON.parse (EC-5/EC-6).\n */\nexport function deserializeFetchResponse(\n raw: string,\n serverTransformerName: string | null,\n clientTransformerName: string,\n): unknown {\n // `raw` is typed `string`, but stay defensive: callers pass `await response.text()`\n // which can be empty.\n if (raw === '') {\n return null\n }\n\n const serverEffective = serverTransformerName ?? 'json'\n if (serverEffective !== clientTransformerName && !mismatchWarned) {\n mismatchWarned = true\n console.warn(\n `[theokit] transformer mismatch: server=${serverEffective}, client=${clientTransformerName}. Falling back to JSON.parse.`,\n )\n }\n\n if (serverEffective === 'superjson' && clientTransformerName === 'superjson') {\n const wrapped = JSON.parse(raw) as Parameters<typeof superjson.deserialize>[0]\n return superjson.deserialize(wrapped)\n }\n\n // Default path (json) or mismatch fallback\n return JSON.parse(raw)\n}\n\n// --- Utility Types ---\n\n/** Infer the response type from a route's handler return */\nexport type InferResponse<T> = T extends { handler: (...args: never[]) => infer R }\n ? Awaited<R>\n : unknown\n\n/** Extract the query Zod schema type, handling optional properties */\ntype ExtractQuery<T> = T extends { query?: infer Q } ? (Q extends z.ZodType ? Q : never) : never\n\n/** Extract the body Zod schema type, handling optional properties */\ntype ExtractBody<T> = T extends { body?: infer B } ? (B extends z.ZodType ? B : never) : never\n\n/** Infer query type from a route's query Zod schema */\nexport type InferQuery<T> = [ExtractQuery<T>] extends [never]\n ? undefined\n : ExtractQuery<T> extends z.ZodUndefined\n ? undefined\n : z.infer<ExtractQuery<T>>\n\n/** Infer body type from a route's body Zod schema */\nexport type InferBody<T> = [ExtractBody<T>] extends [never]\n ? undefined\n : ExtractBody<T> extends z.ZodUndefined\n ? undefined\n : z.infer<ExtractBody<T>>\n\n/** Build the options type based on what schemas the route has */\nexport type TheoFetchOptions<T> = Omit<RequestInit, 'body' | 'method'> &\n (InferQuery<T> extends undefined ? { query?: never } : { query: InferQuery<T> }) &\n (InferBody<T> extends undefined ? { body?: never } : { body: InferBody<T> })\n\n// --- Error Class ---\n\n/**\n * G5 T2.1 — extract a TheoErrorEnvelope from a response body. Supports both\n * the new envelope-at-root shape (`{ code, message, ext?, ... }`, blueprint\n * Recommendations § concrete shape) and the legacy nested shape\n * (`{ error: { code, message, issues? } }`, G3 SerializedActionResult).\n *\n * Falls back to `INTERNAL_SERVER_ERROR` with a synthetic message when the\n * body shape is unrecognized. Pure; no I/O.\n */\nfunction extractEnvelope(status: number, body: unknown): TheoErrorEnvelope {\n if (!body || typeof body !== 'object') {\n return { code: 'INTERNAL_SERVER_ERROR', message: `HTTP ${String(status)}` }\n }\n const obj = body as Record<string, unknown>\n // New shape — envelope at root\n if (typeof obj.code === 'string' && typeof obj.message === 'string') {\n return {\n code: obj.code as TheoErrorCode,\n message: obj.message,\n cause: obj.cause,\n meta: obj.meta as Record<string, unknown> | undefined,\n ext: obj.ext,\n }\n }\n // Legacy shape — { error: { code, message, ... } }\n if (obj.error && typeof obj.error === 'object') {\n const nested = obj.error as Record<string, unknown>\n return {\n code:\n typeof nested.code === 'string' ? (nested.code as TheoErrorCode) : 'INTERNAL_SERVER_ERROR',\n message: typeof nested.message === 'string' ? nested.message : `HTTP ${String(status)}`,\n }\n }\n return { code: 'INTERNAL_SERVER_ERROR', message: `HTTP ${String(status)}` }\n}\n\n/**\n * Pull a single string field from an object, returning undefined if missing\n * or non-string. Helper for `extractLegacyFields` to stay under the\n * complexity ceiling.\n */\nfunction strField(obj: Record<string, unknown> | null, key: string): string | undefined {\n const v = obj?.[key]\n return typeof v === 'string' ? v : undefined\n}\n\n/**\n * Pull the canonical {message, code, issues} from either an envelope-at-root\n * body or the legacy { error: {...} } body. Pure.\n */\nfunction extractLegacyFields(\n status: number,\n body: unknown,\n): { message: string; code?: string; issues?: unknown[] } {\n if (!body || typeof body !== 'object') {\n return { message: `HTTP ${String(status)}` }\n }\n const obj = body as Record<string, unknown>\n const nested =\n obj.error && typeof obj.error === 'object' ? (obj.error as Record<string, unknown>) : null\n const issues = Array.isArray(nested?.issues) ? nested.issues : undefined\n return {\n message: strField(obj, 'message') ?? strField(nested, 'message') ?? `HTTP ${String(status)}`,\n code: strField(obj, 'code') ?? strField(nested, 'code'),\n issues,\n }\n}\n\nexport class TheoFetchError extends Error {\n status: number\n code?: string\n issues?: unknown[]\n /**\n * G5 T2.1 — canonical envelope view of the server-side error. Use this in\n * consumer code that wants to switch on a typed TheoErrorCode instead of\n * coupling to the legacy `.status` / `.code` flat fields.\n */\n readonly envelope: TheoErrorEnvelope\n\n constructor(status: number, body?: unknown) {\n const legacy = extractLegacyFields(status, body)\n super(legacy.message)\n this.name = 'TheoFetchError'\n this.status = status\n this.code = legacy.code\n this.issues = legacy.issues\n this.envelope = extractEnvelope(status, body)\n }\n}\n\n/**\n * Serialize a query-param value to a string. Handles primitives, dates,\n * and falls back to JSON for arrays/objects. Avoids the\n * `[object Object]` foot-gun that `no-base-to-string` warns against.\n */\nfunction stringifyQueryValue(value: unknown): string {\n if (value === null) return 'null'\n if (value instanceof Date) return value.toISOString()\n switch (typeof value) {\n case 'string':\n return value\n case 'number':\n case 'boolean':\n case 'bigint':\n return String(value)\n default:\n return JSON.stringify(value)\n }\n}\n\n// --- Main Function ---\n\ninterface TheoFetchInternalOptions {\n method?: string\n query?: Record<string, unknown>\n body?: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\n/**\n * Resolve the request origin per the documented fallback hierarchy. Pure\n * helper extracted to keep `theoFetch` under the complexity ceiling.\n * 1. `globalThis.location.origin` (browser)\n * 2. `globalThis.__THEO_ORIGIN__` (build-time literal)\n * 3. `process.env.THEO_ORIGIN` (escape hatch)\n * 4. `http://localhost` (placeholder for URL parsing — the URL is built\n * relative so only pathname+search ever flows to the wire)\n */\nfunction resolveRequestOrigin(): string {\n const g = globalThis as { location?: { origin?: string }; __THEO_ORIGIN__?: string }\n const fromEnv = typeof process !== 'undefined' ? process.env.THEO_ORIGIN : undefined\n return g.location?.origin ?? g.__THEO_ORIGIN__ ?? fromEnv ?? 'http://localhost'\n}\n\nfunction buildFetchUrl(path: string, query: Record<string, unknown> | undefined): URL {\n const fetchUrl = new URL(path, resolveRequestOrigin())\n if (!query) return fetchUrl\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined) {\n fetchUrl.searchParams.set(k, stringifyQueryValue(v))\n }\n }\n return fetchUrl\n}\n\n/**\n * Normalize `HeadersInit` (Headers / `[string, string][]` / Record) into a\n * single plain `Record<string, string>`. Plain-object output is required\n * by callers that introspect headers via index access (test fixtures use\n * `(init.headers as Record<string, string>)['Content-Type']`).\n */\nfunction normalizeHeaders(input: HeadersInit | undefined): Record<string, string> {\n const out: Record<string, string> = {}\n if (!input) return out\n if (input instanceof Headers) {\n input.forEach((value, key) => {\n out[key] = value\n })\n return out\n }\n if (Array.isArray(input)) {\n for (const [key, value] of input) out[key] = value\n return out\n }\n for (const [key, value] of Object.entries(input)) {\n out[key] = value\n }\n return out\n}\n\nfunction buildRequestInit(opts: TheoFetchInternalOptions): RequestInit {\n const init: RequestInit = {}\n if (opts.method !== undefined) init.method = opts.method\n if (opts.signal !== undefined) init.signal = opts.signal\n\n const headers = normalizeHeaders(opts.headers)\n init.headers = headers\n\n if (opts.body !== undefined) {\n init.body = JSON.stringify(opts.body)\n headers['Content-Type'] = 'application/json'\n }\n\n // Phase 5 — Auto-attach `X-Theo-Action: 1` for state-mutating methods so\n // the framework's CSRF check passes when servers run in `strict` mode.\n // Safe methods (GET/HEAD/OPTIONS) skip the header to keep them cacheable.\n const method = (opts.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS') {\n headers['X-Theo-Action'] = '1'\n }\n return init\n}\n\nasync function tryBatcher(\n url: string,\n options: TheoFetchInternalOptions,\n): Promise<{ matched: true; result: unknown } | { matched: false }> {\n const batcher = getGlobalBatcher()\n if (!batcher) return { matched: false }\n try {\n const result = await batcher.dispatch({\n path: url,\n method: options.method ?? 'GET',\n query: options.query,\n body: options.body,\n })\n return { matched: true, result }\n } catch {\n // Batcher failure: fall through to direct fetch (graceful degrade).\n return { matched: false }\n }\n}\n\nexport async function theoFetch<T>(\n url: string,\n options?: TheoFetchOptions<T>,\n): Promise<InferResponse<T>> {\n const internal = (options ?? {}) as unknown as TheoFetchInternalOptions\n\n // T1.5 — Transparent batching when globalThis.__THEO_BATCHING__ is truthy.\n const batchAttempt = await tryBatcher(url, internal)\n if (batchAttempt.matched) {\n return batchAttempt.result as InferResponse<T>\n }\n\n const fetchUrl = buildFetchUrl(url, internal.query)\n const init = buildRequestInit(internal)\n const response = await fetch(fetchUrl.toString(), init)\n\n if (!response.ok) {\n let errorBody: unknown\n try {\n errorBody = await response.json()\n } catch {\n // Non-JSON error response\n }\n throw new TheoFetchError(response.status, errorBody)\n }\n\n // Handle 204 No Content (EC-1)\n if (response.status === 204) {\n return null as InferResponse<T>\n }\n\n // Check for empty body\n const contentLength = response.headers.get('content-length')\n if (contentLength === '0') {\n return null as InferResponse<T>\n }\n\n // T1.3 — transformer-aware deserialization\n const serverTransformerName = response.headers.get('x-theo-transformer')\n const clientTransformerName = resolveClientTransformerName()\n const text = await response.text()\n return deserializeFetchResponse(\n text,\n serverTransformerName,\n clientTransformerName,\n ) as InferResponse<T>\n}\n\n/**\n * Read the client-configured transformer name. Default `'json'`.\n *\n * In a Vite build, this is overridden by virtual module\n * `/@theo/runtime-config` which sets `globalThis.__THEO_TRANSFORMER__`.\n * Outside Vite (Node SSR, tests) the default applies.\n */\nfunction resolveClientTransformerName(): string {\n const g = globalThis as { __THEO_TRANSFORMER__?: string }\n return g.__THEO_TRANSFORMER__ ?? 'json'\n}\n","/**\n * T5.1 — client-side microtask batching.\n *\n * Collects all `dispatch` calls within the same microtask and sends them as a\n * single HTTP POST to the configured transport. Each caller's promise resolves\n * with its own result; one failed item does not break the others (per-item\n * error isolation).\n *\n * Designed as a transport-agnostic primitive so unit tests do not require\n * network access. The default transport (fetch to `/api/__theo_batch__`)\n * lives alongside this module but is created by the consumer (e.g., theoFetch).\n */\n\nexport interface BatchRequest {\n path: string\n method: string\n query?: Record<string, unknown>\n body?: unknown\n headers?: Record<string, string>\n}\n\nexport type BatchResponse =\n | { index: number; data: unknown }\n | { index: number; error: { message: string; code?: string } }\n\nexport type BatchTransport = (requests: BatchRequest[]) => Promise<BatchResponse[]>\n\nexport interface BatcherOptions {\n transport: BatchTransport\n /** Maximum batch size before flushing into multiple parallel batches. */\n max?: number\n}\n\nexport interface Batcher {\n dispatch(req: BatchRequest): Promise<unknown>\n}\n\ninterface PendingCall {\n req: BatchRequest\n resolve: (value: unknown) => void\n reject: (reason: unknown) => void\n}\n\nexport function createBatcher(options: BatcherOptions): Batcher {\n const max = options.max ?? 32\n let queue: PendingCall[] = []\n let flushScheduled = false\n\n function flush(): void {\n flushScheduled = false\n const current = queue\n queue = []\n if (current.length === 0) return\n\n // Split into chunks respecting max\n const chunks: PendingCall[][] = []\n for (let i = 0; i < current.length; i += max) {\n chunks.push(current.slice(i, i + max))\n }\n\n for (const chunk of chunks) {\n const payload: BatchRequest[] = chunk.map((p) => p.req)\n options\n .transport(payload)\n .then((results) => {\n for (let i = 0; i < chunk.length; i++) {\n // `results[i]` could be undefined at runtime when the transport\n // returns fewer entries than the chunk; TypeScript's strict\n // typing without `noUncheckedIndexedAccess` does not surface\n // this, so we hand-narrow.\n const result = results.length > i ? results[i] : undefined\n if (result === undefined) {\n chunk[i].reject(new Error(`Batch transport returned no result for index ${i}`))\n continue\n }\n if ('error' in result) {\n const err = new Error(result.error.message)\n ;(err as { code?: string }).code = result.error.code\n chunk[i].reject(err)\n } else {\n chunk[i].resolve(result.data)\n }\n }\n })\n .catch((err: unknown) => {\n for (const item of chunk) item.reject(err)\n })\n }\n }\n\n return {\n dispatch(req: BatchRequest): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n queue.push({ req, resolve, reject })\n if (!flushScheduled) {\n flushScheduled = true\n queueMicrotask(flush)\n }\n })\n },\n }\n}\n","/**\n * T1.5 — Default HTTP transport for the client batcher.\n *\n * Wraps `fetch` to POST `/api/__theo_batch__` with the collected requests\n * and return the array of per-item results.\n */\n\nimport {\n createBatcher,\n type BatchTransport,\n type Batcher,\n type BatchRequest,\n type BatchResponse,\n} from './batch.js'\n\nconst BATCH_ENDPOINT = '/api/__theo_batch__'\n\ninterface CreateBatchTransportOptions {\n /** Override fetch (default: globalThis.fetch). Used by tests. */\n fetchImpl?: typeof fetch\n /** Override endpoint (default '/api/__theo_batch__'). */\n endpoint?: string\n}\n\nexport function createBatchTransport(options: CreateBatchTransportOptions = {}): BatchTransport {\n const fetchImpl = options.fetchImpl ?? fetch\n const endpoint = options.endpoint ?? BATCH_ENDPOINT\n return async (requests: BatchRequest[]): Promise<BatchResponse[]> => {\n const response = await fetchImpl(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ requests }),\n })\n if (!response.ok) {\n throw new Error(`Batch transport returned ${response.status}`)\n }\n const payload = (await response.json()) as { results?: BatchResponse[] }\n if (!Array.isArray(payload.results)) {\n throw new Error('Batch response missing results array')\n }\n // Map results to indexed BatchResponse shape (server already returns the right form)\n return payload.results.map((item, index) => {\n if ('error' in item) {\n return { index, error: (item as { error: { message: string; code?: string } }).error }\n }\n return { index, data: (item as { data: unknown }).data }\n })\n }\n}\n\n// --- EC-7: singleton batcher per page, lazy-instantiated ---\n\nlet globalBatcher: Batcher | undefined\n\n/** Test-only — reset the module-scope singleton between assertions. */\nexport function __resetGlobalBatcherForTests(): void {\n globalBatcher = undefined\n}\n\n/**\n * Returns the global batcher singleton when `globalThis.__THEO_BATCHING__` is\n * truthy; undefined otherwise. Lazy-instantiated on first call.\n */\nexport function getGlobalBatcher(): Batcher | undefined {\n const g = globalThis as { __THEO_BATCHING__?: boolean }\n if (!g.__THEO_BATCHING__) return undefined\n globalBatcher ??= createBatcher({ transport: createBatchTransport() })\n return globalBatcher\n}\n","/**\n * Phase 3 of G1 (g1-client-codegen-plan.md):\n *\n * `createAppClient(baseUrl?, fetchImpl?)` returns a Proxy that walks property\n * access (`client.posts.id.get(...)`) into a `theoFetch` invocation against\n * `{baseUrl}/posts/{params.id}` with method `GET`.\n *\n * Type safety is delivered by the `.d.ts` file emitted in Phase 2 — this\n * runtime is structurally untyped. Power users may use `theoFetch` directly\n * when they need to escape the Proxy facade.\n *\n * Edge cases absorbed:\n * - EC-1 (thenable trap): `then` / `catch` / `finally` / `toJSON` / `Symbol.*`\n * return `undefined` so that accidental `await client.posts` resolves to a\n * plain Proxy value (it is NOT thenable) instead of looping.\n * - EC-7 (abort signal): `opts.signal` is spread through to the underlying\n * fetchImpl unchanged — verified in unit tests.\n *\n * Bundle target: ≤ 2KB gzipped.\n */\n\nimport { HTTP_METHOD_LOWERCASE } from '../core/contracts/http-methods.js'\n\nimport { theoFetch, TheoFetchError } from './theo-fetch.js'\nimport type { TheoFetchOptions } from './theo-fetch.js'\n\nconst HTTP_METHODS_SET = new Set(HTTP_METHOD_LOWERCASE)\n\n/**\n * Keys that JavaScript runtime / inspectors / Promise resolution probe\n * unconditionally. Returning `undefined` for these keeps the Proxy from\n * pretending to be a thenable / iterable / serializable thing.\n */\nconst NON_INTERCEPT_KEYS = new Set([\n 'then',\n 'catch',\n 'finally',\n 'toJSON',\n 'toString',\n 'valueOf',\n 'constructor',\n 'prototype',\n])\n\ntype FetchImpl = typeof theoFetch\n\ninterface CallOptions {\n params?: Record<string, string | number>\n query?: Record<string, unknown>\n body?: unknown\n signal?: AbortSignal\n headers?: HeadersInit\n // arbitrary RequestInit fields (mode, credentials, cache, etc.)\n [k: string]: unknown\n}\n\nfunction injectParams(path: string, params?: Record<string, string | number>): string {\n if (!params) {\n if (/:(?:\\.\\.\\.)?[A-Za-z_]/.test(path)) {\n throw new TheoFetchError(0, {\n error: {\n code: 'MISSING_PARAM',\n message: `Route ${path} requires params but none were provided. Pass them via opts.params, e.g. client.posts.get({ params: { id: '123' } }).`,\n },\n })\n }\n return path\n }\n return path.replace(/:(?:\\.\\.\\.)?([A-Za-z_]\\w*)/g, (_match, key: string) => {\n const value = params[key]\n // `params` is typed as fully-populated, but it crosses a runtime boundary (a caller may hand\n // it raw JSON), so the emptiness guard stays. Narrowed to the check the type cannot rule out.\n if (value === '') {\n throw new TheoFetchError(0, {\n error: {\n code: 'MISSING_PARAM',\n message: `Param '${key}' is required for path '${path}' but was missing/empty.`,\n },\n })\n }\n return encodeURIComponent(String(value))\n })\n}\n\ninterface ProxyContext {\n segments: string[]\n baseUrl: string\n fetchImpl: FetchImpl\n}\n\nfunction makeProxy(ctx: ProxyContext): unknown {\n const handler: ProxyHandler<() => void> = {\n get(_target, key) {\n if (typeof key !== 'string') return undefined\n if (NON_INTERCEPT_KEYS.has(key)) return undefined\n if (HTTP_METHODS_SET.has(key)) {\n return async (opts?: CallOptions) => {\n if (ctx.segments.length === 0) {\n throw new TheoFetchError(0, {\n error: {\n code: 'INVALID_PATH',\n message: `client.${key}() called without a route segment. Use client.<resource>.${key}(...) instead.`,\n },\n })\n }\n let finalPath = `${ctx.baseUrl}/${ctx.segments.join('/')}`\n if (opts?.params) {\n // Build a path with `:name` placeholders re-inserted from segments\n // whose name matches a key in opts.params (treat as dynamic).\n const segmentsWithDynamic = ctx.segments.map((seg) =>\n Object.prototype.hasOwnProperty.call(opts.params, seg) ? `:${seg}` : seg,\n )\n finalPath = injectParams(`${ctx.baseUrl}/${segmentsWithDynamic.join('/')}`, opts.params)\n }\n const { params: _ignored, ...rest } = opts ?? {}\n const init = {\n method: key.toUpperCase(),\n ...rest,\n } as unknown as TheoFetchOptions<unknown>\n return ctx.fetchImpl(finalPath, init)\n }\n }\n // Continue traversal — append segment to the path.\n return makeProxy({ ...ctx, segments: [...ctx.segments, key] })\n },\n apply() {\n return Promise.reject(\n new TheoFetchError(0, {\n error: {\n code: 'INVALID_CALL',\n message:\n 'client(...) is not callable. Use client.<resource>.<method>(opts?) — e.g. client.posts.get().',\n },\n }),\n )\n },\n }\n return new Proxy(() => undefined, handler)\n}\n\nexport interface CreateAppClientOptions {\n /** Base URL for the API. Defaults to `/api`. */\n baseUrl?: string\n /** Test-only fetch override. Production callers should not pass this. */\n fetchImpl?: FetchImpl\n}\n\n// TAppClient is the caller-supplied shape of the generated client. It appears once by design — the\n// proxy is untyped at runtime — and removing it would force every call site to cast.\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- see above\nexport function createAppClient<TAppClient = unknown>(\n baseUrlOrOptions?: string | CreateAppClientOptions,\n legacyFetchImpl?: FetchImpl,\n): TAppClient {\n let baseUrl = '/api'\n let fetchImpl: FetchImpl = theoFetch\n if (typeof baseUrlOrOptions === 'string') {\n baseUrl = baseUrlOrOptions || '/api'\n } else if (baseUrlOrOptions && typeof baseUrlOrOptions === 'object') {\n if (baseUrlOrOptions.baseUrl) baseUrl = baseUrlOrOptions.baseUrl\n if (baseUrlOrOptions.fetchImpl) fetchImpl = baseUrlOrOptions.fetchImpl\n }\n // Legacy 2nd-arg fetchImpl overrides regardless of 1st-arg shape (test seam).\n if (legacyFetchImpl) fetchImpl = legacyFetchImpl\n // Strip trailing slash for predictable joining.\n if (baseUrl.length > 1 && baseUrl.endsWith('/')) baseUrl = baseUrl.slice(0, -1)\n return makeProxy({ segments: [], baseUrl, fetchImpl }) as TAppClient\n}\n","import type { UIMessage } from 'ai'\nimport { useMemo, useRef, useSyncExternalStore } from 'react'\n\nimport { AgentClient, type UseAgentStatus } from './agent-client.js'\nimport { type AgentHandle, isAgentHandle } from './agent-handle.js'\nimport { HttpTransport } from './http-transport.js'\nimport type { AgentTransport, ApprovalDecision, RequestContext } from './transport.js'\n\n/**\n * M2 (theokit-ai-first) / M41 (ADR-0050) — `useAgent`, the ONE typed client hook for the\n * `agents/*.ts` convention, unified across surfaces.\n *\n * Pass an endpoint path (web) OR an {@link AgentTransport} (terminal/desktop). A string is wrapped in\n * an {@link HttpTransport} (exact back-compat with the pre-M41 fetch+SSE hook); an `InProcessTransport`\n * drives the SAME hook in a single process. The hook is a thin binding over the framework-agnostic\n * {@link AgentClient} store via React's native `useSyncExternalStore` (no test-DOM dependency). The\n * generated `@theo/agents` module types `send` to the agent's `input` schema — inferred end-to-end\n * from the server `defineAgent({ input })` with ZERO manual wiring.\n */\nexport type { UseAgentStatus }\n\nexport interface UseAgentReturn<TInput = unknown, TToolNames extends string = string> {\n /** The CURRENT turn's assistant messages (per-turn; reset each `send`). Back-compat since M41. */\n messages: UIMessage[]\n /**\n * M46 — the full conversation to render: committed turns + the current turn's user + in-flight\n * assistant, accumulated across sends with stable ids. Prefer this over hand-rolling a transcript\n * from `messages`. Same shape on every surface (web/desktop/TUI) — it lives in the core store.\n */\n thread: UIMessage[]\n status: UseAgentStatus\n /** The last error, or `undefined`. */\n error: Error | undefined\n /** Send a request; opens a new stream. Typed to the agent's `input` schema. */\n send: (input: TInput) => void\n /** Abort an in-flight stream. */\n abort: () => void\n /** Clear messages + error, back to idle. */\n reset: () => void\n /** Settle a paused HITL approval (HTTP `POST /approve/<id>` for web; the inline callback in-process). */\n approve: (approvalId: string, decision: ApprovalDecision) => Promise<void>\n /** Resume an interrupted stream (M37 durable transport for web; a no-op in-process). */\n reconnect: () => void\n /**\n * The union of tool names this agent can emit (M8), carried end-to-end from the `agent()` builder's\n * accumulated tool-name type through the generated `@theo/agents` client. Type-only witness (never\n * populated at runtime). Resolves to the literal union for builder agents, `string` otherwise.\n */\n readonly __toolNames?: TToolNames\n}\n\nexport interface UseAgentOptions {\n /**\n * Extra request headers (e.g., auth) — applied when a string path builds an `HttpTransport`. Read on\n * EVERY request, so a value that changes across renders (a rotating JWT) is never sent stale.\n */\n headers?: Record<string, string>\n /** Override fetch (primarily for tests) — captured when a string path builds an `HttpTransport`. */\n fetch?: typeof fetch\n /**\n * M43 — per-request context attached uniformly to EVERY transport (`headers` → HTTP request headers;\n * `metadata` → the in-process runner / Tauri invoke). A value OR a resolver evaluated on every\n * send/reconnect, so a rotating token/tenant is never stale.\n */\n context?: RequestContext | (() => RequestContext | undefined)\n}\n\n/**\n * Bind to an agent by endpoint path (`/api/agents/<name>`), by a typed {@link AgentHandle} (M47 — the\n * generated `chat` handle; kills the magic string + duplicated input type), or by an explicit\n * {@link AgentTransport}. Prefer the generated `useAgent` from `@theo/agents` (typed by agent name or\n * handle); this base accepts all three. The store is created once per binding identity — memoize a\n * transport before passing it.\n */\nexport function useAgent<TInput = unknown>(\n binding: string | AgentHandle<TInput> | AgentTransport,\n options: UseAgentOptions = {},\n): UseAgentReturn<TInput> {\n // Track the latest options so the built HttpTransport reads current headers per request (dynamic\n // auth is never stale) without rebuilding the store — which would drop in-flight messages.\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n // A handle resolves to its HTTP path; a string is already a path — both build an HttpTransport. A\n // transport is used as-is. `api` is undefined only for a transport binding.\n let api: string | undefined\n if (typeof binding === 'string') api = binding\n else if (isAgentHandle(binding)) api = binding.path\n // Identity is the binding (a handle's path OR a transport instance) — a stable key for the memo.\n const bindingIdentity = api ?? binding\n\n const client = useMemo(\n () =>\n new AgentClient<TInput>(\n api !== undefined\n ? new HttpTransport({\n api,\n headers: () => optionsRef.current.headers,\n fetch: optionsRef.current.fetch,\n })\n : (binding as AgentTransport),\n // M43 — resolve context live from the ref each send/reconnect (never stale). A value or a resolver.\n () => {\n const ctx = optionsRef.current.context\n return typeof ctx === 'function' ? ctx() : ctx\n },\n ),\n // bindingIdentity captures api/binding; options resolve live via optionsRef (rebuild would drop messages).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [bindingIdentity],\n )\n\n const state = useSyncExternalStore(client.subscribe, client.getSnapshot, client.getSnapshot)\n\n return {\n messages: state.messages,\n thread: state.thread,\n status: state.status,\n error: state.error,\n send: client.send,\n abort: client.abort,\n reset: client.reset,\n approve: client.approve,\n reconnect: client.reconnect,\n }\n}\n","import { ChannelTransport, type ChannelPushSource } from './channel-transport.js'\nimport { InProcessTransport, type InProcessRunner } from './in-process-transport.js'\n\n/**\n * M47 (ADR-M47-2) — a typed, client-safe handle for an exposed agent.\n *\n * It carries ONLY the HTTP `path` at runtime plus phantom `input`/`toolNames` types (never populated) — so\n * `useAgent(chat)` / `createAgentClient(chat…)` bind with NO magic string (the path is generated from the\n * `@Expose` exposure, not hand-typed) and NO duplicated input type (the input type flows through the phantom\n * generic, inferred from the agent's `.input()`). This mirrors tRPC/Hono's type-only handle: the client\n * pulls the agent's TYPE via `import type`, never its server runtime. The generated `@theo/agents` module\n * emits one `export const <name> = agentHandle('/api/agents/<name>')` per agent, typed with the phantoms.\n */\nexport interface AgentHandle<TInput = unknown, TToolNames extends string = string> {\n /** The agent's HTTP endpoint path (e.g. `/api/agents/chat`). The only serializable/runtime-bearing field. */\n readonly path: string\n /**\n * M47 — bind this agent in-process (TUI / single-process): wraps the app's runner in an\n * {@link InProcessTransport}. `useAgent(chat.inProcess(run))` drives the SAME agent without HTTP.\n */\n inProcess(run: InProcessRunner): InProcessTransport\n /**\n * M47 — bind this agent over a push channel (Tauri desktop webview): wraps the source in a\n * {@link ChannelTransport}. `createAgentClient(chat.channel(source))` drives the SAME agent.\n */\n channel(source: ChannelPushSource): ChannelTransport\n /** Phantom — the agent's `input` type, carried for `useAgent(handle).send` inference. Never populated. */\n readonly __input?: TInput\n /** Phantom — the agent's tool-name union, carried end-to-end. Never populated. */\n readonly __toolNames?: TToolNames\n}\n\n/**\n * Build an {@link AgentHandle} from an agent's HTTP path. Types are supplied by the caller/codegen. The\n * `inProcess`/`channel` binders are methods (dropped by `JSON.stringify`, so the `{ path }` core stays\n * serializable + client-safe) that produce the M41 transports for the non-web surfaces.\n */\nexport function agentHandle<TInput = unknown, TToolNames extends string = string>(\n path: string,\n): AgentHandle<TInput, TToolNames> {\n return {\n path,\n inProcess: (run) => new InProcessTransport({ run }),\n channel: (source) => new ChannelTransport({ source }),\n }\n}\n\n/** Narrow an unknown binding to an {@link AgentHandle} (has a string `path`, is not a transport). */\nexport function isAgentHandle(value: unknown): value is AgentHandle {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { path?: unknown }).path === 'string' &&\n typeof (value as { sendMessages?: unknown }).sendMessages !== 'function'\n )\n}\n","/**\n * <Link> — React Router Link with route prefetching.\n *\n * Wraps react-router's <Link> with prefetch behavior:\n * - `intent` (default): prefetch on hover + focus (~200ms before click)\n * - `viewport`: prefetch when visible (IntersectionObserver)\n * - `none`: no prefetch (same as plain react-router Link)\n *\n * Uses `<link rel=\"prefetch\">` (not modulepreload) because route paths\n * can be prefetched directly — no Vite manifest resolution needed (EC-1).\n */\nimport { useRef, useCallback, useEffect } from 'react'\nimport { Link as RouterLink, type LinkProps as RouterLinkProps } from 'react-router'\n\nexport type PrefetchBehavior = 'none' | 'intent' | 'viewport'\n\nexport interface LinkProps extends RouterLinkProps {\n /** Prefetch strategy. Default: 'intent' (on hover + focus). */\n prefetch?: PrefetchBehavior\n}\n\n/** Deduplication — each URL prefetched at most once per session. */\nconst prefetched = new Set<string>()\n\nfunction injectPrefetch(href: string): void {\n // EC-2: SSR guard — document unavailable on server\n if (typeof document === 'undefined') return\n if (prefetched.has(href)) return\n prefetched.add(href)\n\n const link = document.createElement('link')\n link.rel = 'prefetch'\n link.href = href\n document.head.appendChild(link)\n}\n\nfunction resolveTo(to: LinkProps['to']): string {\n if (typeof to === 'string') return to\n return to.pathname ?? ''\n}\n\n/**\n * TheoKit Link — drop-in replacement for react-router Link with prefetch.\n *\n * @example\n * ```tsx\n * import { Link } from 'theokit/client'\n *\n * <Link to=\"/contacts\">Contacts</Link>\n * <Link to=\"/dashboard\" prefetch=\"viewport\">Dashboard</Link>\n * <Link to=\"/settings\" prefetch=\"none\">Settings</Link>\n * ```\n */\nexport function Link({\n prefetch = 'intent',\n to,\n onMouseEnter,\n onFocus,\n ...rest\n}: Readonly<LinkProps>) {\n const ref = useRef<HTMLAnchorElement>(null)\n\n const handleIntent = useCallback(\n (event: React.MouseEvent<HTMLAnchorElement> | React.FocusEvent<HTMLAnchorElement>) => {\n if (prefetch === 'intent') {\n injectPrefetch(resolveTo(to))\n }\n // Forward original handlers\n if (event.type === 'mouseenter' && onMouseEnter) {\n onMouseEnter(event as React.MouseEvent<HTMLAnchorElement>)\n }\n if (event.type === 'focus' && onFocus) {\n onFocus(event as React.FocusEvent<HTMLAnchorElement>)\n }\n },\n [prefetch, to, onMouseEnter, onFocus],\n )\n\n // Viewport mode: IntersectionObserver\n useEffect(() => {\n if (prefetch !== 'viewport' || !ref.current) return\n if (typeof IntersectionObserver === 'undefined') return // SSR guard\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n injectPrefetch(resolveTo(to))\n observer.disconnect()\n }\n },\n { rootMargin: '200px' }, // prefetch slightly before visible\n )\n observer.observe(ref.current)\n return () => {\n observer.disconnect()\n }\n }, [prefetch, to])\n\n return (\n <RouterLink ref={ref} to={to} onMouseEnter={handleIntent} onFocus={handleIntent} {...rest} />\n )\n}\n","/**\n * <Metadata> — SEO-ready head tags from a single component.\n *\n * Uses React 19's native <title>/<meta>/<link> hoisting to <head>.\n * No build-time extraction needed — works in SSR and client.\n *\n * @example\n * ```tsx\n * import { Metadata } from 'theokit/client'\n *\n * export default function ContactsPage() {\n * return (\n * <>\n * <Metadata\n * title=\"Contacts | My CRM\"\n * description=\"Manage your contacts\"\n * ogImage=\"/og/contacts.png\"\n * canonical=\"https://mycrm.com/contacts\"\n * />\n * <h1>Contacts</h1>\n * </>\n * )\n * }\n * ```\n */\n\nexport interface MetadataProps {\n title?: string\n description?: string\n canonical?: string\n ogTitle?: string\n ogDescription?: string\n ogImage?: string\n ogType?: string\n ogUrl?: string\n twitterCard?: 'summary' | 'summary_large_image'\n /** Custom meta tags rendered as children */\n children?: React.ReactNode\n}\n\nexport function Metadata(props: MetadataProps) {\n const ogTitle = props.ogTitle ?? props.title\n const ogDesc = props.ogDescription ?? props.description\n\n return (\n <>\n {props.title && <title>{props.title}</title>}\n {props.description && <meta name=\"description\" content={props.description} />}\n {props.canonical && <link rel=\"canonical\" href={props.canonical} />}\n {ogTitle && <meta property=\"og:title\" content={ogTitle} />}\n {ogDesc && <meta property=\"og:description\" content={ogDesc} />}\n {props.ogImage && <meta property=\"og:image\" content={props.ogImage} />}\n {props.ogType && <meta property=\"og:type\" content={props.ogType} />}\n {props.ogUrl && <meta property=\"og:url\" content={props.ogUrl} />}\n {props.twitterCard && <meta name=\"twitter:card\" content={props.twitterCard} />}\n {props.children}\n </>\n )\n}\n","/**\n * <Image> — optimized image component with lazy loading.\n *\n * Renders a standard <img> with:\n * - loading=\"lazy\" by default (eager with priority={true})\n * - decoding=\"async\" for non-blocking decode\n * - width/height for CLS prevention\n * - srcSet/sizes forwarded for responsive images\n *\n * No CDN, no Sharp, no build-time optimization — pure HTML attributes\n * that deliver 80% of the performance value at zero complexity.\n *\n * @example\n * ```tsx\n * import { Image } from 'theokit/client'\n *\n * <Image src=\"/team.jpg\" alt=\"Team photo\" width={800} height={600} />\n * <Image src=\"/hero.jpg\" alt=\"Hero\" priority />\n * <Image\n * src=\"/product.jpg\"\n * alt=\"Product\"\n * width={400}\n * height={300}\n * srcSet=\"/product-400.jpg 400w, /product-800.jpg 800w\"\n * sizes=\"(max-width: 768px) 100vw, 400px\"\n * />\n * ```\n */\n\nexport interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n /** Image source URL (required). */\n src: string\n /** Alt text for accessibility (required). */\n alt: string\n /** If true, loading=\"eager\" — use for above-the-fold images. */\n priority?: boolean\n}\n\nexport function Image({ priority, loading, decoding, ...props }: ImageProps) {\n return (\n <img\n loading={loading ?? (priority ? 'eager' : 'lazy')}\n decoding={decoding ?? 'async'}\n {...props}\n />\n )\n}\n","/**\n * M30 (ADR-0041) — client host for MCP App `ui://` resources.\n *\n * Renders a tool's `ui://` HTML in a SANDBOXED iframe and bridges a capability-scoped guest API over\n * `postMessage`. Security is load-bearing:\n * - the iframe is `sandbox=\"allow-scripts\"` ONLY — NOT `allow-same-origin`, so the guest runs at a\n * null origin and cannot touch the parent DOM, cookies, or storage;\n * - the host only honors messages whose `source` is the iframe's own `contentWindow`;\n * - the guest API is a fixed, capability-scoped vocabulary (`callServerTool`, `sendMessage`) — any\n * other message type is ignored.\n */\n\n/** The guest → host message vocabulary (capability-scoped). */\nexport type GuestMessage =\n | { type: 'callServerTool'; id: string; tool: string; args?: unknown }\n | { type: 'sendMessage'; text: string }\n\n/** Callbacks the host wires for the guest API. */\nexport interface McpAppHostOptions {\n /** Guest asked to call a server tool — return its result (posted back to the guest by id). */\n onCallServerTool: (tool: string, args: unknown) => unknown\n /** Guest emitted a chat message to the host app. */\n onSendMessage?: (text: string) => void\n}\n\n/**\n * Pure bridge: interpret one guest message and (for `callServerTool`) post the result back via\n * `post`. Exported for unit testing without a DOM. Unknown message shapes are ignored — the guest\n * API is capability-scoped, not an open RPC surface.\n */\nexport function createGuestMessageHandler(\n opts: McpAppHostOptions,\n post: (message: unknown) => void,\n): (data: unknown) => Promise<void> {\n return async (data: unknown): Promise<void> => {\n if (typeof data !== 'object' || data === null) return\n const msg = data as Partial<GuestMessage> & { type?: string }\n if (\n msg.type === 'callServerTool' &&\n typeof msg.id === 'string' &&\n typeof msg.tool === 'string'\n ) {\n const result = await opts.onCallServerTool(msg.tool, msg.args)\n post({ type: 'callServerTool:result', id: msg.id, result })\n return\n }\n if (msg.type === 'sendMessage' && typeof (msg as { text?: unknown }).text === 'string') {\n opts.onSendMessage?.((msg as { text: string }).text)\n }\n }\n}\n\n/** Handle returned by {@link mountMcpApp}. */\nexport interface McpAppHandle {\n iframe: HTMLIFrameElement\n /** Remove the message listener and the iframe. */\n dispose: () => void\n}\n\n/** The sandbox tokens the guest iframe is allowed — scripts only, NEVER `allow-same-origin`. */\nexport const MCP_APP_SANDBOX = 'allow-scripts'\n\n/**\n * Mount an MCP App resource's HTML in a sandboxed iframe inside `container`, wiring the guest API.\n * The HTML comes from `resources/read` (see `mcp-app-resources.ts`). Returns a handle to dispose.\n */\nexport function mountMcpApp(\n container: HTMLElement,\n resource: { html: string },\n opts: McpAppHostOptions,\n): McpAppHandle {\n const iframe = container.ownerDocument.createElement('iframe')\n // Security: scripts only, null origin. Do NOT add allow-same-origin.\n iframe.setAttribute('sandbox', MCP_APP_SANDBOX)\n iframe.srcdoc = resource.html\n container.appendChild(iframe)\n\n const post = (message: unknown): void => {\n // The guest is a sandboxed srcdoc iframe (allow-scripts, NO allow-same-origin) → its origin is\n // the opaque string \"null\", which cannot be used as a reliable targetOrigin. '*' is the only\n // valid target for a null-origin sandboxed guest; the sandbox (no navigation, no same-origin)\n // is what prevents a cross-origin leak, not the targetOrigin string.\n // eslint-disable-next-line sonarjs/post-message -- sandboxed null-origin iframe: '*' is correct\n iframe.contentWindow?.postMessage(message, '*')\n }\n const handle = createGuestMessageHandler(opts, post)\n\n const onMessage = (event: MessageEvent): void => {\n // Only trust messages from THIS iframe's guest window.\n if (event.source !== iframe.contentWindow) return\n void handle(event.data)\n }\n const view = container.ownerDocument.defaultView\n view?.addEventListener('message', onMessage)\n\n return {\n iframe,\n dispose: () => {\n view?.removeEventListener('message', onMessage)\n iframe.remove()\n },\n }\n}\n"],"mappings":"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","names":["useRef","jsx","jsx"]}