@graphrefly/ts 0.0.0 → 0.0.2

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 (405) hide show
  1. package/README.md +135 -0
  2. package/dist/actions-types-CSC3NMDl.d.ts +657 -0
  3. package/dist/actions-types-wl9Mgkmr.d.cts +657 -0
  4. package/dist/adapters/index.cjs +5219 -2974
  5. package/dist/adapters/index.cjs.map +1 -1
  6. package/dist/adapters/index.d.cts +204 -192
  7. package/dist/adapters/index.d.ts +204 -192
  8. package/dist/adapters/index.js +3685 -1833
  9. package/dist/adapters/index.js.map +1 -1
  10. package/dist/adapters/nestjs/microservices.cjs +841 -0
  11. package/dist/adapters/nestjs/microservices.cjs.map +1 -0
  12. package/dist/adapters/nestjs/microservices.d.cts +45 -0
  13. package/dist/adapters/nestjs/microservices.d.ts +45 -0
  14. package/dist/adapters/nestjs/microservices.js +206 -0
  15. package/dist/adapters/nestjs/microservices.js.map +1 -0
  16. package/dist/adapters/nestjs/native.cjs +1391 -0
  17. package/dist/adapters/nestjs/native.cjs.map +1 -0
  18. package/dist/adapters/nestjs/native.d.cts +111 -0
  19. package/dist/adapters/nestjs/native.d.ts +111 -0
  20. package/dist/adapters/nestjs/native.js +577 -0
  21. package/dist/adapters/nestjs/native.js.map +1 -0
  22. package/dist/adapters/nestjs/websockets.cjs +924 -0
  23. package/dist/adapters/nestjs/websockets.cjs.map +1 -0
  24. package/dist/adapters/nestjs/websockets.d.cts +47 -0
  25. package/dist/adapters/nestjs/websockets.d.ts +47 -0
  26. package/dist/adapters/nestjs/websockets.js +286 -0
  27. package/dist/adapters/nestjs/websockets.js.map +1 -0
  28. package/dist/adapters/nestjs.cjs +1085 -0
  29. package/dist/adapters/nestjs.cjs.map +1 -0
  30. package/dist/adapters/nestjs.d.cts +385 -0
  31. package/dist/adapters/nestjs.d.ts +385 -0
  32. package/dist/adapters/nestjs.js +112 -0
  33. package/dist/adapters/nestjs.js.map +1 -0
  34. package/dist/adapters/observe-storage.d.cts +4 -4
  35. package/dist/adapters/observe-storage.d.ts +4 -4
  36. package/dist/adapters/observe-storage.js +5 -4
  37. package/dist/adapters/observe-storage.js.map +1 -1
  38. package/dist/adapters/react.cjs +166 -0
  39. package/dist/adapters/react.cjs.map +1 -0
  40. package/dist/adapters/react.d.cts +31 -0
  41. package/dist/adapters/react.d.ts +31 -0
  42. package/dist/adapters/react.js +51 -0
  43. package/dist/adapters/react.js.map +1 -0
  44. package/dist/adapters/solid.cjs +157 -0
  45. package/dist/adapters/solid.cjs.map +1 -0
  46. package/dist/adapters/solid.d.cts +26 -0
  47. package/dist/adapters/solid.d.ts +26 -0
  48. package/dist/adapters/solid.js +48 -0
  49. package/dist/adapters/solid.js.map +1 -0
  50. package/dist/adapters/svelte.cjs +148 -0
  51. package/dist/adapters/svelte.cjs.map +1 -0
  52. package/dist/adapters/svelte.d.cts +31 -0
  53. package/dist/adapters/svelte.d.ts +31 -0
  54. package/dist/adapters/svelte.js +46 -0
  55. package/dist/adapters/svelte.js.map +1 -0
  56. package/dist/adapters/vue.cjs +155 -0
  57. package/dist/adapters/vue.cjs.map +1 -0
  58. package/dist/adapters/vue.d.cts +26 -0
  59. package/dist/adapters/vue.d.ts +26 -0
  60. package/dist/adapters/vue.js +46 -0
  61. package/dist/adapters/vue.js.map +1 -0
  62. package/dist/agent-runtime-types-core-CaXfKNtY.d.cts +406 -0
  63. package/dist/agent-runtime-types-core-hU299uIC.d.ts +406 -0
  64. package/dist/agent-runtime-types-tool-BEpSINol.d.ts +695 -0
  65. package/dist/agent-runtime-types-tool-DninPEzk.d.cts +695 -0
  66. package/dist/agentic-memory-retention-BmGX368S.d.ts +14 -0
  67. package/dist/agentic-memory-retention-Ih1qhX9Z.d.cts +14 -0
  68. package/dist/agentic-memory-types-CVSUS6XR.d.ts +473 -0
  69. package/dist/agentic-memory-types-FnnYlVUs.d.cts +473 -0
  70. package/dist/capability-admission-BW2CziT6.d.ts +102 -0
  71. package/dist/capability-admission-lwSecxXs.d.cts +102 -0
  72. package/dist/chunk-2KUAG2GZ.js +9693 -0
  73. package/dist/chunk-2KUAG2GZ.js.map +1 -0
  74. package/dist/chunk-2NJP6GO4.js +1320 -0
  75. package/dist/chunk-2NJP6GO4.js.map +1 -0
  76. package/dist/{chunk-GDL26N2T.js → chunk-3KN7NJDR.js} +2 -2
  77. package/dist/{chunk-COHO25CZ.js → chunk-4NWSNI4K.js} +2232 -1672
  78. package/dist/chunk-4NWSNI4K.js.map +1 -0
  79. package/dist/{chunk-Z2ANQ6JW.js → chunk-4Q77MMJY.js} +2 -2
  80. package/dist/chunk-6E76H4OU.js +132 -0
  81. package/dist/chunk-6E76H4OU.js.map +1 -0
  82. package/dist/chunk-7GOTIIQ7.js +819 -0
  83. package/dist/chunk-7GOTIIQ7.js.map +1 -0
  84. package/dist/{chunk-D6BG7U6A.js → chunk-7HZRJMN6.js} +3 -3
  85. package/dist/{chunk-SCRFRCGR.js → chunk-BSQGE5PS.js} +1 -1
  86. package/dist/{chunk-PKVBHGBM.js → chunk-CJIFGJQG.js} +7 -7
  87. package/dist/{chunk-G4M3NHRJ.js → chunk-CX6B6PO2.js} +93 -10
  88. package/dist/chunk-CX6B6PO2.js.map +1 -0
  89. package/dist/chunk-DGUM43GV.js +11 -0
  90. package/dist/chunk-DGUM43GV.js.map +1 -0
  91. package/dist/{chunk-JIMUDQN3.js → chunk-E4QCH32M.js} +449 -447
  92. package/dist/chunk-E4QCH32M.js.map +1 -0
  93. package/dist/{chunk-RIIOUTGM.js → chunk-ECURQ3HD.js} +19 -129
  94. package/dist/chunk-ECURQ3HD.js.map +1 -0
  95. package/dist/{chunk-2ILL7HQI.js → chunk-EOKT4QFF.js} +134 -128
  96. package/dist/chunk-EOKT4QFF.js.map +1 -0
  97. package/dist/{chunk-K3FXTC3I.js → chunk-HJACH5PU.js} +3 -3
  98. package/dist/{chunk-GTPCOEOZ.js → chunk-IDMLXLLG.js} +3 -3
  99. package/dist/{chunk-DKP56CSW.js → chunk-JKAYLDQV.js} +2 -2
  100. package/dist/{chunk-4VLAQHZI.js → chunk-K7FB3JTD.js} +17 -1
  101. package/dist/chunk-K7FB3JTD.js.map +1 -0
  102. package/dist/chunk-L6LDXRWE.js +219 -0
  103. package/dist/chunk-L6LDXRWE.js.map +1 -0
  104. package/dist/chunk-M7J6Z4IJ.js +1930 -0
  105. package/dist/chunk-M7J6Z4IJ.js.map +1 -0
  106. package/dist/chunk-MQEQMS7B.js +1009 -0
  107. package/dist/chunk-MQEQMS7B.js.map +1 -0
  108. package/dist/chunk-MTELVIYR.js +1421 -0
  109. package/dist/chunk-MTELVIYR.js.map +1 -0
  110. package/dist/chunk-PVC7WDKI.js +885 -0
  111. package/dist/chunk-PVC7WDKI.js.map +1 -0
  112. package/dist/chunk-RAHNUYA5.js +368 -0
  113. package/dist/chunk-RAHNUYA5.js.map +1 -0
  114. package/dist/{chunk-DK554R7P.js → chunk-S6HXABGL.js} +2 -1
  115. package/dist/chunk-S6HXABGL.js.map +1 -0
  116. package/dist/{chunk-I3IHOHCJ.js → chunk-SHZDP2MQ.js} +1181 -1001
  117. package/dist/chunk-SHZDP2MQ.js.map +1 -0
  118. package/dist/{chunk-Y3ZLRGHC.js → chunk-SIDJO2T4.js} +16 -16
  119. package/dist/chunk-STXRMPW4.js +4131 -0
  120. package/dist/chunk-STXRMPW4.js.map +1 -0
  121. package/dist/{chunk-JR4IKCR2.js → chunk-TPND5MJS.js} +5 -5
  122. package/dist/chunk-TQPCAIQI.js +612 -0
  123. package/dist/chunk-TQPCAIQI.js.map +1 -0
  124. package/dist/chunk-UT3MHJCW.js +49 -0
  125. package/dist/chunk-UT3MHJCW.js.map +1 -0
  126. package/dist/{chunk-TEW47IVR.js → chunk-VPEFSDME.js} +2 -2
  127. package/dist/{chunk-SWTLEQL6.js → chunk-WQIA3GFB.js} +2 -2
  128. package/dist/chunk-WQIA3GFB.js.map +1 -0
  129. package/dist/{chunk-DJC4CHLQ.js → chunk-YDWBXXQZ.js} +5 -5
  130. package/dist/{chunk-6PHB5CJS.js → chunk-ZLFRB6FI.js} +2 -2
  131. package/dist/composition/index.cjs +1256 -1059
  132. package/dist/composition/index.cjs.map +1 -1
  133. package/dist/composition/index.d.cts +4 -4
  134. package/dist/composition/index.d.ts +4 -4
  135. package/dist/composition/index.js +7 -6
  136. package/dist/core/index.cjs +1218 -1021
  137. package/dist/core/index.cjs.map +1 -1
  138. package/dist/core/index.d.cts +2 -2
  139. package/dist/core/index.d.ts +2 -2
  140. package/dist/core/index.js +5 -4
  141. package/dist/cqrs/index.cjs.map +1 -1
  142. package/dist/cqrs/index.d.cts +4 -4
  143. package/dist/cqrs/index.d.ts +4 -4
  144. package/dist/cqrs/index.js +3 -2
  145. package/dist/cqrs/index.js.map +1 -1
  146. package/dist/cqrs/messaging.cjs +312 -0
  147. package/dist/cqrs/messaging.cjs.map +1 -0
  148. package/dist/cqrs/messaging.d.cts +57 -0
  149. package/dist/cqrs/messaging.d.ts +57 -0
  150. package/dist/cqrs/messaging.js +274 -0
  151. package/dist/cqrs/messaging.js.map +1 -0
  152. package/dist/cqrs/work-queue.cjs +329 -0
  153. package/dist/cqrs/work-queue.cjs.map +1 -0
  154. package/dist/cqrs/work-queue.d.cts +90 -0
  155. package/dist/cqrs/work-queue.d.ts +90 -0
  156. package/dist/cqrs/work-queue.js +292 -0
  157. package/dist/cqrs/work-queue.js.map +1 -0
  158. package/dist/data/index.cjs +19 -0
  159. package/dist/data/index.cjs.map +1 -0
  160. package/dist/data/index.d.cts +36 -0
  161. package/dist/data/index.d.ts +36 -0
  162. package/dist/data/index.js +1 -0
  163. package/dist/data/index.js.map +1 -0
  164. package/dist/data-structures/index.cjs +1252 -1052
  165. package/dist/data-structures/index.cjs.map +1 -1
  166. package/dist/data-structures/index.d.cts +9 -8
  167. package/dist/data-structures/index.d.ts +9 -8
  168. package/dist/data-structures/index.js +9 -7
  169. package/dist/{describe-BZb7AS2y.d.ts → describe-B_A5fbXH.d.ts} +1 -1
  170. package/dist/{describe-Ciu8SUnN.d.cts → describe-CQRrkv-Q.d.cts} +1 -1
  171. package/dist/executors/tool-provider-adapters.cjs +3091 -0
  172. package/dist/executors/tool-provider-adapters.cjs.map +1 -0
  173. package/dist/executors/tool-provider-adapters.d.cts +174 -0
  174. package/dist/executors/tool-provider-adapters.d.ts +174 -0
  175. package/dist/executors/tool-provider-adapters.js +1336 -0
  176. package/dist/executors/tool-provider-adapters.js.map +1 -0
  177. package/dist/executors/tool-provider-runtime.cjs +5178 -0
  178. package/dist/executors/tool-provider-runtime.cjs.map +1 -0
  179. package/dist/executors/tool-provider-runtime.d.cts +17 -0
  180. package/dist/executors/tool-provider-runtime.d.ts +17 -0
  181. package/dist/executors/tool-provider-runtime.js +15 -0
  182. package/dist/executors/tool-provider-runtime.js.map +1 -0
  183. package/dist/executors/tool-provider.cjs +6392 -0
  184. package/dist/executors/tool-provider.cjs.map +1 -0
  185. package/dist/executors/tool-provider.d.cts +60 -0
  186. package/dist/executors/tool-provider.d.ts +60 -0
  187. package/dist/executors/tool-provider.js +89 -0
  188. package/dist/executors/tool-provider.js.map +1 -0
  189. package/dist/executors/work-queue.cjs +342 -0
  190. package/dist/executors/work-queue.cjs.map +1 -0
  191. package/dist/executors/work-queue.d.cts +90 -0
  192. package/dist/executors/work-queue.d.ts +90 -0
  193. package/dist/executors/work-queue.js +306 -0
  194. package/dist/executors/work-queue.js.map +1 -0
  195. package/dist/graph/index.cjs +1536 -1324
  196. package/dist/graph/index.cjs.map +1 -1
  197. package/dist/graph/index.d.cts +10 -9
  198. package/dist/graph/index.d.ts +10 -9
  199. package/dist/graph/index.js +22 -20
  200. package/dist/{graph-s23RbbFO.d.cts → graph-CWK3HLPB.d.cts} +134 -132
  201. package/dist/{graph-DfdF9zy4.d.ts → graph-ho5sotHP.d.ts} +134 -132
  202. package/dist/{index-SnzZu3x7.d.ts → index-CQWcE0Dw.d.ts} +18 -4
  203. package/dist/{index-CAEmLCYF.d.cts → index-DHA1i67c.d.cts} +18 -4
  204. package/dist/index.cjs +3331 -3020
  205. package/dist/index.cjs.map +1 -1
  206. package/dist/index.d.cts +14 -10
  207. package/dist/index.d.ts +14 -10
  208. package/dist/index.js +114 -108
  209. package/dist/inspection/boundary.cjs +98 -0
  210. package/dist/inspection/boundary.cjs.map +1 -0
  211. package/dist/inspection/boundary.d.cts +61 -0
  212. package/dist/inspection/boundary.d.ts +61 -0
  213. package/dist/inspection/boundary.js +75 -0
  214. package/dist/inspection/boundary.js.map +1 -0
  215. package/dist/measurements-C0mAvWU1.d.cts +164 -0
  216. package/dist/measurements-OMpCeBwh.d.ts +164 -0
  217. package/dist/{messages-BZqrGGm1.d.ts → messages-CAzUPPJM.d.cts} +10 -5
  218. package/dist/{messages-BZqrGGm1.d.cts → messages-CAzUPPJM.d.ts} +10 -5
  219. package/dist/messaging/index.cjs +756 -619
  220. package/dist/messaging/index.cjs.map +1 -1
  221. package/dist/messaging/index.d.cts +17 -226
  222. package/dist/messaging/index.d.ts +17 -226
  223. package/dist/messaging/index.js +19 -749
  224. package/dist/messaging/index.js.map +1 -1
  225. package/dist/operators/index.cjs +1256 -1059
  226. package/dist/operators/index.cjs.map +1 -1
  227. package/dist/operators/index.d.cts +6 -6
  228. package/dist/operators/index.d.ts +6 -6
  229. package/dist/operators/index.js +9 -8
  230. package/dist/orchestration/index.cjs +8664 -2617
  231. package/dist/orchestration/index.cjs.map +1 -1
  232. package/dist/orchestration/index.d.cts +171 -221
  233. package/dist/orchestration/index.d.ts +171 -221
  234. package/dist/orchestration/index.js +74 -982
  235. package/dist/orchestration/index.js.map +1 -1
  236. package/dist/orchestration/messaging.cjs +314 -0
  237. package/dist/orchestration/messaging.cjs.map +1 -0
  238. package/dist/orchestration/messaging.d.cts +56 -0
  239. package/dist/orchestration/messaging.d.ts +56 -0
  240. package/dist/orchestration/messaging.js +276 -0
  241. package/dist/orchestration/messaging.js.map +1 -0
  242. package/dist/orchestration/work-queue.cjs +1500 -0
  243. package/dist/orchestration/work-queue.cjs.map +1 -0
  244. package/dist/orchestration/work-queue.d.cts +196 -0
  245. package/dist/orchestration/work-queue.d.ts +196 -0
  246. package/dist/orchestration/work-queue.js +1289 -0
  247. package/dist/orchestration/work-queue.js.map +1 -0
  248. package/dist/patterns/event-flow.cjs +433 -0
  249. package/dist/patterns/event-flow.cjs.map +1 -0
  250. package/dist/patterns/event-flow.d.cts +115 -0
  251. package/dist/patterns/event-flow.d.ts +115 -0
  252. package/dist/patterns/event-flow.js +14 -0
  253. package/dist/patterns/event-flow.js.map +1 -0
  254. package/dist/patterns/index.cjs +748 -355
  255. package/dist/patterns/index.cjs.map +1 -1
  256. package/dist/patterns/index.d.cts +9 -5
  257. package/dist/patterns/index.d.ts +9 -5
  258. package/dist/patterns/index.js +13 -4
  259. package/dist/process-types-C9uMYz3i.d.ts +200 -0
  260. package/dist/process-types-h3uRlzDc.d.cts +200 -0
  261. package/dist/{reactive-collection-BxBqtIOE.d.cts → reactive-collection-B9R0Bl1P.d.cts} +11 -41
  262. package/dist/{reactive-collection-Cb1II1Fi.d.ts → reactive-collection-BXFrH0U2.d.ts} +11 -41
  263. package/dist/{reactive-collection-storage-D-KmjE0J.d.cts → reactive-collection-storage-BLGv8Xp8.d.cts} +5 -5
  264. package/dist/{reactive-collection-storage-BNiEc-Gd.d.ts → reactive-collection-storage-a4zD3665.d.ts} +5 -5
  265. package/dist/{reactive-map-BcB4KsQR.d.ts → reactive-map-C_8sOfdS.d.cts} +7 -6
  266. package/dist/{reactive-map-D-g3dv8I.d.cts → reactive-map-jle5dnok.d.ts} +7 -6
  267. package/dist/render/index.d.cts +3 -3
  268. package/dist/render/index.d.ts +3 -3
  269. package/dist/render/index.js +1 -0
  270. package/dist/scheduled-readiness-5rwQlyjV.d.ts +91 -0
  271. package/dist/scheduled-readiness-DpRY8jI0.d.cts +91 -0
  272. package/dist/semantic-memory-graph-C2ZUwIlq.d.ts +30 -0
  273. package/dist/semantic-memory-graph-DlZBD_Eu.d.cts +30 -0
  274. package/dist/{semantic-memory-graph-BYoIlP35.d.cts → semantic-memory-graph-types-BvzdqmkY.d.cts} +2 -28
  275. package/dist/{semantic-memory-graph-CxyXLms3.d.ts → semantic-memory-graph-types-Ci-OtahO.d.ts} +2 -28
  276. package/dist/solutions/index.cjs +6788 -2128
  277. package/dist/solutions/index.cjs.map +1 -1
  278. package/dist/solutions/index.d.cts +15 -519
  279. package/dist/solutions/index.d.ts +15 -519
  280. package/dist/solutions/index.js +91 -7
  281. package/dist/solutions/reactive-layout/browser/index.cjs +457 -0
  282. package/dist/solutions/reactive-layout/browser/index.cjs.map +1 -0
  283. package/dist/solutions/reactive-layout/browser/index.d.cts +44 -0
  284. package/dist/solutions/reactive-layout/browser/index.d.ts +44 -0
  285. package/dist/solutions/reactive-layout/browser/index.js +69 -0
  286. package/dist/solutions/reactive-layout/browser/index.js.map +1 -0
  287. package/dist/solutions/reactive-layout/index.cjs +4494 -0
  288. package/dist/solutions/reactive-layout/index.cjs.map +1 -0
  289. package/dist/solutions/reactive-layout/index.d.cts +37 -0
  290. package/dist/solutions/reactive-layout/index.d.ts +37 -0
  291. package/dist/solutions/reactive-layout/index.js +146 -0
  292. package/dist/solutions/reactive-layout/index.js.map +1 -0
  293. package/dist/solutions/reactive-layout/node-canvas/index.cjs +555 -0
  294. package/dist/solutions/reactive-layout/node-canvas/index.cjs.map +1 -0
  295. package/dist/solutions/reactive-layout/node-canvas/index.d.cts +54 -0
  296. package/dist/solutions/reactive-layout/node-canvas/index.d.ts +54 -0
  297. package/dist/solutions/reactive-layout/node-canvas/index.js +131 -0
  298. package/dist/solutions/reactive-layout/node-canvas/index.js.map +1 -0
  299. package/dist/solutions/reactive-layout/react-native/index.cjs +504 -0
  300. package/dist/solutions/reactive-layout/react-native/index.cjs.map +1 -0
  301. package/dist/solutions/reactive-layout/react-native/index.d.cts +51 -0
  302. package/dist/solutions/reactive-layout/react-native/index.d.ts +51 -0
  303. package/dist/solutions/reactive-layout/react-native/index.js +77 -0
  304. package/dist/solutions/reactive-layout/react-native/index.js.map +1 -0
  305. package/dist/solutions/reactive-layout/skia/index.cjs +557 -0
  306. package/dist/solutions/reactive-layout/skia/index.cjs.map +1 -0
  307. package/dist/solutions/reactive-layout/skia/index.d.cts +64 -0
  308. package/dist/solutions/reactive-layout/skia/index.d.ts +64 -0
  309. package/dist/solutions/reactive-layout/skia/index.js +70 -0
  310. package/dist/solutions/reactive-layout/skia/index.js.map +1 -0
  311. package/dist/solutions/work-item/actions.cjs +2345 -0
  312. package/dist/solutions/work-item/actions.cjs.map +1 -0
  313. package/dist/solutions/work-item/actions.d.cts +40 -0
  314. package/dist/solutions/work-item/actions.d.ts +40 -0
  315. package/dist/solutions/work-item/actions.js +2078 -0
  316. package/dist/solutions/work-item/actions.js.map +1 -0
  317. package/dist/solutions/work-item/scheduling.cjs +9797 -0
  318. package/dist/solutions/work-item/scheduling.cjs.map +1 -0
  319. package/dist/solutions/work-item/scheduling.d.cts +1868 -0
  320. package/dist/solutions/work-item/scheduling.d.ts +1868 -0
  321. package/dist/solutions/work-item/scheduling.js +146 -0
  322. package/dist/solutions/work-item/scheduling.js.map +1 -0
  323. package/dist/solutions/work-item/work-queue.cjs +306 -0
  324. package/dist/solutions/work-item/work-queue.cjs.map +1 -0
  325. package/dist/solutions/work-item/work-queue.d.cts +71 -0
  326. package/dist/solutions/work-item/work-queue.d.ts +71 -0
  327. package/dist/solutions/work-item/work-queue.js +270 -0
  328. package/dist/solutions/work-item/work-queue.js.map +1 -0
  329. package/dist/sources/browser.cjs +1399 -1052
  330. package/dist/sources/browser.cjs.map +1 -1
  331. package/dist/sources/browser.d.cts +33 -6
  332. package/dist/sources/browser.d.ts +33 -6
  333. package/dist/sources/browser.js +73 -6
  334. package/dist/sources/browser.js.map +1 -1
  335. package/dist/sources/index.cjs +1345 -1065
  336. package/dist/sources/index.cjs.map +1 -1
  337. package/dist/sources/index.d.cts +5 -5
  338. package/dist/sources/index.d.ts +5 -5
  339. package/dist/sources/index.js +7 -6
  340. package/dist/sources/node.cjs.map +1 -1
  341. package/dist/sources/node.d.cts +4 -4
  342. package/dist/sources/node.d.ts +4 -4
  343. package/dist/sources/node.js +2 -1
  344. package/dist/sources/node.js.map +1 -1
  345. package/dist/storage/browser.cjs +16 -0
  346. package/dist/storage/browser.cjs.map +1 -1
  347. package/dist/storage/browser.js +4 -3
  348. package/dist/storage/browser.js.map +1 -1
  349. package/dist/storage/index.cjs +16 -0
  350. package/dist/storage/index.cjs.map +1 -1
  351. package/dist/storage/index.d.cts +6 -5
  352. package/dist/storage/index.d.ts +6 -5
  353. package/dist/storage/index.js +10 -9
  354. package/dist/storage/node.cjs +16 -0
  355. package/dist/storage/node.cjs.map +1 -1
  356. package/dist/storage/node.js +4 -3
  357. package/dist/storage/node.js.map +1 -1
  358. package/dist/store-BmtEs9mG.d.ts +123 -0
  359. package/dist/store-PAAsYvML.d.cts +123 -0
  360. package/dist/testing/index.cjs +1 -0
  361. package/dist/testing/index.cjs.map +1 -1
  362. package/dist/testing/index.d.cts +1 -1
  363. package/dist/testing/index.d.ts +1 -1
  364. package/dist/testing/index.js +3 -2
  365. package/dist/types-BRNKoFHj.d.ts +357 -0
  366. package/dist/{types-h12mNYbq.d.ts → types-BS6CyR-x.d.cts} +49 -130
  367. package/dist/types-BWK2ay3e.d.cts +457 -0
  368. package/dist/types-BXKSAoE1.d.cts +357 -0
  369. package/dist/types-BaPpZItj.d.ts +457 -0
  370. package/dist/types-BhveCMg5.d.cts +274 -0
  371. package/dist/{types-bNMSWKqF.d.cts → types-C9NOgNJw.d.ts} +49 -130
  372. package/dist/types-CTsQ8Ww4.d.ts +274 -0
  373. package/dist/types-DL_05n2M.d.ts +34 -0
  374. package/dist/types-XDoqxYO9.d.cts +34 -0
  375. package/dist/work-item-runtime-types-BqtWnSCS.d.ts +138 -0
  376. package/dist/work-item-runtime-types-CHO03AKh.d.cts +138 -0
  377. package/dist/work-queue/index.cjs +1136 -0
  378. package/dist/work-queue/index.cjs.map +1 -0
  379. package/dist/work-queue/index.d.cts +21 -0
  380. package/dist/work-queue/index.d.ts +21 -0
  381. package/dist/work-queue/index.js +1082 -0
  382. package/dist/work-queue/index.js.map +1 -0
  383. package/package.json +603 -249
  384. package/dist/chunk-2ILL7HQI.js.map +0 -1
  385. package/dist/chunk-4VLAQHZI.js.map +0 -1
  386. package/dist/chunk-COHO25CZ.js.map +0 -1
  387. package/dist/chunk-DK554R7P.js.map +0 -1
  388. package/dist/chunk-G4M3NHRJ.js.map +0 -1
  389. package/dist/chunk-I3IHOHCJ.js.map +0 -1
  390. package/dist/chunk-JIMUDQN3.js.map +0 -1
  391. package/dist/chunk-RIIOUTGM.js.map +0 -1
  392. package/dist/chunk-SWTLEQL6.js.map +0 -1
  393. /package/dist/{chunk-GDL26N2T.js.map → chunk-3KN7NJDR.js.map} +0 -0
  394. /package/dist/{chunk-Z2ANQ6JW.js.map → chunk-4Q77MMJY.js.map} +0 -0
  395. /package/dist/{chunk-D6BG7U6A.js.map → chunk-7HZRJMN6.js.map} +0 -0
  396. /package/dist/{chunk-SCRFRCGR.js.map → chunk-BSQGE5PS.js.map} +0 -0
  397. /package/dist/{chunk-PKVBHGBM.js.map → chunk-CJIFGJQG.js.map} +0 -0
  398. /package/dist/{chunk-K3FXTC3I.js.map → chunk-HJACH5PU.js.map} +0 -0
  399. /package/dist/{chunk-GTPCOEOZ.js.map → chunk-IDMLXLLG.js.map} +0 -0
  400. /package/dist/{chunk-DKP56CSW.js.map → chunk-JKAYLDQV.js.map} +0 -0
  401. /package/dist/{chunk-Y3ZLRGHC.js.map → chunk-SIDJO2T4.js.map} +0 -0
  402. /package/dist/{chunk-JR4IKCR2.js.map → chunk-TPND5MJS.js.map} +0 -0
  403. /package/dist/{chunk-TEW47IVR.js.map → chunk-VPEFSDME.js.map} +0 -0
  404. /package/dist/{chunk-DJC4CHLQ.js.map → chunk-YDWBXXQZ.js.map} +0 -0
  405. /package/dist/{chunk-6PHB5CJS.js.map → chunk-ZLFRB6FI.js.map} +0 -0
@@ -28,11 +28,11 @@ __export(messaging_exports, {
28
28
  SPAWNS_TOPIC: () => SPAWNS_TOPIC,
29
29
  STANDARD_TOPICS: () => STANDARD_TOPICS,
30
30
  TODOS_TOPIC: () => TODOS_TOPIC,
31
- dynamicHub: () => dynamicHub,
32
- fromHubTopic: () => fromHubTopic,
31
+ eventMessage: () => eventMessage,
32
+ eventMessageIssue: () => eventMessageIssue,
33
33
  fromTopic: () => fromTopic,
34
+ isEventMessage: () => isEventMessage,
34
35
  messageBus: () => messageBus,
35
- toHubTopic: () => toHubTopic,
36
36
  toTopic: () => toTopic
37
37
  });
38
38
  module.exports = __toCommonJS(messaging_exports);
@@ -51,15 +51,132 @@ function depBatch(ctx, depIndex) {
51
51
  return flattened.length === 0 ? [] : flattened;
52
52
  }
53
53
 
54
- // src/graph/graph.ts
55
- var lifecycleRegistrars = /* @__PURE__ */ new WeakMap();
56
- function releaseGraphNodes(graph, nodes, opts = {}) {
57
- const registrar = lifecycleRegistrars.get(graph);
58
- if (registrar === void 0) throw new Error("graph: unknown lifecycle registrar");
59
- registrar.releaseNodes(nodes, opts);
54
+ // src/messaging/internal.ts
55
+ var busStates = /* @__PURE__ */ new WeakMap();
56
+ function registerMessageBusState(bus, state) {
57
+ busStates.set(bus, state);
58
+ }
59
+ function getMessageBusState(bus) {
60
+ return busStates.get(bus);
61
+ }
62
+ function attachMessageBusCommandSource(graph, bus, commands) {
63
+ const state = getMessageBusState(bus);
64
+ if (state === void 0) throw new Error("messageBus: unknown implementation");
65
+ if (state.graph !== graph) throw new Error("messageBus: command source graph must match");
66
+ state.commandSources.push(commands);
67
+ const busCommands = bus.commands;
68
+ if (busCommands === void 0) throw new Error("messageBus: missing commands node");
69
+ busCommands.replaceDeps([...state.commandSources], state.commandBody);
70
+ let released = false;
71
+ return () => {
72
+ if (released) return;
73
+ released = true;
74
+ const index = state.commandSources.indexOf(commands);
75
+ if (index >= 0) state.commandSources.splice(index, 1);
76
+ busCommands.replaceDeps([...state.commandSources], state.commandBody);
77
+ };
60
78
  }
61
79
 
62
- // src/messaging/index.ts
80
+ // src/messaging/utils.ts
81
+ function pullParams(pull) {
82
+ return isObjectRecord(pull?.params) ? pull.params : {};
83
+ }
84
+ function publishCommand(commandNode, command) {
85
+ commandNode.down([["DATA", command]]);
86
+ return command;
87
+ }
88
+ function makeTopicState() {
89
+ return { closed: false, headSeq: 1, nextSeq: 1, messages: [] };
90
+ }
91
+ function uniqueTopics(topics) {
92
+ const unique = [...new Set(topics)];
93
+ if (unique.length !== topics.length) throw new Error("messageBus: duplicate topic");
94
+ for (const topic of unique) assertTopicKey(topic, "messageBus");
95
+ return Object.freeze(unique.sort());
96
+ }
97
+ function assertTopicKey(topic, owner) {
98
+ const error = validateTopicKey(topic, owner);
99
+ if (error !== void 0) throw new Error(error);
100
+ }
101
+ function validateTopicKey(topic, owner) {
102
+ if (typeof topic !== "string" || topic.length === 0)
103
+ return `${owner}: topic must be a non-empty string`;
104
+ return void 0;
105
+ }
106
+ function assertNonEmpty(value, owner) {
107
+ if (typeof value !== "string" || value.length === 0)
108
+ throw new Error(`${owner}: must be a non-empty string`);
109
+ }
110
+ function positiveLimit(limit) {
111
+ if (limit === void 0) return 100;
112
+ if (!Number.isInteger(limit) || limit < 1)
113
+ throw new Error("messageBus: limit must be a positive integer");
114
+ return limit;
115
+ }
116
+ function isPositiveSeq(value) {
117
+ return Number.isInteger(value) && value >= 1;
118
+ }
119
+ function isObjectRecord(value) {
120
+ return typeof value === "object" && value !== null && !Array.isArray(value);
121
+ }
122
+ function commandTopic(command) {
123
+ return isObjectRecord(command) && typeof command.topic === "string" ? command.topic : void 0;
124
+ }
125
+ function commandIdOf(command) {
126
+ return isObjectRecord(command) && typeof command.commandId === "string" ? command.commandId : void 0;
127
+ }
128
+ function idempotencyKey(topic, key) {
129
+ return `${topic}\0${key}`;
130
+ }
131
+
132
+ // src/messaging/event-message.ts
133
+ function eventMessage(type, payload, opts) {
134
+ assertNonEmpty(type, "eventMessage.type");
135
+ assertNonEmpty(opts.id, "eventMessage.id");
136
+ return {
137
+ id: opts.id,
138
+ type,
139
+ payload,
140
+ ...opts.key === void 0 ? {} : { key: opts.key },
141
+ ...opts.subjectId === void 0 ? {} : { subjectId: opts.subjectId },
142
+ ...opts.correlationId === void 0 ? {} : { correlationId: opts.correlationId },
143
+ ...opts.causationId === void 0 ? {} : { causationId: opts.causationId },
144
+ ...opts.occurredAtMs === void 0 ? {} : { occurredAtMs: opts.occurredAtMs },
145
+ ...opts.actor === void 0 ? {} : { actor: opts.actor },
146
+ ...opts.evidenceRefs === void 0 ? {} : { evidenceRefs: opts.evidenceRefs },
147
+ ...opts.schema === void 0 ? {} : { schema: opts.schema },
148
+ ...opts.metadata === void 0 ? {} : { metadata: opts.metadata }
149
+ };
150
+ }
151
+ function isEventMessage(value) {
152
+ return eventMessageIssue(value) === void 0;
153
+ }
154
+ function eventMessageIssue(value) {
155
+ if (!isObjectRecord(value)) {
156
+ return eventIssue("event message must be an object");
157
+ }
158
+ if (typeof value.id !== "string" || value.id.length === 0) {
159
+ return eventIssue("event message id must be a non-empty string");
160
+ }
161
+ if (typeof value.type !== "string" || value.type.length === 0) {
162
+ return eventIssue("event message type must be a non-empty string");
163
+ }
164
+ if (!("payload" in value)) {
165
+ return eventIssue("event message payload field is required");
166
+ }
167
+ return void 0;
168
+ }
169
+ function eventIssue(message) {
170
+ return {
171
+ kind: "issue",
172
+ code: "malformed-event-message",
173
+ message,
174
+ severity: "error",
175
+ source: "messageBus.eventMessage"
176
+ };
177
+ }
178
+
179
+ // src/messaging/types.ts
63
180
  var PROMPTS_TOPIC = "prompts";
64
181
  var RESPONSES_TOPIC = "responses";
65
182
  var INJECTIONS_TOPIC = "injections";
@@ -76,727 +193,747 @@ var STANDARD_TOPICS = Object.freeze([
76
193
  CONTEXT_TOPIC,
77
194
  TODOS_TOPIC
78
195
  ]);
79
- var busStates = /* @__PURE__ */ new WeakMap();
80
- var dynamicHubStates = /* @__PURE__ */ new WeakMap();
81
- var DEFAULT_DYNAMIC_HUB_MAX_TOPICS = 1024;
82
- var DEFAULT_DYNAMIC_HUB_MAX_TOPIC_LENGTH = 256;
83
- function messageBus(graph, opts) {
84
- const unique = [...new Set(opts.topics)];
85
- if (unique.length !== opts.topics.length) throw new Error("messageBus: duplicate topic");
86
- if (unique.length === 0) throw new Error("messageBus: at least one topic is required");
196
+
197
+ // src/messaging/index.ts
198
+ function messageBus(graph, opts = {}) {
87
199
  const name = opts.name ?? "messageBus";
88
- const state = {
89
- graph,
90
- name,
91
- now: opts.now ?? Date.now,
92
- topics: Object.freeze([...unique]),
93
- records: /* @__PURE__ */ new Map(),
94
- seq: 0
95
- };
96
- for (const topic of unique) {
97
- const producers = [];
98
- const body = (ctx) => {
99
- for (let i = 0; i < producers.length; i++) {
100
- for (const produced of depBatch(ctx, i) ?? []) {
101
- if (produced.kind === "publish") {
102
- ctx.down([
103
- [
104
- "DATA",
105
- produced.envelope
106
- ]
107
- ]);
108
- }
109
- }
110
- }
111
- };
112
- const node = graph.node([], body, {
113
- name: `${name}/${topic}`,
114
- factory: "messageTopic",
115
- meta: { topic },
116
- completeWhenDepsComplete: false,
117
- errorWhenDepsError: false
118
- });
119
- state.records.set(topic, { node, producers, body });
120
- }
121
- const bus = {
122
- topics: state.topics,
123
- topic(topic) {
124
- return requireTopic(state, topic);
125
- },
126
- publish(topic, payload, publishOpts = {}) {
127
- const node = requireTopic(state, topic);
128
- const envelope = {
129
- topic,
130
- seq: ++state.seq,
131
- payload,
132
- timestampMs: state.now(),
133
- ...publishOpts.key === void 0 ? {} : { key: publishOpts.key }
134
- };
135
- node.down([["DATA", envelope]]);
136
- return envelope;
137
- },
138
- has(topic) {
139
- return state.records.has(topic);
140
- }
141
- };
142
- busStates.set(bus, state);
143
- return bus;
144
- }
145
- function dynamicHub(graph, opts = {}) {
146
- const name = opts.name ?? "dynamicHub";
147
- const unknownTopic = normalizeUnknownTopicPolicy(opts.unknownTopic);
148
- const maxTopics = normalizeHubLimit(
149
- opts.maxTopics,
150
- DEFAULT_DYNAMIC_HUB_MAX_TOPICS,
151
- "dynamicHub: maxTopics"
152
- );
153
- const maxTopicLength = normalizeHubLimit(
154
- opts.maxTopicLength,
155
- DEFAULT_DYNAMIC_HUB_MAX_TOPIC_LENGTH,
156
- "dynamicHub: maxTopicLength"
157
- );
158
- const now = opts.now ?? Date.now;
159
- const initialTopics = uniqueTopics(opts.topics ?? [], maxTopicLength);
160
- if (initialTopics.length > maxTopics) {
161
- throw new Error("dynamicHub: topics exceed maxTopics");
162
- }
200
+ const initialTopics = uniqueTopics(opts.topics ?? []);
163
201
  const commandSources = [];
164
202
  const commandBody = (ctx) => {
165
203
  for (let i = 0; i < commandSources.length; i++) {
166
- for (const command2 of depBatch(ctx, i) ?? []) ctx.down([["DATA", command2]]);
204
+ for (const command of depBatch(ctx, i) ?? []) ctx.down([["DATA", command]]);
167
205
  }
168
206
  };
169
- const command = graph.node([], commandBody, {
170
- name: `${name}/command`,
171
- factory: "dynamicHubCommand",
207
+ const commands = graph.node([], commandBody, {
208
+ name: `${name}/commands`,
209
+ factory: "messageBusCommands",
172
210
  completeWhenDepsComplete: false,
173
211
  errorWhenDepsError: false
174
212
  });
175
- const events = graph.node(
176
- [command],
213
+ const state = {
214
+ graph,
215
+ name,
216
+ now: opts.now ?? Date.now,
217
+ topicPolicy: opts.topicPolicy ?? "strict",
218
+ retention: opts.retention ?? {},
219
+ dedupe: opts.dedupe ?? { commandId: "status" },
220
+ topics: new Map(initialTopics.map((topic) => [topic, makeTopicState()])),
221
+ subscriptions: /* @__PURE__ */ new Map(),
222
+ seenCommandIds: /* @__PURE__ */ new Set(),
223
+ seenIdempotencyKeys: /* @__PURE__ */ new Set(),
224
+ deadLetters: [],
225
+ deadLetterSeq: 0,
226
+ commandSources,
227
+ commandBody
228
+ };
229
+ const runtime = graph.node(
230
+ [commands],
177
231
  (ctx) => {
178
- const runtime = ctx.state.get() ?? {
179
- topics: [...initialTopics],
180
- open: true,
181
- seq: 0,
182
- cursor: 0
183
- };
184
- ctx.state.persist(true);
185
- for (const commandFact of depBatch(ctx, 0) ?? []) {
186
- const parsed = parseDynamicHubCommand(commandFact);
187
- if (typeof parsed === "string") {
188
- ctx.down([["DATA", hubError(runtime, commandFact, parsed, timestampOrFallback(now))]]);
189
- continue;
232
+ for (const command of depBatch(ctx, 0) ?? []) {
233
+ for (const event of reduceMessageBusCommand(state, command)) {
234
+ ctx.down([["DATA", event]]);
190
235
  }
191
- const reduced = reduceDynamicHubCommand(
192
- runtime,
193
- parsed,
194
- unknownTopic,
195
- maxTopics,
196
- maxTopicLength,
197
- now
198
- );
199
- for (const event of reduced) ctx.down([["DATA", event]]);
200
236
  }
201
- ctx.state.set(runtime);
202
237
  },
203
238
  {
204
- name: `${name}/events`,
205
- factory: "dynamicHubEvents",
206
- meta: { unknownTopic },
239
+ name: `${name}/runtime`,
240
+ factory: "messageBusRuntime",
207
241
  completeWhenDepsComplete: false,
208
242
  errorWhenDepsError: false
209
243
  }
210
244
  );
211
- const status = graph.node(
212
- [events],
245
+ graph.retain(runtime, { reason: `${name}.messageBus.runtime` });
246
+ const messages = graph.node(
247
+ [runtime],
213
248
  (ctx) => {
214
249
  for (const event of depBatch(ctx, 0) ?? []) {
215
250
  const typed = event;
216
- ctx.down([["DATA", typed.status]]);
251
+ if (typed.kind === "message") ctx.down([["DATA", typed.message]]);
217
252
  }
218
253
  },
219
254
  {
220
- name: `${name}/status`,
221
- factory: "dynamicHubStatus",
255
+ name: `${name}/messages`,
256
+ factory: "messageBusMessages",
222
257
  completeWhenDepsComplete: false,
223
258
  errorWhenDepsError: false
224
259
  }
225
260
  );
226
- const errors = graph.node(
227
- [events],
261
+ const status = graph.node(
262
+ [runtime],
228
263
  (ctx) => {
229
264
  for (const event of depBatch(ctx, 0) ?? []) {
230
265
  const typed = event;
231
- if (typed.kind !== "error") continue;
232
- ctx.down([
233
- [
234
- "DATA",
235
- {
236
- ...typed.topic === void 0 ? {} : { topic: typed.topic },
237
- error: typed.error,
238
- command: typed.command,
239
- meta: typed.meta
240
- }
241
- ]
242
- ]);
266
+ if (typed.kind === "status") ctx.down([["DATA", typed.status]]);
243
267
  }
244
268
  },
245
269
  {
246
- name: `${name}/errors`,
247
- factory: "dynamicHubErrors",
270
+ name: `${name}/status`,
271
+ factory: "messageBusStatus",
248
272
  completeWhenDepsComplete: false,
249
273
  errorWhenDepsError: false
250
274
  }
251
275
  );
252
- const deadLetter = opts.deadLetter === true || unknownTopic === "dead-letter" ? graph.node(
253
- [events],
276
+ const issues = graph.node(
277
+ [runtime],
254
278
  (ctx) => {
255
279
  for (const event of depBatch(ctx, 0) ?? []) {
256
280
  const typed = event;
257
- if (typed.kind !== "dead-letter") continue;
258
- ctx.down([
259
- [
260
- "DATA",
261
- {
262
- ...typed.topic === void 0 ? {} : { topic: typed.topic },
263
- reason: typed.reason,
264
- command: typed.command,
265
- meta: typed.meta
266
- }
267
- ]
268
- ]);
281
+ if (typed.kind === "issue") ctx.down([["DATA", typed.issue]]);
269
282
  }
270
283
  },
271
284
  {
272
- name: `${name}/deadLetter`,
273
- factory: "dynamicHubDeadLetter",
285
+ name: `${name}/issues`,
286
+ factory: "messageBusIssues",
274
287
  completeWhenDepsComplete: false,
275
288
  errorWhenDepsError: false
276
289
  }
277
- ) : void 0;
278
- const releaseEventsRetain = graph.retain(events, { reason: `${name}.dynamicHub.events` });
279
- const hub = {
280
- command,
281
- events,
290
+ );
291
+ const bus = {
292
+ commands,
293
+ messages,
282
294
  status,
283
- errors,
284
- ...deadLetter === void 0 ? {} : { deadLetter },
285
- create(topic, commandOpts = {}) {
286
- return publishHubCommand(command, {
287
- kind: "create",
295
+ issues,
296
+ ensureTopic(topic, commandOpts = {}) {
297
+ return publishCommand(commands, {
298
+ kind: "ensure-topic",
288
299
  topic,
289
- ...commandOpts.key === void 0 ? {} : { key: commandOpts.key },
290
- ...commandOpts.payload === void 0 ? {} : { payload: commandOpts.payload }
300
+ ...commandOpts.commandId === void 0 ? {} : { commandId: commandOpts.commandId }
291
301
  });
292
302
  },
293
- delete(topic, commandOpts = {}) {
294
- return publishHubCommand(command, {
295
- kind: "delete",
303
+ closeTopic(topic, commandOpts = {}) {
304
+ return publishCommand(commands, {
305
+ kind: "close-topic",
296
306
  topic,
297
- ...commandOpts.key === void 0 ? {} : { key: commandOpts.key },
298
- ...commandOpts.payload === void 0 ? {} : { payload: commandOpts.payload }
307
+ ...commandOpts.commandId === void 0 ? {} : { commandId: commandOpts.commandId }
299
308
  });
300
309
  },
301
- publish(topic, payload, commandOpts = {}) {
302
- return publishHubCommand(command, {
310
+ publish(topic, payload, publishOpts = {}) {
311
+ return publishCommand(commands, {
303
312
  kind: "publish",
304
313
  topic,
305
314
  payload,
306
- ...commandOpts.key === void 0 ? {} : { key: commandOpts.key }
315
+ ...publishOpts.key === void 0 ? {} : { key: publishOpts.key },
316
+ ...publishOpts.commandId === void 0 ? {} : { commandId: publishOpts.commandId },
317
+ ...publishOpts.idempotencyKey === void 0 ? {} : { idempotencyKey: publishOpts.idempotencyKey }
307
318
  });
308
319
  },
309
- subscribeTopic(topic, commandOpts = {}) {
310
- return publishHubCommand(command, {
311
- kind: "subscribe",
312
- topic,
313
- ...commandOpts.key === void 0 ? {} : { key: commandOpts.key },
314
- ...commandOpts.payload === void 0 ? {} : { payload: commandOpts.payload }
315
- });
320
+ topic(topic, projectionOpts = {}) {
321
+ assertTopicKey(topic, "messageBus.topic");
322
+ const snapshotPullId = /* @__PURE__ */ Symbol(`${name}/${topic}/topicSnapshot`);
323
+ const snapshot = graph.node(
324
+ [messages],
325
+ (ctx) => {
326
+ const params = pullParams(ctx.pull);
327
+ ctx.down([["DATA", topicPage(state, topic, params)]]);
328
+ },
329
+ {
330
+ name: projectionOpts.name ?? `${name}/${topic}/topic`,
331
+ factory: "messageBusTopicProjection",
332
+ meta: { topic },
333
+ pullId: snapshotPullId,
334
+ partial: true,
335
+ completeWhenDepsComplete: false,
336
+ errorWhenDepsError: false
337
+ }
338
+ );
339
+ return { snapshot, snapshotPullId, status, issues };
340
+ },
341
+ catalog(projectionOpts = {}) {
342
+ const snapshotPullId = /* @__PURE__ */ Symbol(`${name}/catalogSnapshot`);
343
+ const snapshot = graph.node(
344
+ [runtime],
345
+ (ctx) => {
346
+ const params = pullParams(ctx.pull);
347
+ ctx.down([["DATA", catalogPage(state, params)]]);
348
+ },
349
+ {
350
+ name: projectionOpts.name ?? `${name}/catalog`,
351
+ factory: "messageBusCatalog",
352
+ pullId: snapshotPullId,
353
+ partial: true,
354
+ completeWhenDepsComplete: false,
355
+ errorWhenDepsError: false
356
+ }
357
+ );
358
+ return { snapshot, snapshotPullId, status, issues };
359
+ },
360
+ deadLetter(projectionOpts = {}) {
361
+ const snapshotPullId = /* @__PURE__ */ Symbol(`${name}/deadLetterSnapshot`);
362
+ const snapshot = graph.node(
363
+ [runtime],
364
+ (ctx) => {
365
+ const params = pullParams(ctx.pull);
366
+ ctx.down([["DATA", deadLetterPage(state, params)]]);
367
+ },
368
+ {
369
+ name: projectionOpts.name ?? `${name}/deadLetter`,
370
+ factory: "messageBusDeadLetter",
371
+ pullId: snapshotPullId,
372
+ partial: true,
373
+ completeWhenDepsComplete: false,
374
+ errorWhenDepsError: false
375
+ }
376
+ );
377
+ return { snapshot, snapshotPullId, status, issues };
316
378
  },
317
- close(commandOpts = {}) {
318
- return publishHubCommand(command, {
319
- kind: "close",
320
- ...commandOpts.key === void 0 ? {} : { key: commandOpts.key },
321
- ...commandOpts.payload === void 0 ? {} : { payload: commandOpts.payload }
379
+ subscription(subscriptionOpts) {
380
+ assertTopicKey(subscriptionOpts.topic, "messageBus.subscription");
381
+ assertNonEmpty(subscriptionOpts.subscriptionId, "messageBus.subscriptionId");
382
+ const sub = ensureSubscription(state, {
383
+ topic: subscriptionOpts.topic,
384
+ subscriptionId: subscriptionOpts.subscriptionId,
385
+ from: subscriptionOpts.from ?? "earliest"
322
386
  });
387
+ const availablePullId = /* @__PURE__ */ Symbol(
388
+ `${name}/${subscriptionOpts.topic}/${subscriptionOpts.subscriptionId}/available`
389
+ );
390
+ const projectionName = subscriptionOpts.name ?? `${name}/${subscriptionOpts.topic}/${subscriptionOpts.subscriptionId}`;
391
+ const available = graph.node(
392
+ [messages, status],
393
+ (ctx) => {
394
+ const params = pullParams(ctx.pull);
395
+ ctx.down([["DATA", availablePage(state, sub, params)]]);
396
+ },
397
+ {
398
+ name: `${projectionName}/available`,
399
+ factory: "messageBusSubscriptionAvailable",
400
+ meta: { topic: subscriptionOpts.topic, subscriptionId: subscriptionOpts.subscriptionId },
401
+ pullId: availablePullId,
402
+ partial: true,
403
+ completeWhenDepsComplete: false,
404
+ errorWhenDepsError: false
405
+ }
406
+ );
407
+ const cursor = graph.node(
408
+ [status],
409
+ (ctx) => {
410
+ for (const fact of depBatch(ctx, 0) ?? []) {
411
+ const typed = fact;
412
+ const subscriptionMoved = typed.topic === sub.topic && typed.subscriptionId === sub.subscriptionId && (typed.kind === "subscription-acked" || typed.kind === "subscription-sought" || typed.kind === "subscription-closed");
413
+ const retentionMoved = typed.topic === sub.topic && typed.kind === "retention-trimmed";
414
+ if (subscriptionMoved || retentionMoved) {
415
+ ctx.down([["DATA", cursorSnapshot(state, sub)]]);
416
+ }
417
+ }
418
+ },
419
+ {
420
+ name: `${projectionName}/cursor`,
421
+ factory: "messageBusSubscriptionCursor",
422
+ completeWhenDepsComplete: false,
423
+ errorWhenDepsError: false
424
+ }
425
+ );
426
+ return {
427
+ available,
428
+ availablePullId,
429
+ cursor,
430
+ status,
431
+ issues,
432
+ ack(seq, commandOpts = {}) {
433
+ return publishCommand(commands, {
434
+ kind: "ack",
435
+ topic: sub.topic,
436
+ subscriptionId: sub.subscriptionId,
437
+ seq,
438
+ ...commandOpts.commandId === void 0 ? {} : { commandId: commandOpts.commandId }
439
+ });
440
+ },
441
+ seek(nextSeq, commandOpts = {}) {
442
+ return publishCommand(commands, {
443
+ kind: "seek",
444
+ topic: sub.topic,
445
+ subscriptionId: sub.subscriptionId,
446
+ nextSeq,
447
+ ...commandOpts.commandId === void 0 ? {} : { commandId: commandOpts.commandId }
448
+ });
449
+ },
450
+ close(commandOpts = {}) {
451
+ return publishCommand(commands, {
452
+ kind: "close-subscription",
453
+ topic: sub.topic,
454
+ subscriptionId: sub.subscriptionId,
455
+ ...commandOpts.commandId === void 0 ? {} : { commandId: commandOpts.commandId }
456
+ });
457
+ }
458
+ };
323
459
  }
324
460
  };
325
- dynamicHubStates.set(hub, {
326
- graph,
327
- name,
328
- maxTopicLength,
329
- commandSources,
330
- commandBody,
331
- releaseEventsRetain
332
- });
333
- return hub;
461
+ registerMessageBusState(bus, state);
462
+ return bus;
463
+ }
464
+ function fromTopic(bus, topic) {
465
+ return bus.topic(topic).snapshot;
334
466
  }
335
- function fromHubTopic(hub, topic, opts = {}) {
336
- const state = requireDynamicHubState(hub);
337
- assertTopicKey(topic, "fromHubTopic", state.maxTopicLength);
338
- return state.graph.node(
339
- [hub.events],
467
+ function toTopic(graph, source, bus, topic, opts = {}) {
468
+ const state = getMessageBusState(bus);
469
+ if (state === void 0) throw new Error("toTopic: unknown message bus implementation");
470
+ if (state.graph !== graph) throw new Error("toTopic: bus and source graph must match");
471
+ assertTopicKey(topic, "toTopic");
472
+ const commands = graph.node(
473
+ [source],
340
474
  (ctx) => {
341
- for (const event of depBatch(ctx, 0) ?? []) {
342
- const typed = event;
343
- if (typed.kind !== "message" || typed.topic !== topic) continue;
475
+ for (const value of depBatch(ctx, 0) ?? []) {
476
+ const key = opts.keyOf?.(value);
477
+ const commandId = opts.commandIdOf?.(value);
344
478
  ctx.down([
345
479
  [
346
480
  "DATA",
347
481
  {
482
+ kind: "publish",
348
483
  topic,
349
- seq: typed.meta.seq,
350
- payload: typed.payload,
351
- timestampMs: typed.meta.timestampMs,
352
- ...typed.key === void 0 ? {} : { key: typed.key }
484
+ payload: value,
485
+ ...key === void 0 ? {} : { key },
486
+ ...commandId === void 0 ? {} : { commandId }
353
487
  }
354
488
  ]
355
489
  ]);
356
490
  }
357
491
  },
358
492
  {
359
- name: opts.name ?? `${state.name}/${topic}/fromHubTopic`,
360
- factory: "fromHubTopic",
493
+ name: opts.name ?? `${state.name}/${topic}/toTopic`,
494
+ factory: "toTopic",
361
495
  meta: { topic },
362
496
  completeWhenDepsComplete: false,
363
497
  errorWhenDepsError: false
364
498
  }
365
499
  );
500
+ const releaseSource = attachMessageBusCommandSource(
501
+ graph,
502
+ bus,
503
+ commands
504
+ );
505
+ let released = false;
506
+ return {
507
+ commands,
508
+ release() {
509
+ if (released) return;
510
+ released = true;
511
+ releaseSource();
512
+ }
513
+ };
366
514
  }
367
- function toHubTopic(graph, source, hub, topic, opts = {}) {
368
- const state = requireDynamicHubState(hub);
369
- assertTopicKey(topic, "toHubTopic", state.maxTopicLength);
370
- if (state.graph !== graph) throw new Error("toHubTopic: hub and source graph must match");
371
- if (isReachableUpstream(source, hub.command)) {
372
- throw new Error("toHubTopic: source already depends on hub command path");
373
- }
374
- const commands = graph.node(
375
- [source],
376
- (ctx) => {
377
- for (const value of depBatch(ctx, 0) ?? []) {
378
- try {
379
- const key = opts.keyOf?.(value);
380
- ctx.down([
381
- [
382
- "DATA",
383
- {
384
- kind: "publish",
385
- topic,
386
- payload: value,
387
- ...key === void 0 ? {} : { key }
388
- }
389
- ]
390
- ]);
391
- } catch (error) {
392
- ctx.down([
393
- [
394
- "DATA",
395
- {
396
- kind: "invalid",
397
- topic,
398
- error: error instanceof Error ? error.message : String(error)
399
- }
400
- ]
401
- ]);
402
- }
403
- }
404
- },
405
- {
406
- name: opts.name ?? `${state.name}/${topic}/toHubTopic`,
407
- factory: "toHubTopic",
408
- meta: { topic },
409
- completeWhenDepsComplete: false,
410
- errorWhenDepsError: false
515
+ function reduceMessageBusCommand(state, command) {
516
+ const malformed = validateCommand(command);
517
+ if (malformed !== void 0) return rejectCommand(state, command, malformed);
518
+ if (command.commandId !== void 0) {
519
+ if (state.seenCommandIds.has(command.commandId)) {
520
+ return duplicateCommandEvents(state, command, "duplicate commandId");
411
521
  }
412
- );
413
- const commandSource = commands;
414
- state.commandSources.push(commandSource);
415
- try {
416
- hub.command.replaceDeps([...state.commandSources], state.commandBody);
417
- } catch (error) {
418
- state.commandSources.splice(state.commandSources.indexOf(commandSource), 1);
419
- releaseGraphNodes(graph, [commands], {
420
- reason: "toHubTopic failed command wiring"
421
- });
422
- throw error;
522
+ state.seenCommandIds.add(command.commandId);
423
523
  }
424
- return { commands };
425
- }
426
- function fromTopic(bus, topic) {
427
- return bus.topic(topic);
428
- }
429
- function toTopic(graph, source, bus, topic, opts = {}) {
430
- const state = busStates.get(bus);
431
- if (state === void 0) throw new Error("toTopic: unknown message bus implementation");
432
- if (state.graph !== graph) throw new Error("toTopic: bus and source graph must match");
433
- const record = requireTopicRecord(state, topic);
434
- const name = opts.name ?? `toTopic/${topic}`;
435
- const producer = graph.node(
436
- [source],
437
- (ctx) => {
438
- for (const value of depBatch(ctx, 0) ?? []) {
439
- try {
440
- const key = opts.keyOf?.(value);
441
- const envelope = {
442
- topic,
443
- seq: ++state.seq,
444
- payload: value,
445
- timestampMs: state.now(),
446
- ...key === void 0 ? {} : { key }
447
- };
448
- ctx.down([
449
- [
450
- "DATA",
451
- {
452
- kind: "publish",
453
- envelope
454
- }
455
- ]
456
- ]);
457
- } catch (error) {
458
- ctx.down([["DATA", { kind: "error", topic, error }]]);
459
- }
524
+ if (command.kind === "publish" && command.idempotencyKey !== void 0 && state.seenIdempotencyKeys.has(idempotencyKey(command.topic, command.idempotencyKey))) {
525
+ return duplicateCommandEvents(state, command, "duplicate idempotencyKey");
526
+ }
527
+ switch (command.kind) {
528
+ case "ensure-topic":
529
+ return ensureTopic(state, command.topic, command.commandId);
530
+ case "close-topic": {
531
+ const topic = state.topics.get(command.topic);
532
+ if (topic === void 0) {
533
+ return issueEvents(state, command, "unknown-topic", `unknown topic '${command.topic}'`);
460
534
  }
461
- },
462
- {
463
- name,
464
- factory: "toTopic",
465
- meta: { topic },
466
- completeWhenDepsComplete: false,
467
- errorWhenDepsError: false
468
- }
469
- );
470
- record.producers.push(producer);
471
- record.node.replaceDeps([...record.producers], record.body);
472
- const events = graph.node(
473
- [producer, source],
474
- (ctx) => {
475
- for (const produced of depBatch(ctx, 0) ?? []) {
476
- const typed = produced;
477
- if (typed.kind === "publish") {
478
- ctx.down([
479
- [
480
- "DATA",
481
- {
482
- kind: "publish",
483
- topic,
484
- seq: typed.envelope.seq,
485
- payload: typed.envelope.payload
486
- }
487
- ]
488
- ]);
489
- } else {
490
- ctx.down([
491
- ["DATA", { kind: "error", topic, error: typed.error }]
492
- ]);
535
+ topic.closed = true;
536
+ return [
537
+ {
538
+ kind: "status",
539
+ status: statusFact(state, "topic-closed", {
540
+ topic: command.topic,
541
+ commandId: command.commandId
542
+ })
493
543
  }
494
- }
495
- const terminal = ctx.terminal[0];
496
- if (terminal !== false && terminal !== void 0 && terminal !== true) {
497
- ctx.down([
498
- ["DATA", { kind: "error", topic, error: terminal }]
499
- ]);
500
- }
501
- const sourceTerminal = ctx.terminal[1];
502
- if (sourceTerminal === true) {
503
- ctx.down([["DATA", { kind: "complete", topic }]]);
504
- } else if (sourceTerminal !== false && sourceTerminal !== void 0) {
505
- ctx.down([
506
- ["DATA", { kind: "error", topic, error: sourceTerminal }]
507
- ]);
508
- }
509
- },
510
- {
511
- name: `${name}/events`,
512
- factory: "toTopicEvents",
513
- meta: { topic },
514
- completeWhenDepsComplete: false,
515
- errorWhenDepsError: false,
516
- terminalAsRealInput: true
544
+ ];
517
545
  }
518
- );
519
- return { events };
520
- }
521
- function requireTopic(state, topic) {
522
- return requireTopicRecord(state, topic).node;
523
- }
524
- function requireTopicRecord(state, topic) {
525
- const record = state.records.get(topic);
526
- if (record === void 0) throw new Error(`messageBus: unknown topic '${topic}'`);
527
- return record;
528
- }
529
- function uniqueTopics(topics, maxTopicLength) {
530
- const unique = [...new Set(topics)];
531
- if (unique.length !== topics.length) throw new Error("dynamicHub: duplicate topic");
532
- for (const topic of unique) assertTopicKey(topic, "dynamicHub", maxTopicLength);
533
- return Object.freeze(unique.sort());
534
- }
535
- function normalizeUnknownTopicPolicy(policy) {
536
- if (policy === void 0) return "error";
537
- if (policy === "drop" || policy === "error" || policy === "dead-letter" || policy === "create-as-fact") {
538
- return policy;
539
- }
540
- throw new Error("dynamicHub: unknownTopic policy is not recognized");
541
- }
542
- function normalizeHubLimit(value, fallback, owner) {
543
- if (value === void 0) return fallback;
544
- if (!Number.isInteger(value) || value < 1) {
545
- throw new Error(`${owner} must be a positive integer`);
546
+ case "topic-policy":
547
+ state.topicPolicy = command.topicPolicy;
548
+ return [
549
+ {
550
+ kind: "status",
551
+ status: statusFact(state, "projection-ready", {
552
+ commandId: command.commandId,
553
+ details: { topicPolicy: command.topicPolicy }
554
+ })
555
+ }
556
+ ];
557
+ case "publish":
558
+ return publishMessage(state, command);
559
+ case "ack":
560
+ return ackSubscription(state, command);
561
+ case "seek":
562
+ return seekSubscription(state, command);
563
+ case "close-subscription":
564
+ return closeSubscription(state, command);
546
565
  }
547
- return value;
548
- }
549
- function publishHubCommand(commandNode, command) {
550
- commandNode.down([["DATA", command]]);
551
- return command;
552
566
  }
553
- function parseDynamicHubCommand(value) {
554
- if (!isObjectRecord(value)) return "dynamicHub: command fact must be an object";
555
- const kind = value.kind;
556
- if (kind !== "create" && kind !== "delete" && kind !== "publish" && kind !== "subscribe" && kind !== "close") {
557
- return "dynamicHub: command kind is not recognized";
558
- }
559
- if (kind === "close") {
560
- return {
561
- kind,
562
- ...typeof value.key === "string" ? { key: value.key } : {},
563
- ...value.payload === void 0 ? {} : { payload: value.payload }
564
- };
565
- }
566
- const topic = value.topic;
567
- if (typeof topic !== "string" || topic.length === 0) {
568
- return "dynamicHub: command topic must be a non-empty string";
569
- }
570
- if (kind === "publish") {
571
- if (value.payload === void 0) return "dynamicHub: publish command payload is required";
572
- return {
573
- kind,
574
- topic,
575
- payload: value.payload,
576
- ...typeof value.key === "string" ? { key: value.key } : {}
577
- };
567
+ function publishMessage(state, command) {
568
+ let topic = state.topics.get(command.topic);
569
+ const events = [];
570
+ if (topic === void 0) {
571
+ if (state.topicPolicy !== "create-as-fact") {
572
+ return issueEvents(state, command, "unknown-topic", `unknown topic '${command.topic}'`);
573
+ }
574
+ events.push(...ensureTopic(state, command.topic, command.commandId));
575
+ topic = state.topics.get(command.topic);
578
576
  }
579
- return {
580
- kind,
581
- topic,
582
- ...typeof value.key === "string" ? { key: value.key } : {},
583
- ...value.payload === void 0 ? {} : { payload: value.payload }
577
+ if (topic === void 0)
578
+ return issueEvents(state, command, "unknown-topic", `unknown topic '${command.topic}'`);
579
+ if (topic.closed)
580
+ return issueEvents(state, command, "closed-topic", `closed topic '${command.topic}'`);
581
+ const message = {
582
+ topic: command.topic,
583
+ seq: topic.nextSeq++,
584
+ payload: command.payload,
585
+ timestampMs: state.now(),
586
+ ...command.key === void 0 ? {} : { key: command.key },
587
+ ...command.idempotencyKey === void 0 ? {} : { idempotencyKey: command.idempotencyKey },
588
+ ...command.commandId === void 0 ? {} : { commandId: command.commandId }
584
589
  };
585
- }
586
- function isObjectRecord(value) {
587
- return typeof value === "object" && value !== null && !Array.isArray(value);
588
- }
589
- function readHubTimestamp(now) {
590
- try {
591
- const timestampMs = now();
592
- return Number.isFinite(timestampMs) ? timestampMs : "dynamicHub: now() must return a finite number";
593
- } catch (error) {
594
- return `dynamicHub: now() threw: ${error instanceof Error ? error.message : String(error)}`;
590
+ if (command.idempotencyKey !== void 0) {
591
+ state.seenIdempotencyKeys.add(idempotencyKey(command.topic, command.idempotencyKey));
595
592
  }
593
+ topic.messages.push(message);
594
+ events.push({ kind: "message", message });
595
+ events.push({
596
+ kind: "status",
597
+ status: statusFact(state, "message-published", {
598
+ topic: command.topic,
599
+ seq: message.seq,
600
+ commandId: command.commandId
601
+ })
602
+ });
603
+ events.push(...trimRetention(state, command.topic, topic));
604
+ return events;
596
605
  }
597
- function timestampOrFallback(now) {
598
- const timestampMs = readHubTimestamp(now);
599
- return typeof timestampMs === "number" ? timestampMs : Date.now();
600
- }
601
- function reduceDynamicHubCommand(runtime, command, unknownTopic, maxTopics, maxTopicLength, now) {
602
- const topic = "topic" in command ? command.topic : void 0;
603
- if (topic !== void 0) {
604
- const topicError = validateTopicKey(topic, "dynamicHub", maxTopicLength);
605
- if (topicError !== void 0) {
606
- return [hubError(runtime, command, topicError, timestampOrFallback(now))];
606
+ function ensureTopic(state, topic, commandId) {
607
+ assertTopicKey(topic, "messageBus");
608
+ if (!state.topics.has(topic)) state.topics.set(topic, makeTopicState());
609
+ return [
610
+ {
611
+ kind: "status",
612
+ status: statusFact(state, "topic-created", { topic, commandId })
607
613
  }
614
+ ];
615
+ }
616
+ function trimRetention(state, topicName, topic) {
617
+ const max = state.retention.maxMessages;
618
+ if (max === void 0 || topic.messages.length <= max) return [];
619
+ if (!Number.isInteger(max) || max < 1) {
620
+ return issueEvents(
621
+ state,
622
+ { kind: "publish", topic: topicName, payload: void 0 },
623
+ "policy-rejected",
624
+ "retention.maxMessages must be a positive integer"
625
+ );
608
626
  }
609
- if (!runtime.open && command.kind !== "close") {
610
- return [hubError(runtime, command, "dynamicHub: hub is closed", timestampOrFallback(now))];
611
- }
612
- switch (command.kind) {
613
- case "create": {
614
- const capacityError = canAddHubTopic(runtime, command.topic, maxTopics);
615
- if (capacityError !== void 0) {
616
- return [hubError(runtime, command, capacityError, timestampOrFallback(now))];
617
- }
618
- const timestampMs = readHubTimestamp(now);
619
- if (typeof timestampMs === "string")
620
- return [hubError(runtime, command, timestampMs, Date.now())];
621
- addHubTopic(runtime, command.topic);
622
- return [hubEvent(runtime, timestampMs, command)];
627
+ const trimCount = topic.messages.length - max;
628
+ topic.messages.splice(0, trimCount);
629
+ topic.headSeq = topic.messages[0]?.seq ?? topic.nextSeq;
630
+ const events = [
631
+ {
632
+ kind: "status",
633
+ status: statusFact(state, "retention-trimmed", {
634
+ topic: topicName,
635
+ headSeq: topic.headSeq,
636
+ details: { trimCount }
637
+ })
623
638
  }
624
- case "delete": {
625
- if (!hasHubTopic(runtime, command.topic)) {
626
- return unknownHubTopic(runtime, command, unknownTopic, now);
627
- }
628
- const timestampMs = readHubTimestamp(now);
629
- if (typeof timestampMs === "string")
630
- return [hubError(runtime, command, timestampMs, Date.now())];
631
- deleteHubTopic(runtime, command.topic);
632
- return [hubEvent(runtime, timestampMs, command)];
639
+ ];
640
+ for (const sub of state.subscriptions.values()) {
641
+ if (sub.closed || sub.topic !== topicName || sub.nextSeq >= topic.headSeq) continue;
642
+ sub.retentionGap = true;
643
+ events.push(
644
+ ...issueEvents(
645
+ state,
646
+ {
647
+ kind: "seek",
648
+ topic: topicName,
649
+ subscriptionId: sub.subscriptionId,
650
+ nextSeq: sub.nextSeq
651
+ },
652
+ "retention-gap",
653
+ `subscription '${sub.subscriptionId}' is before retained headSeq`
654
+ )
655
+ );
656
+ }
657
+ return events;
658
+ }
659
+ function ackSubscription(state, command) {
660
+ const topic = state.topics.get(command.topic);
661
+ if (topic === void 0)
662
+ return issueEvents(state, command, "unknown-topic", `unknown topic '${command.topic}'`);
663
+ const sub = getSubscription(state, command.topic, command.subscriptionId);
664
+ if (sub === void 0)
665
+ return issueEvents(
666
+ state,
667
+ command,
668
+ "unknown-subscription",
669
+ `unknown subscription '${command.subscriptionId}'`
670
+ );
671
+ if (sub.closed)
672
+ return issueEvents(state, command, "subscription-closed", "subscription is closed");
673
+ if (sub.retentionGap)
674
+ return issueEvents(state, command, "retention-gap", "subscription must seek before ack");
675
+ if (command.seq < sub.nextSeq)
676
+ return issueEvents(state, command, "source-cursor-stale", "ack is behind subscription cursor");
677
+ if (command.seq >= topic.nextSeq)
678
+ return issueEvents(state, command, "cursor-out-of-range", "ack is beyond topic tail");
679
+ sub.nextSeq = Math.max(sub.nextSeq, command.seq + 1);
680
+ return [
681
+ {
682
+ kind: "status",
683
+ status: statusFact(state, "subscription-acked", {
684
+ topic: command.topic,
685
+ subscriptionId: command.subscriptionId,
686
+ nextSeq: sub.nextSeq,
687
+ commandId: command.commandId
688
+ })
633
689
  }
634
- case "publish": {
635
- if (!hasHubTopic(runtime, command.topic)) {
636
- if (unknownTopic === "create-as-fact") {
637
- const capacityError = canAddHubTopic(runtime, command.topic, maxTopics);
638
- if (capacityError !== void 0) {
639
- return [hubError(runtime, command, capacityError, timestampOrFallback(now))];
640
- }
641
- const createTimestampMs = readHubTimestamp(now);
642
- if (typeof createTimestampMs === "string") {
643
- return [hubError(runtime, command, createTimestampMs, Date.now())];
644
- }
645
- const messageTimestampMs = readHubTimestamp(now);
646
- if (typeof messageTimestampMs === "string") {
647
- return [hubError(runtime, command, messageTimestampMs, Date.now())];
648
- }
649
- addHubTopic(runtime, command.topic);
650
- return [
651
- hubEvent(runtime, createTimestampMs, { kind: "create", topic: command.topic }),
652
- hubEvent(runtime, messageTimestampMs, {
653
- kind: "message",
654
- topic: command.topic,
655
- payload: command.payload,
656
- ...command.key === void 0 ? {} : { key: command.key }
657
- })
658
- ];
659
- }
660
- return unknownHubTopic(runtime, command, unknownTopic, now);
661
- }
662
- const timestampMs = readHubTimestamp(now);
663
- if (typeof timestampMs === "string")
664
- return [hubError(runtime, command, timestampMs, Date.now())];
665
- return [
666
- hubEvent(runtime, timestampMs, {
667
- kind: "message",
668
- topic: command.topic,
669
- payload: command.payload,
670
- ...command.key === void 0 ? {} : { key: command.key }
671
- })
672
- ];
690
+ ];
691
+ }
692
+ function seekSubscription(state, command) {
693
+ const topic = state.topics.get(command.topic);
694
+ if (topic === void 0)
695
+ return issueEvents(state, command, "unknown-topic", `unknown topic '${command.topic}'`);
696
+ const sub = getSubscription(state, command.topic, command.subscriptionId);
697
+ if (sub === void 0)
698
+ return issueEvents(
699
+ state,
700
+ command,
701
+ "unknown-subscription",
702
+ `unknown subscription '${command.subscriptionId}'`
703
+ );
704
+ if (sub.closed)
705
+ return issueEvents(state, command, "subscription-closed", "subscription is closed");
706
+ if (command.nextSeq < topic.headSeq)
707
+ return issueEvents(state, command, "retention-gap", "seek is before retained headSeq");
708
+ if (command.nextSeq > topic.nextSeq)
709
+ return issueEvents(state, command, "cursor-out-of-range", "seek is beyond topic tail");
710
+ sub.nextSeq = command.nextSeq;
711
+ sub.retentionGap = false;
712
+ return [
713
+ {
714
+ kind: "status",
715
+ status: statusFact(state, "subscription-sought", {
716
+ topic: command.topic,
717
+ subscriptionId: command.subscriptionId,
718
+ nextSeq: sub.nextSeq,
719
+ commandId: command.commandId
720
+ })
673
721
  }
674
- case "subscribe": {
675
- if (!hasHubTopic(runtime, command.topic)) {
676
- if (unknownTopic === "create-as-fact") {
677
- const capacityError = canAddHubTopic(runtime, command.topic, maxTopics);
678
- if (capacityError !== void 0) {
679
- return [hubError(runtime, command, capacityError, timestampOrFallback(now))];
680
- }
681
- const createTimestampMs = readHubTimestamp(now);
682
- if (typeof createTimestampMs === "string") {
683
- return [hubError(runtime, command, createTimestampMs, Date.now())];
684
- }
685
- const subscribeTimestampMs = readHubTimestamp(now);
686
- if (typeof subscribeTimestampMs === "string") {
687
- return [hubError(runtime, command, subscribeTimestampMs, Date.now())];
688
- }
689
- addHubTopic(runtime, command.topic);
690
- return [
691
- hubEvent(runtime, createTimestampMs, { kind: "create", topic: command.topic }),
692
- hubEvent(runtime, subscribeTimestampMs, command)
693
- ];
694
- }
695
- return unknownHubTopic(runtime, command, unknownTopic, now);
696
- }
697
- const timestampMs = readHubTimestamp(now);
698
- if (typeof timestampMs === "string")
699
- return [hubError(runtime, command, timestampMs, Date.now())];
700
- return [hubEvent(runtime, timestampMs, command)];
722
+ ];
723
+ }
724
+ function closeSubscription(state, command) {
725
+ if (!state.topics.has(command.topic))
726
+ return issueEvents(state, command, "unknown-topic", `unknown topic '${command.topic}'`);
727
+ const sub = getSubscription(state, command.topic, command.subscriptionId);
728
+ if (sub === void 0)
729
+ return issueEvents(
730
+ state,
731
+ command,
732
+ "unknown-subscription",
733
+ `unknown subscription '${command.subscriptionId}'`
734
+ );
735
+ sub.closed = true;
736
+ return [
737
+ {
738
+ kind: "status",
739
+ status: statusFact(state, "subscription-closed", {
740
+ topic: command.topic,
741
+ subscriptionId: command.subscriptionId,
742
+ nextSeq: sub.nextSeq,
743
+ commandId: command.commandId
744
+ })
701
745
  }
702
- case "close": {
703
- const timestampMs = readHubTimestamp(now);
704
- if (typeof timestampMs === "string")
705
- return [hubError(runtime, command, timestampMs, Date.now())];
706
- runtime.open = false;
707
- return [hubEvent(runtime, timestampMs, command)];
746
+ ];
747
+ }
748
+ function issueEvents(state, command, code, message) {
749
+ const topic = commandTopic(command);
750
+ const commandId = commandIdOf(command);
751
+ const issue = {
752
+ kind: "issue",
753
+ code,
754
+ message,
755
+ severity: "error",
756
+ source: "messageBus",
757
+ details: command,
758
+ metadata: topic === void 0 ? void 0 : { topic }
759
+ };
760
+ const entry = {
761
+ entrySeq: ++state.deadLetterSeq,
762
+ ...topic === void 0 ? {} : { topic },
763
+ ...isObjectRecord(command) ? { command } : {},
764
+ issue,
765
+ timestampMs: state.now()
766
+ };
767
+ state.deadLetters.push(entry);
768
+ return [
769
+ { kind: "issue", issue },
770
+ { kind: "dead-letter", entry },
771
+ {
772
+ kind: "status",
773
+ status: statusFact(state, "command-rejected", {
774
+ topic,
775
+ commandId,
776
+ issueCode: code
777
+ })
708
778
  }
709
- }
779
+ ];
710
780
  }
711
- function hubEvent(runtime, timestampMs, event) {
712
- const meta = nextHubMetadata(runtime, timestampMs);
713
- return {
714
- ...event,
715
- meta,
716
- status: snapshotHubStatus(runtime, meta, event.kind)
717
- };
781
+ function rejectCommand(state, command, reason) {
782
+ return issueEvents(state, command, "malformed-command", reason);
718
783
  }
719
- function hubError(runtime, command, error, timestampMs) {
720
- return hubEvent(runtime, timestampMs, {
721
- kind: "error",
722
- ...isObjectRecord(command) && typeof command.topic === "string" ? { topic: command.topic } : {},
723
- error,
724
- command
784
+ function duplicateCommandEvents(state, command, message) {
785
+ const status = statusFact(state, "duplicate-command", {
786
+ topic: "topic" in command ? command.topic : void 0,
787
+ commandId: command.commandId
725
788
  });
726
- }
727
- function unknownHubTopic(runtime, command, policy, now) {
728
- const topic = "topic" in command ? command.topic : void 0;
729
- const reason = `dynamicHub: unknown topic '${topic ?? ""}'`;
730
- if (policy === "drop") return [];
731
- if (policy === "dead-letter") {
789
+ if (state.dedupe.commandId === "issue") {
732
790
  return [
733
- hubEvent(runtime, timestampOrFallback(now), {
734
- kind: "dead-letter",
735
- ...topic === void 0 ? {} : { topic },
736
- reason,
737
- command
738
- })
791
+ { kind: "status", status },
792
+ ...issueEvents(state, command, "duplicate-command", message)
739
793
  ];
740
794
  }
741
- return [hubError(runtime, command, reason, timestampOrFallback(now))];
795
+ return [{ kind: "status", status }];
742
796
  }
743
- function nextHubMetadata(runtime, timestampMs) {
744
- runtime.seq += 1;
745
- runtime.cursor = runtime.seq;
746
- return { seq: runtime.seq, cursor: runtime.cursor, timestampMs };
747
- }
748
- function snapshotHubStatus(runtime, meta, kind) {
797
+ function statusFact(state, kind, fields) {
749
798
  return {
750
- open: runtime.open,
751
- topics: Object.freeze([...runtime.topics].sort()),
752
- seq: meta.seq,
753
- cursor: meta.cursor,
754
- lastEventKind: kind
799
+ kind,
800
+ timestampMs: state.now(),
801
+ ...fields.topic === void 0 ? {} : { topic: fields.topic },
802
+ ...fields.seq === void 0 ? {} : { seq: fields.seq },
803
+ ...fields.headSeq === void 0 ? {} : { headSeq: fields.headSeq },
804
+ ...fields.subscriptionId === void 0 ? {} : { subscriptionId: fields.subscriptionId },
805
+ ...fields.nextSeq === void 0 ? {} : { nextSeq: fields.nextSeq },
806
+ ...fields.commandId === void 0 ? {} : { commandId: fields.commandId },
807
+ ...fields.issueCode === void 0 ? {} : { issueCode: fields.issueCode },
808
+ ...fields.details === void 0 ? {} : { details: fields.details }
755
809
  };
756
810
  }
757
- function assertTopicKey(topic, owner, maxTopicLength) {
758
- const error = validateTopicKey(topic, owner, maxTopicLength);
759
- if (error !== void 0) throw new Error(error);
760
- }
761
- function validateTopicKey(topic, owner, maxTopicLength) {
762
- if (typeof topic !== "string" || topic.length === 0) {
763
- return `${owner}: topic must be a non-empty string`;
811
+ function validateCommand(command) {
812
+ if (!isObjectRecord(command)) return "command must be an object";
813
+ if (typeof command.kind !== "string") return "command kind is required";
814
+ if (!isMessageBusCommandKind(command.kind)) return `unknown command kind '${command.kind}'`;
815
+ if ("topic" in command) {
816
+ if (typeof command.topic !== "string") return "messageBus: topic must be a non-empty string";
817
+ const topicError = validateTopicKey(command.topic, "messageBus");
818
+ if (topicError !== void 0) return topicError;
819
+ }
820
+ if ("subscriptionId" in command && typeof command.subscriptionId !== "string") {
821
+ return "subscriptionId must be a string";
764
822
  }
765
- if (topic.length > maxTopicLength) {
766
- return `${owner}: topic exceeds maxTopicLength`;
823
+ if (command.kind === "publish" && command.payload === void 0)
824
+ return "publish payload is required";
825
+ if (command.kind === "ack" && !isPositiveSeq(command.seq))
826
+ return "ack seq must be a positive integer";
827
+ if (command.kind === "seek" && !isPositiveSeq(command.nextSeq)) {
828
+ return "seek nextSeq must be a positive integer";
829
+ }
830
+ if (command.kind === "topic-policy" && command.topicPolicy !== "strict" && command.topicPolicy !== "create-as-fact") {
831
+ return "topicPolicy is not recognized";
767
832
  }
768
833
  return void 0;
769
834
  }
770
- function hasHubTopic(runtime, topic) {
771
- return runtime.topics.includes(topic);
772
- }
773
- function addHubTopic(runtime, topic) {
774
- if (!hasHubTopic(runtime, topic)) runtime.topics = [...runtime.topics, topic];
775
- }
776
- function deleteHubTopic(runtime, topic) {
777
- runtime.topics = runtime.topics.filter((existing) => existing !== topic);
778
- }
779
- function canAddHubTopic(runtime, topic, maxTopics) {
780
- if (hasHubTopic(runtime, topic)) return void 0;
781
- return runtime.topics.length >= maxTopics ? "dynamicHub: topic count exceeds maxTopics" : void 0;
782
- }
783
- function isReachableUpstream(from, target) {
784
- const seen = /* @__PURE__ */ new Set();
785
- const stack = [from];
786
- while (stack.length > 0) {
787
- const node = stack.pop();
788
- if (node === void 0) continue;
789
- if (node === target) return true;
790
- if (seen.has(node)) continue;
791
- seen.add(node);
792
- for (const dep of node.deps) stack.push(dep);
793
- }
794
- return false;
835
+ function isMessageBusCommandKind(kind) {
836
+ return kind === "ensure-topic" || kind === "close-topic" || kind === "publish" || kind === "topic-policy" || kind === "ack" || kind === "seek" || kind === "close-subscription";
837
+ }
838
+ function catalogPage(state, params) {
839
+ const limit = positiveLimit(params.limit);
840
+ const topics = [...state.topics.entries()].filter(
841
+ ([topic, value]) => (params.includeClosed ? true : !value.closed) && (params.afterTopic === void 0 || topic > params.afterTopic)
842
+ ).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
843
+ const page = topics.slice(0, limit);
844
+ const hasMore = topics.length > limit;
845
+ return {
846
+ topics: page.map(([topic, value]) => ({
847
+ topic,
848
+ closed: value.closed,
849
+ headSeq: value.headSeq,
850
+ nextSeq: value.nextSeq,
851
+ messageCount: value.messages.length
852
+ })),
853
+ ...hasMore && page.length > 0 ? { nextAfterTopic: page[page.length - 1]?.[0] } : {},
854
+ hasMore
855
+ };
856
+ }
857
+ function topicPage(state, topicName, params) {
858
+ const topic = state.topics.get(topicName);
859
+ const start = params.afterSeq === void 0 ? topic?.headSeq ?? 1 : params.afterSeq + 1;
860
+ const all = (topic?.messages ?? []).filter((message) => message.seq >= start);
861
+ const limit = positiveLimit(params.limit);
862
+ const messages = all.slice(0, limit);
863
+ const hasMore = all.length > limit;
864
+ return {
865
+ topic: topicName,
866
+ messages,
867
+ fromSeq: start,
868
+ ...messages.length > 0 ? { throughSeq: messages[messages.length - 1]?.seq } : {},
869
+ ...hasMore && messages.length > 0 ? { nextAfterSeq: messages[messages.length - 1]?.seq } : {},
870
+ hasMore
871
+ };
872
+ }
873
+ function availablePage(state, sub, params) {
874
+ const cursor = cursorSnapshot(state, sub);
875
+ const start = params.afterSeq === void 0 ? sub.nextSeq : params.afterSeq + 1;
876
+ const topic = state.topics.get(sub.topic);
877
+ const all = sub.retentionGap ? [] : (topic?.messages ?? []).filter((message) => message.seq >= start);
878
+ const limit = positiveLimit(params.limit);
879
+ const messages = all.slice(0, limit);
880
+ const hasMore = all.length > limit;
881
+ return {
882
+ topic: sub.topic,
883
+ subscriptionId: sub.subscriptionId,
884
+ cursor,
885
+ messages,
886
+ fromSeq: start,
887
+ ...messages.length > 0 ? { throughSeq: messages[messages.length - 1]?.seq } : {},
888
+ ...hasMore && messages.length > 0 ? { nextAfterSeq: messages[messages.length - 1]?.seq } : {},
889
+ hasMore
890
+ };
891
+ }
892
+ function deadLetterPage(state, params) {
893
+ const limit = positiveLimit(params.limit);
894
+ const entries = state.deadLetters.filter((entry) => {
895
+ if (params.afterEntrySeq !== void 0 && entry.entrySeq <= params.afterEntrySeq) return false;
896
+ if (params.topic !== void 0 && entry.topic !== params.topic) return false;
897
+ if (params.code !== void 0 && entry.issue.code !== params.code) return false;
898
+ return true;
899
+ });
900
+ const page = entries.slice(0, limit);
901
+ const hasMore = entries.length > limit;
902
+ return {
903
+ entries: page,
904
+ ...hasMore && page.length > 0 ? { nextAfterEntrySeq: page[page.length - 1]?.entrySeq } : {},
905
+ hasMore
906
+ };
907
+ }
908
+ function cursorSnapshot(state, sub) {
909
+ const topic = state.topics.get(sub.topic);
910
+ return {
911
+ topic: sub.topic,
912
+ subscriptionId: sub.subscriptionId,
913
+ nextSeq: sub.nextSeq,
914
+ closed: sub.closed,
915
+ retentionGap: sub.retentionGap,
916
+ headSeq: topic?.headSeq ?? 1
917
+ };
918
+ }
919
+ function ensureSubscription(state, opts) {
920
+ const key = `${opts.topic}\0${opts.subscriptionId}`;
921
+ const existing = state.subscriptions.get(key);
922
+ if (existing !== void 0) return existing;
923
+ const topic = state.topics.get(opts.topic);
924
+ const nextSeq = opts.from === "earliest" ? topic?.headSeq ?? 1 : opts.from === "latest" ? topic?.nextSeq ?? 1 : opts.from;
925
+ const sub = {
926
+ topic: opts.topic,
927
+ subscriptionId: opts.subscriptionId,
928
+ nextSeq,
929
+ closed: false,
930
+ retentionGap: topic !== void 0 && nextSeq < topic.headSeq
931
+ };
932
+ state.subscriptions.set(key, sub);
933
+ return sub;
795
934
  }
796
- function requireDynamicHubState(hub) {
797
- const state = dynamicHubStates.get(hub);
798
- if (state === void 0) throw new Error("dynamicHub: unknown hub implementation");
799
- return state;
935
+ function getSubscription(state, topic, subscriptionId) {
936
+ return state.subscriptions.get(`${topic}\0${subscriptionId}`);
800
937
  }
801
938
  // Annotate the CommonJS export names for ESM import in node:
802
939
  0 && (module.exports = {
@@ -808,11 +945,11 @@ function requireDynamicHubState(hub) {
808
945
  SPAWNS_TOPIC,
809
946
  STANDARD_TOPICS,
810
947
  TODOS_TOPIC,
811
- dynamicHub,
812
- fromHubTopic,
948
+ eventMessage,
949
+ eventMessageIssue,
813
950
  fromTopic,
951
+ isEventMessage,
814
952
  messageBus,
815
- toHubTopic,
816
953
  toTopic
817
954
  });
818
955
  //# sourceMappingURL=index.cjs.map