@graphrefly/graphrefly 0.45.0 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (714) hide show
  1. package/README.md +1 -2
  2. package/dist/_internal-B23BagFd.d.cts +33 -0
  3. package/dist/_internal-B23BagFd.d.ts +33 -0
  4. package/dist/adaptive-rate-limiter-Dch_xYIi.d.cts +111 -0
  5. package/dist/adaptive-rate-limiter-Dch_xYIi.d.ts +111 -0
  6. package/dist/agents-C0Ji9ldU.d.cts +629 -0
  7. package/dist/agents-C9zexT7I.d.ts +629 -0
  8. package/dist/audit-BAXb3VOg.d.ts +246 -0
  9. package/dist/audit-C_bPfkqS.d.cts +246 -0
  10. package/dist/backoff-7KIK3WQW.js +24 -0
  11. package/dist/backoff-7KIK3WQW.js.map +1 -0
  12. package/dist/backoff-Bnb9OoPh.d.cts +6 -0
  13. package/dist/backoff-Bnb9OoPh.d.ts +6 -0
  14. package/dist/base/composition/index.cjs +865 -0
  15. package/dist/base/composition/index.cjs.map +1 -0
  16. package/dist/base/composition/index.d.cts +468 -0
  17. package/dist/base/composition/index.d.ts +468 -0
  18. package/dist/base/composition/index.js +40 -0
  19. package/dist/base/composition/index.js.map +1 -0
  20. package/dist/base/index.cjs +6390 -0
  21. package/dist/base/index.cjs.map +1 -0
  22. package/dist/base/index.d.cts +21 -0
  23. package/dist/base/index.d.ts +21 -0
  24. package/dist/base/index.js +259 -0
  25. package/dist/base/index.js.map +1 -0
  26. package/dist/base/io/index.cjs +3270 -0
  27. package/dist/base/io/index.cjs.map +1 -0
  28. package/dist/base/io/index.d.cts +2245 -0
  29. package/dist/base/io/index.d.ts +2245 -0
  30. package/dist/base/io/index.js +117 -0
  31. package/dist/base/io/index.js.map +1 -0
  32. package/dist/base/meta/index.cjs +43 -0
  33. package/dist/base/meta/index.cjs.map +1 -0
  34. package/dist/base/meta/index.d.cts +45 -0
  35. package/dist/base/meta/index.d.ts +45 -0
  36. package/dist/base/meta/index.js +13 -0
  37. package/dist/base/meta/index.js.map +1 -0
  38. package/dist/base/mutation/index.cjs +200 -0
  39. package/dist/base/mutation/index.cjs.map +1 -0
  40. package/dist/base/mutation/index.d.cts +177 -0
  41. package/dist/base/mutation/index.d.ts +177 -0
  42. package/dist/base/mutation/index.js +22 -0
  43. package/dist/base/mutation/index.js.map +1 -0
  44. package/dist/base/render/index.cjs +1120 -0
  45. package/dist/base/render/index.cjs.map +1 -0
  46. package/dist/base/render/index.d.cts +227 -0
  47. package/dist/base/render/index.d.ts +227 -0
  48. package/dist/base/render/index.js +24 -0
  49. package/dist/base/render/index.js.map +1 -0
  50. package/dist/base/sources/browser/index.cjs +172 -0
  51. package/dist/base/sources/browser/index.cjs.map +1 -0
  52. package/dist/base/sources/browser/index.d.cts +84 -0
  53. package/dist/base/sources/browser/index.d.ts +84 -0
  54. package/dist/base/sources/browser/index.js +151 -0
  55. package/dist/base/sources/browser/index.js.map +1 -0
  56. package/dist/base/sources/event/index.cjs +98 -0
  57. package/dist/base/sources/event/index.cjs.map +1 -0
  58. package/dist/base/sources/event/index.d.cts +91 -0
  59. package/dist/base/sources/event/index.d.ts +91 -0
  60. package/dist/base/sources/event/index.js +13 -0
  61. package/dist/base/sources/event/index.js.map +1 -0
  62. package/dist/base/sources/index.cjs +755 -0
  63. package/dist/base/sources/index.cjs.map +1 -0
  64. package/dist/base/sources/index.d.cts +357 -0
  65. package/dist/base/sources/index.d.ts +357 -0
  66. package/dist/base/sources/index.js +42 -0
  67. package/dist/base/sources/index.js.map +1 -0
  68. package/dist/base/sources/node/index.cjs +320 -0
  69. package/dist/base/sources/node/index.cjs.map +1 -0
  70. package/dist/base/sources/node/index.d.cts +185 -0
  71. package/dist/base/sources/node/index.d.ts +185 -0
  72. package/dist/base/sources/node/index.js +306 -0
  73. package/dist/base/sources/node/index.js.map +1 -0
  74. package/dist/base/utils/index.cjs +37 -0
  75. package/dist/base/utils/index.cjs.map +1 -0
  76. package/dist/base/utils/index.d.cts +37 -0
  77. package/dist/base/utils/index.d.ts +37 -0
  78. package/dist/base/utils/index.js +11 -0
  79. package/dist/base/utils/index.js.map +1 -0
  80. package/dist/base/worker/index.cjs +548 -0
  81. package/dist/base/worker/index.cjs.map +1 -0
  82. package/dist/base/worker/index.d.cts +207 -0
  83. package/dist/base/worker/index.d.ts +207 -0
  84. package/dist/base/worker/index.js +20 -0
  85. package/dist/base/worker/index.js.map +1 -0
  86. package/dist/breaker-C9skL3d8.d.ts +175 -0
  87. package/dist/breaker-ugSdq54q.d.cts +175 -0
  88. package/dist/cascading-CSSbKGrJ.d.ts +199 -0
  89. package/dist/cascading-baGkiihI.d.cts +199 -0
  90. package/dist/chunk-22SG74BD.js +207 -0
  91. package/dist/chunk-22SG74BD.js.map +1 -0
  92. package/dist/chunk-255UCBG4.js +58 -0
  93. package/dist/chunk-255UCBG4.js.map +1 -0
  94. package/dist/chunk-2LO3EL4W.js +1 -0
  95. package/dist/chunk-2LO3EL4W.js.map +1 -0
  96. package/dist/chunk-2OB3CEJS.js +1065 -0
  97. package/dist/chunk-2OB3CEJS.js.map +1 -0
  98. package/dist/chunk-36NMM65U.js +144 -0
  99. package/dist/chunk-36NMM65U.js.map +1 -0
  100. package/dist/chunk-3CEXCBN6.js +1 -0
  101. package/dist/chunk-3CEXCBN6.js.map +1 -0
  102. package/dist/chunk-3MUSLI6E.js +105 -0
  103. package/dist/chunk-3MUSLI6E.js.map +1 -0
  104. package/dist/chunk-3PSLNJDU.js +884 -0
  105. package/dist/chunk-3PSLNJDU.js.map +1 -0
  106. package/dist/chunk-42FQ27MQ.js +594 -0
  107. package/dist/chunk-42FQ27MQ.js.map +1 -0
  108. package/dist/chunk-4GYMCUDZ.js +1085 -0
  109. package/dist/chunk-4GYMCUDZ.js.map +1 -0
  110. package/dist/chunk-4S53H2KR.js +382 -0
  111. package/dist/chunk-4S53H2KR.js.map +1 -0
  112. package/dist/chunk-4XCHZRUJ.js +128 -0
  113. package/dist/chunk-4XCHZRUJ.js.map +1 -0
  114. package/dist/chunk-5IMMNARC.js +1153 -0
  115. package/dist/chunk-5IMMNARC.js.map +1 -0
  116. package/dist/chunk-6XZYT4SW.js +256 -0
  117. package/dist/chunk-6XZYT4SW.js.map +1 -0
  118. package/dist/chunk-7EGRP2VX.js +76 -0
  119. package/dist/chunk-7EGRP2VX.js.map +1 -0
  120. package/dist/chunk-A7KV5UK4.js +150 -0
  121. package/dist/chunk-A7KV5UK4.js.map +1 -0
  122. package/dist/chunk-APY2SS5X.js +156 -0
  123. package/dist/chunk-APY2SS5X.js.map +1 -0
  124. package/dist/chunk-AZDQPQ3V.js +66 -0
  125. package/dist/chunk-AZDQPQ3V.js.map +1 -0
  126. package/dist/chunk-BU3SEFA5.js +90 -0
  127. package/dist/chunk-BU3SEFA5.js.map +1 -0
  128. package/dist/chunk-BXGZFGZ4.js +189 -0
  129. package/dist/chunk-BXGZFGZ4.js.map +1 -0
  130. package/dist/chunk-CGHORL6G.js +579 -0
  131. package/dist/chunk-CGHORL6G.js.map +1 -0
  132. package/dist/chunk-CXANAIZU.js +530 -0
  133. package/dist/chunk-CXANAIZU.js.map +1 -0
  134. package/dist/chunk-CZQHCKKG.js +1 -0
  135. package/dist/chunk-CZQHCKKG.js.map +1 -0
  136. package/dist/chunk-DKNHAICT.js +133 -0
  137. package/dist/chunk-DKNHAICT.js.map +1 -0
  138. package/dist/chunk-DM4OMPWK.js +584 -0
  139. package/dist/chunk-DM4OMPWK.js.map +1 -0
  140. package/dist/chunk-DMSNO6ZB.js +452 -0
  141. package/dist/chunk-DMSNO6ZB.js.map +1 -0
  142. package/dist/chunk-E5OZPDIW.js +229 -0
  143. package/dist/chunk-E5OZPDIW.js.map +1 -0
  144. package/dist/chunk-EHRRQ4IC.js +211 -0
  145. package/dist/chunk-EHRRQ4IC.js.map +1 -0
  146. package/dist/chunk-EVYY4X5A.js +509 -0
  147. package/dist/chunk-EVYY4X5A.js.map +1 -0
  148. package/dist/chunk-FDFD67UO.js +1 -0
  149. package/dist/chunk-FDFD67UO.js.map +1 -0
  150. package/dist/chunk-FMPF42Q4.js +13 -0
  151. package/dist/chunk-FMPF42Q4.js.map +1 -0
  152. package/dist/chunk-FW23JYNQ.js +454 -0
  153. package/dist/chunk-FW23JYNQ.js.map +1 -0
  154. package/dist/chunk-GWRNLJNW.js +2508 -0
  155. package/dist/chunk-GWRNLJNW.js.map +1 -0
  156. package/dist/chunk-HL7HUJIX.js +1 -0
  157. package/dist/chunk-HL7HUJIX.js.map +1 -0
  158. package/dist/chunk-IHTWQEDR.js +169 -0
  159. package/dist/chunk-IHTWQEDR.js.map +1 -0
  160. package/dist/chunk-IJRR6YAI.js +128 -0
  161. package/dist/chunk-IJRR6YAI.js.map +1 -0
  162. package/dist/chunk-JGFRAFDL.js +221 -0
  163. package/dist/chunk-JGFRAFDL.js.map +1 -0
  164. package/dist/chunk-JKTC747G.js +725 -0
  165. package/dist/chunk-JKTC747G.js.map +1 -0
  166. package/dist/chunk-KN3H5CNT.js +11 -0
  167. package/dist/chunk-KN3H5CNT.js.map +1 -0
  168. package/dist/chunk-KPG3DGLA.js +1 -0
  169. package/dist/chunk-KPG3DGLA.js.map +1 -0
  170. package/dist/chunk-KRNQ6RGQ.js +1 -0
  171. package/dist/chunk-KRNQ6RGQ.js.map +1 -0
  172. package/dist/chunk-MLTPJMH6.js +417 -0
  173. package/dist/chunk-MLTPJMH6.js.map +1 -0
  174. package/dist/chunk-N3SZ7BMH.js +95 -0
  175. package/dist/chunk-N3SZ7BMH.js.map +1 -0
  176. package/dist/chunk-NDUD3IMO.js +540 -0
  177. package/dist/chunk-NDUD3IMO.js.map +1 -0
  178. package/dist/chunk-NY2PYHNC.js +873 -0
  179. package/dist/chunk-NY2PYHNC.js.map +1 -0
  180. package/dist/chunk-O3MT7DYI.js +225 -0
  181. package/dist/chunk-O3MT7DYI.js.map +1 -0
  182. package/dist/chunk-OCUDSN63.js +2386 -0
  183. package/dist/chunk-OCUDSN63.js.map +1 -0
  184. package/dist/chunk-OIWU3NYV.js +199 -0
  185. package/dist/chunk-OIWU3NYV.js.map +1 -0
  186. package/dist/chunk-OQUIJT7A.js +1 -0
  187. package/dist/chunk-OQUIJT7A.js.map +1 -0
  188. package/dist/chunk-P5LBT622.js +105 -0
  189. package/dist/chunk-P5LBT622.js.map +1 -0
  190. package/dist/chunk-PKGQG5QQ.js +519 -0
  191. package/dist/chunk-PKGQG5QQ.js.map +1 -0
  192. package/dist/chunk-PKPO3JTZ.js +561 -0
  193. package/dist/chunk-PKPO3JTZ.js.map +1 -0
  194. package/dist/chunk-PL5UDIQ5.js +118 -0
  195. package/dist/chunk-PL5UDIQ5.js.map +1 -0
  196. package/dist/chunk-PZWISPIQ.js +432 -0
  197. package/dist/chunk-PZWISPIQ.js.map +1 -0
  198. package/dist/chunk-Q3EYOCZB.js +510 -0
  199. package/dist/chunk-Q3EYOCZB.js.map +1 -0
  200. package/dist/chunk-QMBYUVRL.js +15 -0
  201. package/dist/chunk-QMBYUVRL.js.map +1 -0
  202. package/dist/chunk-RAGGHLCV.js +200 -0
  203. package/dist/chunk-RAGGHLCV.js.map +1 -0
  204. package/dist/chunk-RJOG4IJU.js +1039 -0
  205. package/dist/chunk-RJOG4IJU.js.map +1 -0
  206. package/dist/chunk-SOOKUYVM.js +403 -0
  207. package/dist/chunk-SOOKUYVM.js.map +1 -0
  208. package/dist/chunk-T5BN5KG7.js +1 -0
  209. package/dist/chunk-T5BN5KG7.js.map +1 -0
  210. package/dist/chunk-TNX5ZGDJ.js +574 -0
  211. package/dist/chunk-TNX5ZGDJ.js.map +1 -0
  212. package/dist/chunk-TP7244Y6.js +207 -0
  213. package/dist/chunk-TP7244Y6.js.map +1 -0
  214. package/dist/chunk-TSBFTJKM.js +57 -0
  215. package/dist/chunk-TSBFTJKM.js.map +1 -0
  216. package/dist/chunk-URQ2CBBF.js +143 -0
  217. package/dist/chunk-URQ2CBBF.js.map +1 -0
  218. package/dist/chunk-VLAGJZSL.js +1079 -0
  219. package/dist/chunk-VLAGJZSL.js.map +1 -0
  220. package/dist/chunk-W2BOPXTI.js +1 -0
  221. package/dist/chunk-W2BOPXTI.js.map +1 -0
  222. package/dist/chunk-Y52CS6YA.js +88 -0
  223. package/dist/chunk-Y52CS6YA.js.map +1 -0
  224. package/dist/chunk-YCBUWK77.js +92 -0
  225. package/dist/chunk-YCBUWK77.js.map +1 -0
  226. package/dist/chunk-YJ4U2D2C.js +314 -0
  227. package/dist/chunk-YJ4U2D2C.js.map +1 -0
  228. package/dist/chunk-Z4YXAUDN.js +239 -0
  229. package/dist/chunk-Z4YXAUDN.js.map +1 -0
  230. package/dist/chunk-Z65DVDEQ.js +146 -0
  231. package/dist/chunk-Z65DVDEQ.js.map +1 -0
  232. package/dist/chunk-Z6EGP5D7.js +92 -0
  233. package/dist/chunk-Z6EGP5D7.js.map +1 -0
  234. package/dist/chunk-ZT4WMQW4.js +1575 -0
  235. package/dist/chunk-ZT4WMQW4.js.map +1 -0
  236. package/dist/chunk-ZVXXDWIB.js +1282 -0
  237. package/dist/chunk-ZVXXDWIB.js.map +1 -0
  238. package/dist/compat/index.cjs +3150 -6
  239. package/dist/compat/index.cjs.map +1 -1
  240. package/dist/compat/index.d.cts +116 -1
  241. package/dist/compat/index.d.ts +116 -1
  242. package/dist/compat/index.js +175 -2
  243. package/dist/compat/index.js.map +1 -1
  244. package/dist/compat/jotai/index.cjs +130 -2
  245. package/dist/compat/jotai/index.cjs.map +1 -1
  246. package/dist/compat/jotai/index.d.cts +2 -1
  247. package/dist/compat/jotai/index.d.ts +2 -1
  248. package/dist/compat/jotai/index.js +7 -2
  249. package/dist/compat/jotai/index.js.map +1 -1
  250. package/dist/compat/nanostores/index.cjs +186 -2
  251. package/dist/compat/nanostores/index.cjs.map +1 -1
  252. package/dist/compat/nanostores/index.d.cts +2 -1
  253. package/dist/compat/nanostores/index.d.ts +2 -1
  254. package/dist/compat/nanostores/index.js +21 -2
  255. package/dist/compat/nanostores/index.js.map +1 -1
  256. package/dist/compat/nestjs/index.cjs +2291 -6
  257. package/dist/compat/nestjs/index.cjs.map +1 -1
  258. package/dist/compat/nestjs/index.d.cts +10 -1
  259. package/dist/compat/nestjs/index.d.ts +10 -1
  260. package/dist/compat/nestjs/index.js +76 -2
  261. package/dist/compat/nestjs/index.js.map +1 -1
  262. package/dist/compat/react/index.cjs +95 -2
  263. package/dist/compat/react/index.cjs.map +1 -1
  264. package/dist/compat/react/index.d.cts +2 -1
  265. package/dist/compat/react/index.d.ts +2 -1
  266. package/dist/compat/react/index.js +11 -2
  267. package/dist/compat/react/index.js.map +1 -1
  268. package/dist/compat/solid/index.cjs +82 -2
  269. package/dist/compat/solid/index.cjs.map +1 -1
  270. package/dist/compat/solid/index.d.cts +2 -1
  271. package/dist/compat/solid/index.d.ts +2 -1
  272. package/dist/compat/solid/index.js +11 -2
  273. package/dist/compat/solid/index.js.map +1 -1
  274. package/dist/compat/svelte/index.cjs +85 -2
  275. package/dist/compat/svelte/index.cjs.map +1 -1
  276. package/dist/compat/svelte/index.d.cts +2 -1
  277. package/dist/compat/svelte/index.d.ts +2 -1
  278. package/dist/compat/svelte/index.js +11 -2
  279. package/dist/compat/svelte/index.js.map +1 -1
  280. package/dist/compat/vue/index.cjs +100 -2
  281. package/dist/compat/vue/index.cjs.map +1 -1
  282. package/dist/compat/vue/index.d.cts +3 -1
  283. package/dist/compat/vue/index.d.ts +3 -1
  284. package/dist/compat/vue/index.js +11 -2
  285. package/dist/compat/vue/index.js.map +1 -1
  286. package/dist/compat/zustand/index.cjs +50 -2
  287. package/dist/compat/zustand/index.cjs.map +1 -1
  288. package/dist/compat/zustand/index.d.cts +2 -1
  289. package/dist/compat/zustand/index.d.ts +2 -1
  290. package/dist/compat/zustand/index.js +7 -2
  291. package/dist/compat/zustand/index.js.map +1 -1
  292. package/dist/distill-De6Rnn15.d.cts +48 -0
  293. package/dist/distill-De6Rnn15.d.ts +48 -0
  294. package/dist/external-register-CWyroXb_.d.cts +138 -0
  295. package/dist/external-register-CWyroXb_.d.ts +138 -0
  296. package/dist/fallback-Bx46zqky.d.cts +243 -0
  297. package/dist/fallback-pIWW8A2d.d.ts +243 -0
  298. package/dist/guarded-execution-BcdtxeBk.d.ts +207 -0
  299. package/dist/guarded-execution-C-3hnP6A.d.cts +207 -0
  300. package/dist/index-B6pxYJzO.d.cts +36 -0
  301. package/dist/index-B6pxYJzO.d.ts +36 -0
  302. package/dist/index-BFsng6v1.d.cts +44 -0
  303. package/dist/index-BFsng6v1.d.ts +44 -0
  304. package/dist/index-B_p8tnvf.d.cts +770 -0
  305. package/dist/index-Bg-LwEt-.d.cts +45 -0
  306. package/dist/index-Bg-LwEt-.d.ts +45 -0
  307. package/dist/index-Brp888t0.d.cts +127 -0
  308. package/dist/index-Brp888t0.d.ts +127 -0
  309. package/dist/index-CDfk6jHN.d.cts +37 -0
  310. package/dist/index-CDfk6jHN.d.ts +37 -0
  311. package/dist/index-DLAxYaN5.d.cts +169 -0
  312. package/dist/index-DLAxYaN5.d.ts +169 -0
  313. package/dist/index-DeWbQzMe.d.cts +34 -0
  314. package/dist/index-DeWbQzMe.d.ts +34 -0
  315. package/dist/index-_HDSmPyp.d.ts +770 -0
  316. package/dist/index-dX9IzPqj.d.cts +86 -0
  317. package/dist/index-dX9IzPqj.d.ts +86 -0
  318. package/dist/index.cjs +26009 -0
  319. package/dist/index.cjs.map +1 -1
  320. package/dist/index.d.cts +55 -42
  321. package/dist/index.d.ts +55 -42
  322. package/dist/index.js +849 -0
  323. package/dist/index.js.map +1 -1
  324. package/dist/layout-types-B5aiHYgk.d.cts +72 -0
  325. package/dist/layout-types-B5aiHYgk.d.ts +72 -0
  326. package/dist/memory-composers-BryDrRBX.d.cts +529 -0
  327. package/dist/memory-composers-CVQqPYEV.d.ts +529 -0
  328. package/dist/observable-B25XqCbZ.d.cts +59 -0
  329. package/dist/observable-B25XqCbZ.d.ts +59 -0
  330. package/dist/pipeline-graph-Ce47CB6Y.d.cts +145 -0
  331. package/dist/pipeline-graph-DXCwY9vG.d.ts +145 -0
  332. package/dist/presets/ai/index.cjs +4377 -0
  333. package/dist/presets/ai/index.cjs.map +1 -0
  334. package/dist/presets/ai/index.d.cts +98 -0
  335. package/dist/presets/ai/index.d.ts +98 -0
  336. package/dist/presets/ai/index.js +54 -0
  337. package/dist/presets/ai/index.js.map +1 -0
  338. package/dist/presets/harness/index.cjs +5929 -0
  339. package/dist/presets/harness/index.cjs.map +1 -0
  340. package/dist/presets/harness/index.d.cts +566 -0
  341. package/dist/presets/harness/index.d.ts +566 -0
  342. package/dist/presets/harness/index.js +71 -0
  343. package/dist/presets/harness/index.js.map +1 -0
  344. package/dist/presets/index.cjs +9782 -0
  345. package/dist/presets/index.cjs.map +1 -0
  346. package/dist/presets/index.d.cts +28 -0
  347. package/dist/presets/index.d.ts +28 -0
  348. package/dist/presets/index.js +129 -0
  349. package/dist/presets/index.js.map +1 -0
  350. package/dist/presets/inspect/index.cjs +1087 -0
  351. package/dist/presets/inspect/index.cjs.map +1 -0
  352. package/dist/presets/inspect/index.d.cts +172 -0
  353. package/dist/presets/inspect/index.d.ts +172 -0
  354. package/dist/presets/inspect/index.js +21 -0
  355. package/dist/presets/inspect/index.js.map +1 -0
  356. package/dist/presets/resilience/index.cjs +1593 -0
  357. package/dist/presets/resilience/index.cjs.map +1 -0
  358. package/dist/presets/resilience/index.d.cts +205 -0
  359. package/dist/presets/resilience/index.d.ts +205 -0
  360. package/dist/presets/resilience/index.js +18 -0
  361. package/dist/presets/resilience/index.js.map +1 -0
  362. package/dist/rate-limiter-CEALq4N1.d.ts +559 -0
  363. package/dist/rate-limiter-DpVbSYdH.d.cts +559 -0
  364. package/dist/reactive-layout-fswlBUvX.d.cts +195 -0
  365. package/dist/reactive-layout-fswlBUvX.d.ts +195 -0
  366. package/dist/retry-BDbRZ_gx.d.ts +125 -0
  367. package/dist/retry-DWuhjvsA.d.cts +125 -0
  368. package/dist/solutions/index.cjs +8200 -0
  369. package/dist/solutions/index.cjs.map +1 -0
  370. package/dist/solutions/index.d.cts +23 -0
  371. package/dist/solutions/index.d.ts +23 -0
  372. package/dist/solutions/index.js +55 -0
  373. package/dist/solutions/index.js.map +1 -0
  374. package/dist/spawnable-5mDY501F.d.cts +746 -0
  375. package/dist/spawnable-D3lR0oQu.d.ts +746 -0
  376. package/dist/status-U-rUI79b.d.cts +84 -0
  377. package/dist/status-U-rUI79b.d.ts +84 -0
  378. package/dist/timeout-U5O4ESK3.js +12 -0
  379. package/dist/timeout-U5O4ESK3.js.map +1 -0
  380. package/dist/types-BB5Lw-pB.d.cts +442 -0
  381. package/dist/types-BB5Lw-pB.d.ts +442 -0
  382. package/dist/types-CJWIMJiZ.d.ts +548 -0
  383. package/dist/types-vCq7ShIm.d.cts +548 -0
  384. package/dist/utils/ai/browser.cjs +2169 -0
  385. package/dist/utils/ai/browser.cjs.map +1 -0
  386. package/dist/utils/ai/browser.d.cts +129 -0
  387. package/dist/utils/ai/browser.d.ts +129 -0
  388. package/dist/utils/ai/browser.js +255 -0
  389. package/dist/utils/ai/browser.js.map +1 -0
  390. package/dist/utils/ai/index.cjs +8468 -0
  391. package/dist/utils/ai/index.cjs.map +1 -0
  392. package/dist/utils/ai/index.d.cts +1777 -0
  393. package/dist/utils/ai/index.d.ts +1777 -0
  394. package/dist/utils/ai/index.js +173 -0
  395. package/dist/utils/ai/index.js.map +1 -0
  396. package/dist/utils/ai/node.cjs +648 -0
  397. package/dist/utils/ai/node.cjs.map +1 -0
  398. package/dist/utils/ai/node.d.cts +57 -0
  399. package/dist/utils/ai/node.d.ts +57 -0
  400. package/dist/utils/ai/node.js +84 -0
  401. package/dist/utils/ai/node.js.map +1 -0
  402. package/dist/utils/cqrs/index.cjs +1036 -0
  403. package/dist/utils/cqrs/index.cjs.map +1 -0
  404. package/dist/utils/cqrs/index.d.cts +438 -0
  405. package/dist/utils/cqrs/index.d.ts +438 -0
  406. package/dist/utils/cqrs/index.js +18 -0
  407. package/dist/utils/cqrs/index.js.map +1 -0
  408. package/dist/utils/demo-shell/index.cjs +865 -0
  409. package/dist/utils/demo-shell/index.cjs.map +1 -0
  410. package/dist/utils/demo-shell/index.d.cts +90 -0
  411. package/dist/utils/demo-shell/index.d.ts +90 -0
  412. package/dist/utils/demo-shell/index.js +13 -0
  413. package/dist/utils/demo-shell/index.js.map +1 -0
  414. package/dist/utils/domain-templates/index.cjs +732 -0
  415. package/dist/utils/domain-templates/index.cjs.map +1 -0
  416. package/dist/utils/domain-templates/index.d.cts +214 -0
  417. package/dist/utils/domain-templates/index.d.ts +214 -0
  418. package/dist/utils/domain-templates/index.js +17 -0
  419. package/dist/utils/domain-templates/index.js.map +1 -0
  420. package/dist/utils/graphspec/index.cjs +1174 -0
  421. package/dist/utils/graphspec/index.cjs.map +1 -0
  422. package/dist/utils/graphspec/index.d.cts +449 -0
  423. package/dist/utils/graphspec/index.d.ts +449 -0
  424. package/dist/utils/graphspec/index.js +35 -0
  425. package/dist/utils/graphspec/index.js.map +1 -0
  426. package/dist/utils/harness/index.cjs +656 -0
  427. package/dist/utils/harness/index.cjs.map +1 -0
  428. package/dist/utils/harness/index.d.cts +542 -0
  429. package/dist/utils/harness/index.d.ts +542 -0
  430. package/dist/utils/harness/index.js +56 -0
  431. package/dist/utils/harness/index.js.map +1 -0
  432. package/dist/utils/index.cjs +17614 -0
  433. package/dist/utils/index.cjs.map +1 -0
  434. package/dist/utils/index.d.cts +96 -0
  435. package/dist/utils/index.d.ts +96 -0
  436. package/dist/utils/index.js +514 -0
  437. package/dist/utils/index.js.map +1 -0
  438. package/dist/utils/inspect/index.cjs +807 -0
  439. package/dist/utils/inspect/index.cjs.map +1 -0
  440. package/dist/utils/inspect/index.d.cts +123 -0
  441. package/dist/utils/inspect/index.d.ts +123 -0
  442. package/dist/utils/inspect/index.js +30 -0
  443. package/dist/utils/inspect/index.js.map +1 -0
  444. package/dist/utils/job-queue/index.cjs +717 -0
  445. package/dist/utils/job-queue/index.cjs.map +1 -0
  446. package/dist/utils/job-queue/index.d.cts +200 -0
  447. package/dist/utils/job-queue/index.d.ts +200 -0
  448. package/dist/utils/job-queue/index.js +18 -0
  449. package/dist/utils/job-queue/index.js.map +1 -0
  450. package/dist/utils/memory/index.cjs +1456 -0
  451. package/dist/utils/memory/index.cjs.map +1 -0
  452. package/dist/utils/memory/index.d.cts +660 -0
  453. package/dist/utils/memory/index.d.ts +660 -0
  454. package/dist/utils/memory/index.js +19 -0
  455. package/dist/utils/memory/index.js.map +1 -0
  456. package/dist/utils/messaging/index.cjs +666 -0
  457. package/dist/utils/messaging/index.cjs.map +1 -0
  458. package/dist/utils/messaging/index.d.cts +562 -0
  459. package/dist/utils/messaging/index.d.ts +562 -0
  460. package/dist/utils/messaging/index.js +50 -0
  461. package/dist/utils/messaging/index.js.map +1 -0
  462. package/dist/utils/orchestration/index.cjs +876 -0
  463. package/dist/utils/orchestration/index.cjs.map +1 -0
  464. package/dist/utils/orchestration/index.d.cts +233 -0
  465. package/dist/utils/orchestration/index.d.ts +233 -0
  466. package/dist/utils/orchestration/index.js +19 -0
  467. package/dist/utils/orchestration/index.js.map +1 -0
  468. package/dist/utils/process/index.cjs +743 -0
  469. package/dist/utils/process/index.cjs.map +1 -0
  470. package/dist/utils/process/index.d.cts +411 -0
  471. package/dist/utils/process/index.d.ts +411 -0
  472. package/dist/utils/process/index.js +14 -0
  473. package/dist/utils/process/index.js.map +1 -0
  474. package/dist/utils/reactive-layout/index.cjs +1607 -0
  475. package/dist/utils/reactive-layout/index.cjs.map +1 -0
  476. package/dist/utils/reactive-layout/index.d.cts +492 -0
  477. package/dist/utils/reactive-layout/index.d.ts +492 -0
  478. package/dist/utils/reactive-layout/index.js +52 -0
  479. package/dist/utils/reactive-layout/index.js.map +1 -0
  480. package/dist/utils/reduction/index.cjs +203 -0
  481. package/dist/utils/reduction/index.cjs.map +1 -0
  482. package/dist/utils/reduction/index.d.cts +102 -0
  483. package/dist/utils/reduction/index.d.ts +102 -0
  484. package/dist/utils/reduction/index.js +14 -0
  485. package/dist/utils/reduction/index.js.map +1 -0
  486. package/dist/utils/resilience/index.cjs +1617 -0
  487. package/dist/utils/resilience/index.cjs.map +1 -0
  488. package/dist/utils/resilience/index.d.cts +9 -0
  489. package/dist/utils/resilience/index.d.ts +9 -0
  490. package/dist/utils/resilience/index.js +44 -0
  491. package/dist/utils/resilience/index.js.map +1 -0
  492. package/dist/utils/surface/index.cjs +1070 -0
  493. package/dist/utils/surface/index.cjs.map +1 -0
  494. package/dist/utils/surface/index.d.cts +240 -0
  495. package/dist/utils/surface/index.d.ts +240 -0
  496. package/dist/utils/surface/index.js +30 -0
  497. package/dist/utils/surface/index.js.map +1 -0
  498. package/dist/utils/topology-view/index.cjs +620 -0
  499. package/dist/utils/topology-view/index.cjs.map +1 -0
  500. package/dist/utils/topology-view/index.d.cts +68 -0
  501. package/dist/utils/topology-view/index.d.ts +68 -0
  502. package/dist/utils/topology-view/index.js +11 -0
  503. package/dist/utils/topology-view/index.js.map +1 -0
  504. package/package.json +293 -241
  505. package/dist/core/index.cjs +0 -21
  506. package/dist/core/index.cjs.map +0 -1
  507. package/dist/core/index.d.cts +0 -1
  508. package/dist/core/index.d.ts +0 -1
  509. package/dist/core/index.js +0 -3
  510. package/dist/core/index.js.map +0 -1
  511. package/dist/extra/browser.cjs +0 -21
  512. package/dist/extra/browser.cjs.map +0 -1
  513. package/dist/extra/browser.d.cts +0 -1
  514. package/dist/extra/browser.d.ts +0 -1
  515. package/dist/extra/browser.js +0 -3
  516. package/dist/extra/browser.js.map +0 -1
  517. package/dist/extra/index.cjs +0 -21
  518. package/dist/extra/index.cjs.map +0 -1
  519. package/dist/extra/index.d.cts +0 -1
  520. package/dist/extra/index.d.ts +0 -1
  521. package/dist/extra/index.js +0 -3
  522. package/dist/extra/index.js.map +0 -1
  523. package/dist/extra/node.cjs +0 -21
  524. package/dist/extra/node.cjs.map +0 -1
  525. package/dist/extra/node.d.cts +0 -1
  526. package/dist/extra/node.d.ts +0 -1
  527. package/dist/extra/node.js +0 -3
  528. package/dist/extra/node.js.map +0 -1
  529. package/dist/extra/operators.cjs +0 -21
  530. package/dist/extra/operators.cjs.map +0 -1
  531. package/dist/extra/operators.d.cts +0 -1
  532. package/dist/extra/operators.d.ts +0 -1
  533. package/dist/extra/operators.js +0 -3
  534. package/dist/extra/operators.js.map +0 -1
  535. package/dist/extra/reactive.cjs +0 -21
  536. package/dist/extra/reactive.cjs.map +0 -1
  537. package/dist/extra/reactive.d.cts +0 -1
  538. package/dist/extra/reactive.d.ts +0 -1
  539. package/dist/extra/reactive.js +0 -3
  540. package/dist/extra/reactive.js.map +0 -1
  541. package/dist/extra/render/index.cjs +0 -21
  542. package/dist/extra/render/index.cjs.map +0 -1
  543. package/dist/extra/render/index.d.cts +0 -1
  544. package/dist/extra/render/index.d.ts +0 -1
  545. package/dist/extra/render/index.js +0 -3
  546. package/dist/extra/render/index.js.map +0 -1
  547. package/dist/extra/sources.cjs +0 -21
  548. package/dist/extra/sources.cjs.map +0 -1
  549. package/dist/extra/sources.d.cts +0 -1
  550. package/dist/extra/sources.d.ts +0 -1
  551. package/dist/extra/sources.js +0 -3
  552. package/dist/extra/sources.js.map +0 -1
  553. package/dist/extra/storage-browser.cjs +0 -21
  554. package/dist/extra/storage-browser.cjs.map +0 -1
  555. package/dist/extra/storage-browser.d.cts +0 -1
  556. package/dist/extra/storage-browser.d.ts +0 -1
  557. package/dist/extra/storage-browser.js +0 -3
  558. package/dist/extra/storage-browser.js.map +0 -1
  559. package/dist/extra/storage-core.cjs +0 -21
  560. package/dist/extra/storage-core.cjs.map +0 -1
  561. package/dist/extra/storage-core.d.cts +0 -1
  562. package/dist/extra/storage-core.d.ts +0 -1
  563. package/dist/extra/storage-core.js +0 -3
  564. package/dist/extra/storage-core.js.map +0 -1
  565. package/dist/extra/storage-node.cjs +0 -21
  566. package/dist/extra/storage-node.cjs.map +0 -1
  567. package/dist/extra/storage-node.d.cts +0 -1
  568. package/dist/extra/storage-node.d.ts +0 -1
  569. package/dist/extra/storage-node.js +0 -3
  570. package/dist/extra/storage-node.js.map +0 -1
  571. package/dist/extra/storage-tiers-browser.cjs +0 -21
  572. package/dist/extra/storage-tiers-browser.cjs.map +0 -1
  573. package/dist/extra/storage-tiers-browser.d.cts +0 -1
  574. package/dist/extra/storage-tiers-browser.d.ts +0 -1
  575. package/dist/extra/storage-tiers-browser.js +0 -3
  576. package/dist/extra/storage-tiers-browser.js.map +0 -1
  577. package/dist/extra/storage-tiers-node.cjs +0 -21
  578. package/dist/extra/storage-tiers-node.cjs.map +0 -1
  579. package/dist/extra/storage-tiers-node.d.cts +0 -1
  580. package/dist/extra/storage-tiers-node.d.ts +0 -1
  581. package/dist/extra/storage-tiers-node.js +0 -3
  582. package/dist/extra/storage-tiers-node.js.map +0 -1
  583. package/dist/extra/storage-tiers.cjs +0 -21
  584. package/dist/extra/storage-tiers.cjs.map +0 -1
  585. package/dist/extra/storage-tiers.d.cts +0 -1
  586. package/dist/extra/storage-tiers.d.ts +0 -1
  587. package/dist/extra/storage-tiers.js +0 -3
  588. package/dist/extra/storage-tiers.js.map +0 -1
  589. package/dist/extra/storage-wal.cjs +0 -21
  590. package/dist/extra/storage-wal.cjs.map +0 -1
  591. package/dist/extra/storage-wal.d.cts +0 -1
  592. package/dist/extra/storage-wal.d.ts +0 -1
  593. package/dist/extra/storage-wal.js +0 -3
  594. package/dist/extra/storage-wal.js.map +0 -1
  595. package/dist/graph/index.cjs +0 -21
  596. package/dist/graph/index.cjs.map +0 -1
  597. package/dist/graph/index.d.cts +0 -1
  598. package/dist/graph/index.d.ts +0 -1
  599. package/dist/graph/index.js +0 -3
  600. package/dist/graph/index.js.map +0 -1
  601. package/dist/patterns/ai/browser.cjs +0 -21
  602. package/dist/patterns/ai/browser.cjs.map +0 -1
  603. package/dist/patterns/ai/browser.d.cts +0 -1
  604. package/dist/patterns/ai/browser.d.ts +0 -1
  605. package/dist/patterns/ai/browser.js +0 -3
  606. package/dist/patterns/ai/browser.js.map +0 -1
  607. package/dist/patterns/ai/index.cjs +0 -21
  608. package/dist/patterns/ai/index.cjs.map +0 -1
  609. package/dist/patterns/ai/index.d.cts +0 -1
  610. package/dist/patterns/ai/index.d.ts +0 -1
  611. package/dist/patterns/ai/index.js +0 -3
  612. package/dist/patterns/ai/index.js.map +0 -1
  613. package/dist/patterns/ai/node.cjs +0 -21
  614. package/dist/patterns/ai/node.cjs.map +0 -1
  615. package/dist/patterns/ai/node.d.cts +0 -1
  616. package/dist/patterns/ai/node.d.ts +0 -1
  617. package/dist/patterns/ai/node.js +0 -3
  618. package/dist/patterns/ai/node.js.map +0 -1
  619. package/dist/patterns/cqrs/index.cjs +0 -21
  620. package/dist/patterns/cqrs/index.cjs.map +0 -1
  621. package/dist/patterns/cqrs/index.d.cts +0 -1
  622. package/dist/patterns/cqrs/index.d.ts +0 -1
  623. package/dist/patterns/cqrs/index.js +0 -3
  624. package/dist/patterns/cqrs/index.js.map +0 -1
  625. package/dist/patterns/demo-shell/index.cjs +0 -21
  626. package/dist/patterns/demo-shell/index.cjs.map +0 -1
  627. package/dist/patterns/demo-shell/index.d.cts +0 -1
  628. package/dist/patterns/demo-shell/index.d.ts +0 -1
  629. package/dist/patterns/demo-shell/index.js +0 -3
  630. package/dist/patterns/demo-shell/index.js.map +0 -1
  631. package/dist/patterns/domain-templates/index.cjs +0 -21
  632. package/dist/patterns/domain-templates/index.cjs.map +0 -1
  633. package/dist/patterns/domain-templates/index.d.cts +0 -1
  634. package/dist/patterns/domain-templates/index.d.ts +0 -1
  635. package/dist/patterns/domain-templates/index.js +0 -3
  636. package/dist/patterns/domain-templates/index.js.map +0 -1
  637. package/dist/patterns/graphspec/index.cjs +0 -21
  638. package/dist/patterns/graphspec/index.cjs.map +0 -1
  639. package/dist/patterns/graphspec/index.d.cts +0 -1
  640. package/dist/patterns/graphspec/index.d.ts +0 -1
  641. package/dist/patterns/graphspec/index.js +0 -3
  642. package/dist/patterns/graphspec/index.js.map +0 -1
  643. package/dist/patterns/harness/index.cjs +0 -21
  644. package/dist/patterns/harness/index.cjs.map +0 -1
  645. package/dist/patterns/harness/index.d.cts +0 -1
  646. package/dist/patterns/harness/index.d.ts +0 -1
  647. package/dist/patterns/harness/index.js +0 -3
  648. package/dist/patterns/harness/index.js.map +0 -1
  649. package/dist/patterns/inspect/index.cjs +0 -21
  650. package/dist/patterns/inspect/index.cjs.map +0 -1
  651. package/dist/patterns/inspect/index.d.cts +0 -1
  652. package/dist/patterns/inspect/index.d.ts +0 -1
  653. package/dist/patterns/inspect/index.js +0 -3
  654. package/dist/patterns/inspect/index.js.map +0 -1
  655. package/dist/patterns/job-queue/index.cjs +0 -21
  656. package/dist/patterns/job-queue/index.cjs.map +0 -1
  657. package/dist/patterns/job-queue/index.d.cts +0 -1
  658. package/dist/patterns/job-queue/index.d.ts +0 -1
  659. package/dist/patterns/job-queue/index.js +0 -3
  660. package/dist/patterns/job-queue/index.js.map +0 -1
  661. package/dist/patterns/memory/index.cjs +0 -21
  662. package/dist/patterns/memory/index.cjs.map +0 -1
  663. package/dist/patterns/memory/index.d.cts +0 -1
  664. package/dist/patterns/memory/index.d.ts +0 -1
  665. package/dist/patterns/memory/index.js +0 -3
  666. package/dist/patterns/memory/index.js.map +0 -1
  667. package/dist/patterns/messaging/index.cjs +0 -21
  668. package/dist/patterns/messaging/index.cjs.map +0 -1
  669. package/dist/patterns/messaging/index.d.cts +0 -1
  670. package/dist/patterns/messaging/index.d.ts +0 -1
  671. package/dist/patterns/messaging/index.js +0 -3
  672. package/dist/patterns/messaging/index.js.map +0 -1
  673. package/dist/patterns/orchestration/index.cjs +0 -21
  674. package/dist/patterns/orchestration/index.cjs.map +0 -1
  675. package/dist/patterns/orchestration/index.d.cts +0 -1
  676. package/dist/patterns/orchestration/index.d.ts +0 -1
  677. package/dist/patterns/orchestration/index.js +0 -3
  678. package/dist/patterns/orchestration/index.js.map +0 -1
  679. package/dist/patterns/process/index.cjs +0 -21
  680. package/dist/patterns/process/index.cjs.map +0 -1
  681. package/dist/patterns/process/index.d.cts +0 -1
  682. package/dist/patterns/process/index.d.ts +0 -1
  683. package/dist/patterns/process/index.js +0 -3
  684. package/dist/patterns/process/index.js.map +0 -1
  685. package/dist/patterns/reactive-layout/index.cjs +0 -21
  686. package/dist/patterns/reactive-layout/index.cjs.map +0 -1
  687. package/dist/patterns/reactive-layout/index.d.cts +0 -1
  688. package/dist/patterns/reactive-layout/index.d.ts +0 -1
  689. package/dist/patterns/reactive-layout/index.js +0 -3
  690. package/dist/patterns/reactive-layout/index.js.map +0 -1
  691. package/dist/patterns/reduction/index.cjs +0 -21
  692. package/dist/patterns/reduction/index.cjs.map +0 -1
  693. package/dist/patterns/reduction/index.d.cts +0 -1
  694. package/dist/patterns/reduction/index.d.ts +0 -1
  695. package/dist/patterns/reduction/index.js +0 -3
  696. package/dist/patterns/reduction/index.js.map +0 -1
  697. package/dist/patterns/surface/index.cjs +0 -21
  698. package/dist/patterns/surface/index.cjs.map +0 -1
  699. package/dist/patterns/surface/index.d.cts +0 -1
  700. package/dist/patterns/surface/index.d.ts +0 -1
  701. package/dist/patterns/surface/index.js +0 -3
  702. package/dist/patterns/surface/index.js.map +0 -1
  703. package/dist/patterns/topology-view/index.cjs +0 -21
  704. package/dist/patterns/topology-view/index.cjs.map +0 -1
  705. package/dist/patterns/topology-view/index.d.cts +0 -1
  706. package/dist/patterns/topology-view/index.d.ts +0 -1
  707. package/dist/patterns/topology-view/index.js +0 -3
  708. package/dist/patterns/topology-view/index.js.map +0 -1
  709. package/dist/testing/index.cjs +0 -21
  710. package/dist/testing/index.cjs.map +0 -1
  711. package/dist/testing/index.d.cts +0 -1
  712. package/dist/testing/index.d.ts +0 -1
  713. package/dist/testing/index.js +0 -3
  714. package/dist/testing/index.js.map +0 -1
@@ -0,0 +1,76 @@
1
+ // src/base/sources/event/cron.ts
2
+ import { node, wallClockNs } from "@graphrefly/pure-ts/core";
3
+ function sourceOpts(opts) {
4
+ return { describeKind: "producer", ...opts };
5
+ }
6
+ function parseField(field, min, max) {
7
+ const result = /* @__PURE__ */ new Set();
8
+ for (const part of field.split(",")) {
9
+ const [range, stepStr] = part.split("/");
10
+ const step = stepStr ? Number.parseInt(stepStr, 10) : 1;
11
+ if (Number.isNaN(step) || step < 1) throw new Error(`Invalid cron step: ${part}`);
12
+ let start;
13
+ let end;
14
+ if (range === "*") {
15
+ start = min;
16
+ end = max;
17
+ } else if (range.includes("-")) {
18
+ const [a, b] = range.split("-");
19
+ start = Number.parseInt(a, 10);
20
+ end = Number.parseInt(b, 10);
21
+ } else {
22
+ start = Number.parseInt(range, 10);
23
+ end = start;
24
+ }
25
+ if (Number.isNaN(start) || Number.isNaN(end)) throw new Error(`Invalid cron field: ${field}`);
26
+ if (start < min || end > max)
27
+ throw new Error(`Cron field out of range: ${field} (${min}-${max})`);
28
+ if (start > end) throw new Error(`Invalid cron range: ${start}-${end} in ${field}`);
29
+ for (let i = start; i <= end; i += step) result.add(i);
30
+ }
31
+ return result;
32
+ }
33
+ function parseCron(expr) {
34
+ const parts = expr.trim().split(/\s+/);
35
+ if (parts.length !== 5) throw new Error(`Invalid cron: expected 5 fields, got ${parts.length}`);
36
+ return {
37
+ minutes: parseField(parts[0], 0, 59),
38
+ hours: parseField(parts[1], 0, 23),
39
+ daysOfMonth: parseField(parts[2], 1, 31),
40
+ months: parseField(parts[3], 1, 12),
41
+ daysOfWeek: parseField(parts[4], 0, 6)
42
+ };
43
+ }
44
+ function matchesCron(schedule, date) {
45
+ return schedule.minutes.has(date.getMinutes()) && schedule.hours.has(date.getHours()) && schedule.daysOfMonth.has(date.getDate()) && schedule.months.has(date.getMonth() + 1) && schedule.daysOfWeek.has(date.getDay());
46
+ }
47
+ function fromCron(expr, opts) {
48
+ const schedule = parseCron(expr);
49
+ const { tickMs: tickOpt, output, ...rest } = opts ?? {};
50
+ const tickMs = tickOpt ?? 6e4;
51
+ const emitDate = output === "date";
52
+ return node(
53
+ (_data, a) => {
54
+ let lastFiredKey = -1;
55
+ const check = () => {
56
+ const now = /* @__PURE__ */ new Date();
57
+ const key = now.getFullYear() * 1e8 + (now.getMonth() + 1) * 1e6 + now.getDate() * 1e4 + now.getHours() * 100 + now.getMinutes();
58
+ if (key !== lastFiredKey && matchesCron(schedule, now)) {
59
+ lastFiredKey = key;
60
+ a.emit(emitDate ? now : wallClockNs());
61
+ }
62
+ };
63
+ check();
64
+ const id = setInterval(check, tickMs);
65
+ return () => clearInterval(id);
66
+ },
67
+ { ...sourceOpts(rest), name: rest.name ?? `cron:${expr}` }
68
+ );
69
+ }
70
+
71
+ export {
72
+ parseCron,
73
+ matchesCron,
74
+ fromCron
75
+ };
76
+ //# sourceMappingURL=chunk-7EGRP2VX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/base/sources/event/cron.ts"],"sourcesContent":["/**\n * Cron-based reactive sources and schedule types.\n *\n * Merged from extra/cron.ts + extra/sources/event.ts (fromCron) during cleave A2.\n * `fromCron` relocated here from `dom.ts` (post-cleave /qa A1): it uses zero DOM\n * APIs (only `setInterval` + `new Date()`), so it belongs on the universal\n * `event/index.ts` barrel, not the browser-only `dom.ts` subpath.\n */\n\nimport { type Node, type NodeOptions, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\n/** Options for {@link fromCron}. */\nexport type FromCronOptions = ExtraOpts & {\n\t/** Polling interval in ms. Default `60_000`. */\n\ttickMs?: number;\n\t/** Output format: `\"timestamp_ns\"` (default) emits wall-clock nanoseconds; `\"date\"` emits a `Date` object. */\n\toutput?: \"timestamp_ns\" | \"date\";\n};\n\n/**\n * Minimal 5-field cron parser and matcher (minute hour day-of-month month day-of-week).\n * Ported from callbag-recharge `extra/cron.ts` for `fromCron` (roadmap §2.3).\n */\nexport interface CronSchedule {\n\tminutes: Set<number>;\n\thours: Set<number>;\n\tdaysOfMonth: Set<number>;\n\tmonths: Set<number>;\n\tdaysOfWeek: Set<number>;\n}\n\nfunction parseField(field: string, min: number, max: number): Set<number> {\n\tconst result = new Set<number>();\n\tfor (const part of field.split(\",\")) {\n\t\tconst [range, stepStr] = part.split(\"/\");\n\t\tconst step = stepStr ? Number.parseInt(stepStr, 10) : 1;\n\t\tif (Number.isNaN(step) || step < 1) throw new Error(`Invalid cron step: ${part}`);\n\t\tlet start: number;\n\t\tlet end: number;\n\t\tif (range === \"*\") {\n\t\t\tstart = min;\n\t\t\tend = max;\n\t\t} else if (range.includes(\"-\")) {\n\t\t\tconst [a, b] = range.split(\"-\");\n\t\t\tstart = Number.parseInt(a, 10);\n\t\t\tend = Number.parseInt(b, 10);\n\t\t} else {\n\t\t\tstart = Number.parseInt(range, 10);\n\t\t\tend = start;\n\t\t}\n\t\tif (Number.isNaN(start) || Number.isNaN(end)) throw new Error(`Invalid cron field: ${field}`);\n\t\tif (start < min || end > max)\n\t\t\tthrow new Error(`Cron field out of range: ${field} (${min}-${max})`);\n\t\tif (start > end) throw new Error(`Invalid cron range: ${start}-${end} in ${field}`);\n\t\tfor (let i = start; i <= end; i += step) result.add(i);\n\t}\n\treturn result;\n}\n\n/**\n * Parses a standard 5-field cron expression into a {@link CronSchedule}.\n *\n * Supports `*`, ranges (`1-5`), steps (`*\\/5`, `0-30/10`), and comma-separated\n * lists. Fields are: minute (0–59), hour (0–23), day-of-month (1–31),\n * month (1–12), day-of-week (0–6, Sunday = 0).\n *\n * @param expr - Five-field whitespace-separated cron string (e.g. `\"0 9 * * 1-5\"`).\n * @returns Parsed {@link CronSchedule} with one `Set<number>` per field.\n * @throws Error when the expression does not have exactly 5 fields, contains\n * out-of-range values, or uses an invalid step.\n *\n * @example\n * ```ts\n * import { parseCron } from \"@graphrefly/graphrefly-ts\";\n *\n * const sched = parseCron(\"0 9 * * 1-5\"); // weekdays at 09:00\n * sched.hours; // Set { 9 }\n * sched.daysOfWeek; // Set { 1, 2, 3, 4, 5 }\n * ```\n */\nexport function parseCron(expr: string): CronSchedule {\n\tconst parts = expr.trim().split(/\\s+/);\n\tif (parts.length !== 5) throw new Error(`Invalid cron: expected 5 fields, got ${parts.length}`);\n\treturn {\n\t\tminutes: parseField(parts[0], 0, 59),\n\t\thours: parseField(parts[1], 0, 23),\n\t\tdaysOfMonth: parseField(parts[2], 1, 31),\n\t\tmonths: parseField(parts[3], 1, 12),\n\t\tdaysOfWeek: parseField(parts[4], 0, 6),\n\t};\n}\n\n/**\n * Returns `true` if `date` satisfies every field of `schedule`.\n *\n * @param schedule - Parsed schedule from {@link parseCron}.\n * @param date - Moment to test (local time via `getMinutes`, `getHours`, etc.).\n * @returns `true` when all five cron fields match the given date.\n *\n * @example\n * ```ts\n * import { parseCron, matchesCron } from \"@graphrefly/graphrefly-ts\";\n *\n * const sched = parseCron(\"30 8 * * 1\"); // Mondays at 08:30\n * const monday = new Date(\"2026-03-30T08:30:00\"); // a Monday\n * matchesCron(sched, monday); // true\n * ```\n */\nexport function matchesCron(schedule: CronSchedule, date: Date): boolean {\n\treturn (\n\t\tschedule.minutes.has(date.getMinutes()) &&\n\t\tschedule.hours.has(date.getHours()) &&\n\t\tschedule.daysOfMonth.has(date.getDate()) &&\n\t\tschedule.months.has(date.getMonth() + 1) &&\n\t\tschedule.daysOfWeek.has(date.getDay())\n\t);\n}\n\n/**\n * Polls on an interval; when the current minute matches a 5-field cron expression, emits once (see {@link parseCron}).\n *\n * @param expr - Cron string (`min hour dom month dow`).\n * @param opts - Producer options plus `tickMs` (default `60_000`) and `output` (`timestamp_ns` default, or `date` for `Date` values).\n * @returns `Node<number>` (nanosecond timestamp) or `Node<Date>` when `output: \"date\"`.\n *\n * @example\n * ```ts\n * import { fromCron } from \"@graphrefly/graphrefly\";\n *\n * fromCron(\"0 9 * * 1\");\n * ```\n *\n * @category extra\n */\nexport function fromCron(expr: string, opts?: FromCronOptions & { output: \"date\" }): Node<Date>;\nexport function fromCron(expr: string, opts?: FromCronOptions): Node<number>;\nexport function fromCron(expr: string, opts?: FromCronOptions): Node<number | Date> {\n\tconst schedule: CronSchedule = parseCron(expr);\n\tconst { tickMs: tickOpt, output, ...rest } = opts ?? {};\n\tconst tickMs = tickOpt ?? 60_000;\n\tconst emitDate = output === \"date\";\n\treturn node<number | Date>(\n\t\t(_data, a) => {\n\t\t\tlet lastFiredKey = -1;\n\t\t\tconst check = () => {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst key =\n\t\t\t\t\tnow.getFullYear() * 100_000_000 +\n\t\t\t\t\t(now.getMonth() + 1) * 1_000_000 +\n\t\t\t\t\tnow.getDate() * 10_000 +\n\t\t\t\t\tnow.getHours() * 100 +\n\t\t\t\t\tnow.getMinutes();\n\t\t\t\tif (key !== lastFiredKey && matchesCron(schedule, now)) {\n\t\t\t\t\tlastFiredKey = key;\n\t\t\t\t\ta.emit(emitDate ? now : wallClockNs());\n\t\t\t\t}\n\t\t\t};\n\t\t\tcheck();\n\t\t\tconst id = setInterval(check, tickMs);\n\t\t\treturn () => clearInterval(id);\n\t\t},\n\t\t{ ...sourceOpts(rest), name: rest.name ?? `cron:${expr}` },\n\t);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,150 @@
1
+ import {
2
+ forEach
3
+ } from "./chunk-DKNHAICT.js";
4
+
5
+ // src/base/composition/distill.ts
6
+ import { batch, factoryTag, node } from "@graphrefly/pure-ts/core";
7
+ import {
8
+ fromAny,
9
+ reactiveMap,
10
+ switchMap,
11
+ withLatestFrom
12
+ } from "@graphrefly/pure-ts/extra";
13
+ function isNodeLike(value) {
14
+ return typeof value === "object" && value !== null && "cache" in value && typeof value.subscribe === "function";
15
+ }
16
+ function keepalive(node2) {
17
+ node2.subscribe(() => void 0);
18
+ }
19
+ function mapFromSnapshot(snapshot) {
20
+ if (snapshot instanceof Map) return snapshot;
21
+ return /* @__PURE__ */ new Map();
22
+ }
23
+ function applyExtraction(store, extraction) {
24
+ if (!Array.isArray(extraction.upsert)) {
25
+ throw new TypeError("distill extraction requires upsert: Array<{ key, value }>");
26
+ }
27
+ batch(() => {
28
+ for (const { key, value } of extraction.upsert) {
29
+ store.set(key, value);
30
+ }
31
+ for (const key of extraction.remove ?? []) {
32
+ store.delete(key);
33
+ }
34
+ });
35
+ }
36
+ function distill(source, extractFn, opts) {
37
+ const sourceNode = fromAny(source);
38
+ const store = reactiveMap(opts.mapOptions ?? {});
39
+ const budget = opts.budget ?? 2e3;
40
+ const hasContext = opts.context !== void 0 && opts.context !== null;
41
+ const contextNode = hasContext ? fromAny(opts.context) : node([], { initial: null });
42
+ const extractionStream = fromAny(
43
+ extractFn(sourceNode, store.entries)
44
+ );
45
+ forEach(extractionStream, (extraction) => {
46
+ applyExtraction(store, extraction);
47
+ });
48
+ if (opts.evict) {
49
+ const verdictUnsubs = /* @__PURE__ */ new Map();
50
+ const evictionKeys = node(
51
+ [store.entries],
52
+ (batchData, actions, ctx) => {
53
+ const batch0 = batchData[0];
54
+ const snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];
55
+ const out = [];
56
+ const entries = mapFromSnapshot(snapshot);
57
+ for (const key of verdictUnsubs.keys()) {
58
+ if (!entries.has(key)) {
59
+ verdictUnsubs.get(key)();
60
+ verdictUnsubs.delete(key);
61
+ }
62
+ }
63
+ for (const [key, mem] of entries) {
64
+ const verdict = opts.evict(key, mem);
65
+ if (isNodeLike(verdict)) {
66
+ if (!verdictUnsubs.has(key)) {
67
+ const unsub = forEach(verdict, (val) => {
68
+ if (val === true && store.has(key)) {
69
+ store.delete(key);
70
+ }
71
+ });
72
+ verdictUnsubs.set(key, unsub);
73
+ }
74
+ continue;
75
+ }
76
+ if (typeof verdict === "boolean") {
77
+ if (verdict) out.push(key);
78
+ continue;
79
+ }
80
+ throw new TypeError("distill evict() must return boolean or Node<boolean>");
81
+ }
82
+ actions.emit(out);
83
+ },
84
+ { describeKind: "derived" }
85
+ );
86
+ forEach(evictionKeys, (keys) => {
87
+ for (const key of keys) store.delete(key);
88
+ });
89
+ }
90
+ const hasConsolidateTrigger = opts.consolidateTrigger !== void 0 && opts.consolidateTrigger !== null;
91
+ if (opts.consolidate && hasConsolidateTrigger) {
92
+ const consolidateTriggerNode = fromAny(opts.consolidateTrigger);
93
+ const consolidatePaired = withLatestFrom(
94
+ consolidateTriggerNode,
95
+ store.entries
96
+ );
97
+ const consolidationStream = switchMap(
98
+ consolidatePaired,
99
+ ([, entries]) => opts.consolidate(mapFromSnapshot(entries))
100
+ );
101
+ forEach(consolidationStream, (extraction) => {
102
+ applyExtraction(store, extraction);
103
+ });
104
+ }
105
+ const compact = node(
106
+ [store.entries, contextNode],
107
+ (batchData, actions, ctx) => {
108
+ const data = batchData.map(
109
+ (batch2, i) => batch2 != null && batch2.length > 0 ? batch2.at(-1) : ctx.prevData[i]
110
+ );
111
+ const snapshot = data[0];
112
+ const context = data[1];
113
+ const map = mapFromSnapshot(snapshot);
114
+ const entries = [...map.entries()].map(([key, value]) => ({
115
+ key,
116
+ value,
117
+ score: opts.score(value, context),
118
+ cost: opts.cost(value)
119
+ }));
120
+ entries.sort((a, b) => b.score - a.score);
121
+ const packed = [];
122
+ let remaining = budget;
123
+ for (const item of entries) {
124
+ if (item.cost <= remaining) {
125
+ packed.push({ key: item.key, value: item.value, score: item.score });
126
+ remaining -= item.cost;
127
+ }
128
+ }
129
+ actions.emit(packed);
130
+ },
131
+ { describeKind: "derived", meta: { ...factoryTag("distill", { budget }) } }
132
+ );
133
+ const size = node(
134
+ [store.entries],
135
+ (batchData, actions, ctx) => {
136
+ const batch0 = batchData[0];
137
+ const snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];
138
+ actions.emit(mapFromSnapshot(snapshot).size);
139
+ },
140
+ { describeKind: "derived" }
141
+ );
142
+ keepalive(compact);
143
+ keepalive(size);
144
+ return { store, compact, size };
145
+ }
146
+
147
+ export {
148
+ distill
149
+ };
150
+ //# sourceMappingURL=chunk-A7KV5UK4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/base/composition/distill.ts"],"sourcesContent":["/**\n * Budget-constrained reactive memory composition (roadmap §3.2b).\n *\n * Moved to base/composition/distill.ts during cleave A2.\n */\n\nimport { batch, factoryTag, type Node, node } from \"@graphrefly/pure-ts/core\";\nimport {\n\tfromAny,\n\ttype NodeInput,\n\ttype ReactiveMapBundle,\n\ttype ReactiveMapOptions,\n\treactiveMap,\n\tswitchMap,\n\twithLatestFrom,\n} from \"@graphrefly/pure-ts/extra\";\nimport { forEach } from \"../sources/async.js\";\n\nfunction isNodeLike<T>(value: unknown): value is Node<T> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"cache\" in (value as Node<T>) &&\n\t\ttypeof (value as Node<T>).subscribe === \"function\"\n\t);\n}\n\nexport type Extraction<TMem> = {\n\tupsert: Array<{ key: string; value: TMem }>;\n\tremove?: string[];\n};\n\nexport type DistillOptions<TMem> = {\n\tscore: (mem: TMem, context: unknown) => number;\n\tcost: (mem: TMem) => number;\n\tbudget?: number;\n\tevict?: (key: string, mem: TMem) => boolean | Node<boolean>;\n\tconsolidate?: (entries: ReadonlyMap<string, TMem>) => NodeInput<Extraction<TMem>>;\n\tconsolidateTrigger?: NodeInput<unknown>;\n\tcontext?: NodeInput<unknown>;\n\tmapOptions?: ReactiveMapOptions<string, TMem>;\n};\n\nexport type DistillBundle<TMem> = {\n\tstore: ReactiveMapBundle<string, TMem>;\n\tcompact: Node<Array<{ key: string; value: TMem; score: number }>>;\n\tsize: Node<number>;\n};\n\nfunction keepalive(node: Node): void {\n\tnode.subscribe(() => undefined);\n}\n\n/**\n * Defensive snapshot → ReadonlyMap coercion (D2 /qa lock, Tier 9.1).\n *\n * `ReactiveMapBundle.entries` always emits a real `Map` on the live emit\n * path. The non-Map case happens on snapshot **restore**: the default\n * `JsonGraphCodec` serializes a `Map` to `null`/`{}`/`[]` depending on the\n * codec configuration, and `Graph.restore` writes that decoded value back\n * to the cache. A naive `(snapshot as ReadonlyMap) ?? new Map()` would\n * pass a plain object through and then `.entries()` / `.size` access would\n * silently yield wrong results (or throw). The runtime `instanceof Map`\n * check below restores the safety net the previous `mapFromSnapshot` helper\n * provided before its initial deletion in Tier 10.1.\n */\nfunction mapFromSnapshot<TMem>(snapshot: unknown): ReadonlyMap<string, TMem> {\n\tif (snapshot instanceof Map) return snapshot as ReadonlyMap<string, TMem>;\n\treturn new Map<string, TMem>();\n}\n\nfunction applyExtraction<TMem>(\n\tstore: ReactiveMapBundle<string, TMem>,\n\textraction: Extraction<TMem>,\n): void {\n\tif (!Array.isArray(extraction.upsert)) {\n\t\tthrow new TypeError(\"distill extraction requires upsert: Array<{ key, value }>\");\n\t}\n\tbatch(() => {\n\t\tfor (const { key, value } of extraction.upsert) {\n\t\t\tstore.set(key, value);\n\t\t}\n\t\tfor (const key of extraction.remove ?? []) {\n\t\t\tstore.delete(key);\n\t\t}\n\t});\n}\n\n/**\n * Budget-constrained reactive memory composition.\n *\n * **Tier 1.5.4 (Session A.5 lock, 2026-04-27):** `extractFn` receives the\n * source and existing-store as `Node`s. Distill calls `extractFn` ONCE at\n * wiring time and consumes the returned stream of extractions. The user\n * controls reactive composition — wrap with `switchMap` for cancel-on-new-input,\n * `mergeMap` for parallel, `derived` for sync transforms. See COMPOSITION-GUIDE\n * §40 for the recipe.\n */\nexport function distill<TRaw, TMem>(\n\tsource: NodeInput<TRaw>,\n\textractFn: (\n\t\traw: Node<TRaw>,\n\t\texisting: Node<ReadonlyMap<string, TMem>>,\n\t) => NodeInput<Extraction<TMem>>,\n\topts: DistillOptions<TMem>,\n): DistillBundle<TMem> {\n\tconst sourceNode = fromAny(source);\n\tconst store = reactiveMap<string, TMem>(opts.mapOptions ?? {});\n\tconst budget = opts.budget ?? 2000;\n\tconst hasContext = opts.context !== undefined && opts.context !== null;\n\tconst contextNode = hasContext ? fromAny(opts.context) : node<unknown>([], { initial: null });\n\n\t// `latestStore` (formerly a §28 closure-mirror) is no longer needed —\n\t// Phase 10.5 (`withLatestFrom` flipped to `partial: false`) fixed the\n\t// W1 initial-pair drop. `consolidate` now uses\n\t// `withLatestFrom(trigger, store.entries)` below to pair each trigger\n\t// with the latest store snapshot via a real reactive edge (visible in\n\t// `describe()`). The `mapFromSnapshot` transform runs inside the\n\t// switchMap fn body.\n\n\t// Tier 1.5.4: one-shot wire. User's `extractFn` returns the reactive\n\t// extraction stream — distill just `forEach`s and applies. No internal\n\t// switchMap; user picks the cancellation / queueing semantics.\n\tconst extractionStream = fromAny(\n\t\textractFn(sourceNode, store.entries as Node<ReadonlyMap<string, TMem>>),\n\t);\n\tforEach(extractionStream, (extraction) => {\n\t\tapplyExtraction(store, extraction);\n\t});\n\n\tif (opts.evict) {\n\t\t// Track active verdict-node subscriptions so we can react to Node<boolean> changes.\n\t\tconst verdictUnsubs = new Map<string, () => void>();\n\n\t\tconst evictionKeys = node<string[]>(\n\t\t\t[store.entries],\n\t\t\t(batchData, actions, ctx) => {\n\t\t\t\tconst batch0 = batchData[0];\n\t\t\t\tconst snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];\n\t\t\t\tconst out: string[] = [];\n\t\t\t\tconst entries = mapFromSnapshot<TMem>(snapshot);\n\t\t\t\t// Clean up verdict subscriptions for removed keys.\n\t\t\t\tfor (const key of verdictUnsubs.keys()) {\n\t\t\t\t\tif (!entries.has(key)) {\n\t\t\t\t\t\tverdictUnsubs.get(key)!();\n\t\t\t\t\t\tverdictUnsubs.delete(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (const [key, mem] of entries) {\n\t\t\t\t\tconst verdict = opts.evict!(key, mem);\n\t\t\t\t\tif (isNodeLike<boolean>(verdict)) {\n\t\t\t\t\t\t// Subscribe if not already — push-on-subscribe fires with\n\t\t\t\t\t\t// the verdict's current value on first subscribe, so an\n\t\t\t\t\t\t// already-true verdict deletes via the callback without\n\t\t\t\t\t\t// needing a `verdict.cache` read (closes P3 audit #3).\n\t\t\t\t\t\t// Future transitions to `true` flow through the same path.\n\t\t\t\t\t\tif (!verdictUnsubs.has(key)) {\n\t\t\t\t\t\t\tconst unsub = forEach(verdict, (val) => {\n\t\t\t\t\t\t\t\tif (val === true && store.has(key)) {\n\t\t\t\t\t\t\t\t\tstore.delete(key);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tverdictUnsubs.set(key, unsub);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof verdict === \"boolean\") {\n\t\t\t\t\t\tif (verdict) out.push(key);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tthrow new TypeError(\"distill evict() must return boolean or Node<boolean>\");\n\t\t\t\t}\n\t\t\t\tactions.emit(out);\n\t\t\t},\n\t\t\t{ describeKind: \"derived\" },\n\t\t);\n\t\tforEach(evictionKeys, (keys) => {\n\t\t\tfor (const key of keys) store.delete(key);\n\t\t});\n\t}\n\n\tconst hasConsolidateTrigger =\n\t\topts.consolidateTrigger !== undefined && opts.consolidateTrigger !== null;\n\tif (opts.consolidate && hasConsolidateTrigger) {\n\t\tconst consolidateTriggerNode = fromAny(opts.consolidateTrigger);\n\t\tconst consolidatePaired = withLatestFrom(\n\t\t\tconsolidateTriggerNode,\n\t\t\tstore.entries as Node<unknown>,\n\t\t);\n\t\tconst consolidationStream = switchMap(consolidatePaired, ([, entries]) =>\n\t\t\topts.consolidate!(mapFromSnapshot<TMem>(entries)),\n\t\t);\n\t\tforEach(consolidationStream, (extraction) => {\n\t\t\tapplyExtraction(store, extraction);\n\t\t});\n\t}\n\n\tconst compact = node<Array<{ key: string; value: TMem; score: number }>>(\n\t\t[store.entries, contextNode],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst data = batchData.map((batch, i) =>\n\t\t\t\tbatch != null && batch.length > 0 ? batch.at(-1) : ctx.prevData[i],\n\t\t\t);\n\t\t\tconst snapshot = data[0];\n\t\t\tconst context = data[1];\n\t\t\tconst map = mapFromSnapshot<TMem>(snapshot);\n\t\t\tconst entries = [...map.entries()].map(([key, value]) => ({\n\t\t\t\tkey,\n\t\t\t\tvalue,\n\t\t\t\tscore: opts.score(value, context),\n\t\t\t\tcost: opts.cost(value),\n\t\t\t}));\n\t\t\tentries.sort((a, b) => b.score - a.score);\n\n\t\t\tconst packed: Array<{ key: string; value: TMem; score: number }> = [];\n\t\t\tlet remaining = budget;\n\t\t\tfor (const item of entries) {\n\t\t\t\tif (item.cost <= remaining) {\n\t\t\t\t\tpacked.push({ key: item.key, value: item.value, score: item.score });\n\t\t\t\t\tremaining -= item.cost;\n\t\t\t\t}\n\t\t\t}\n\t\t\tactions.emit(packed);\n\t\t},\n\t\t{ describeKind: \"derived\", meta: { ...factoryTag(\"distill\", { budget }) } },\n\t);\n\n\tconst size = node<number>(\n\t\t[store.entries],\n\t\t(batchData, actions, ctx) => {\n\t\t\tconst batch0 = batchData[0];\n\t\t\tconst snapshot = batch0 != null && batch0.length > 0 ? batch0.at(-1) : ctx.prevData[0];\n\t\t\tactions.emit(mapFromSnapshot<TMem>(snapshot).size);\n\t\t},\n\t\t{ describeKind: \"derived\" },\n\t);\n\tkeepalive(compact);\n\tkeepalive(size);\n\n\treturn { store, compact, size };\n}\n"],"mappings":";;;;;AAMA,SAAS,OAAO,YAAuB,YAAY;AACnD;AAAA,EACC;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAGP,SAAS,WAAc,OAAkC;AACxD,SACC,OAAO,UAAU,YACjB,UAAU,QACV,WAAY,SACZ,OAAQ,MAAkB,cAAc;AAE1C;AAwBA,SAAS,UAAUA,OAAkB;AACpC,EAAAA,MAAK,UAAU,MAAM,MAAS;AAC/B;AAeA,SAAS,gBAAsB,UAA8C;AAC5E,MAAI,oBAAoB,IAAK,QAAO;AACpC,SAAO,oBAAI,IAAkB;AAC9B;AAEA,SAAS,gBACR,OACA,YACO;AACP,MAAI,CAAC,MAAM,QAAQ,WAAW,MAAM,GAAG;AACtC,UAAM,IAAI,UAAU,2DAA2D;AAAA,EAChF;AACA,QAAM,MAAM;AACX,eAAW,EAAE,KAAK,MAAM,KAAK,WAAW,QAAQ;AAC/C,YAAM,IAAI,KAAK,KAAK;AAAA,IACrB;AACA,eAAW,OAAO,WAAW,UAAU,CAAC,GAAG;AAC1C,YAAM,OAAO,GAAG;AAAA,IACjB;AAAA,EACD,CAAC;AACF;AAYO,SAAS,QACf,QACA,WAIA,MACsB;AACtB,QAAM,aAAa,QAAQ,MAAM;AACjC,QAAM,QAAQ,YAA0B,KAAK,cAAc,CAAC,CAAC;AAC7D,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,aAAa,KAAK,YAAY,UAAa,KAAK,YAAY;AAClE,QAAM,cAAc,aAAa,QAAQ,KAAK,OAAO,IAAI,KAAc,CAAC,GAAG,EAAE,SAAS,KAAK,CAAC;AAa5F,QAAM,mBAAmB;AAAA,IACxB,UAAU,YAAY,MAAM,OAA0C;AAAA,EACvE;AACA,UAAQ,kBAAkB,CAAC,eAAe;AACzC,oBAAgB,OAAO,UAAU;AAAA,EAClC,CAAC;AAED,MAAI,KAAK,OAAO;AAEf,UAAM,gBAAgB,oBAAI,IAAwB;AAElD,UAAM,eAAe;AAAA,MACpB,CAAC,MAAM,OAAO;AAAA,MACd,CAAC,WAAW,SAAS,QAAQ;AAC5B,cAAM,SAAS,UAAU,CAAC;AAC1B,cAAM,WAAW,UAAU,QAAQ,OAAO,SAAS,IAAI,OAAO,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AACrF,cAAM,MAAgB,CAAC;AACvB,cAAM,UAAU,gBAAsB,QAAQ;AAE9C,mBAAW,OAAO,cAAc,KAAK,GAAG;AACvC,cAAI,CAAC,QAAQ,IAAI,GAAG,GAAG;AACtB,0BAAc,IAAI,GAAG,EAAG;AACxB,0BAAc,OAAO,GAAG;AAAA,UACzB;AAAA,QACD;AACA,mBAAW,CAAC,KAAK,GAAG,KAAK,SAAS;AACjC,gBAAM,UAAU,KAAK,MAAO,KAAK,GAAG;AACpC,cAAI,WAAoB,OAAO,GAAG;AAMjC,gBAAI,CAAC,cAAc,IAAI,GAAG,GAAG;AAC5B,oBAAM,QAAQ,QAAQ,SAAS,CAAC,QAAQ;AACvC,oBAAI,QAAQ,QAAQ,MAAM,IAAI,GAAG,GAAG;AACnC,wBAAM,OAAO,GAAG;AAAA,gBACjB;AAAA,cACD,CAAC;AACD,4BAAc,IAAI,KAAK,KAAK;AAAA,YAC7B;AACA;AAAA,UACD;AACA,cAAI,OAAO,YAAY,WAAW;AACjC,gBAAI,QAAS,KAAI,KAAK,GAAG;AACzB;AAAA,UACD;AACA,gBAAM,IAAI,UAAU,sDAAsD;AAAA,QAC3E;AACA,gBAAQ,KAAK,GAAG;AAAA,MACjB;AAAA,MACA,EAAE,cAAc,UAAU;AAAA,IAC3B;AACA,YAAQ,cAAc,CAAC,SAAS;AAC/B,iBAAW,OAAO,KAAM,OAAM,OAAO,GAAG;AAAA,IACzC,CAAC;AAAA,EACF;AAEA,QAAM,wBACL,KAAK,uBAAuB,UAAa,KAAK,uBAAuB;AACtE,MAAI,KAAK,eAAe,uBAAuB;AAC9C,UAAM,yBAAyB,QAAQ,KAAK,kBAAkB;AAC9D,UAAM,oBAAoB;AAAA,MACzB;AAAA,MACA,MAAM;AAAA,IACP;AACA,UAAM,sBAAsB;AAAA,MAAU;AAAA,MAAmB,CAAC,CAAC,EAAE,OAAO,MACnE,KAAK,YAAa,gBAAsB,OAAO,CAAC;AAAA,IACjD;AACA,YAAQ,qBAAqB,CAAC,eAAe;AAC5C,sBAAgB,OAAO,UAAU;AAAA,IAClC,CAAC;AAAA,EACF;AAEA,QAAM,UAAU;AAAA,IACf,CAAC,MAAM,SAAS,WAAW;AAAA,IAC3B,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,OAAO,UAAU;AAAA,QAAI,CAACC,QAAO,MAClCA,UAAS,QAAQA,OAAM,SAAS,IAAIA,OAAM,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AAAA,MAClE;AACA,YAAM,WAAW,KAAK,CAAC;AACvB,YAAM,UAAU,KAAK,CAAC;AACtB,YAAM,MAAM,gBAAsB,QAAQ;AAC1C,YAAM,UAAU,CAAC,GAAG,IAAI,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO;AAAA,QACzD;AAAA,QACA;AAAA,QACA,OAAO,KAAK,MAAM,OAAO,OAAO;AAAA,QAChC,MAAM,KAAK,KAAK,KAAK;AAAA,MACtB,EAAE;AACF,cAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAExC,YAAM,SAA6D,CAAC;AACpE,UAAI,YAAY;AAChB,iBAAW,QAAQ,SAAS;AAC3B,YAAI,KAAK,QAAQ,WAAW;AAC3B,iBAAO,KAAK,EAAE,KAAK,KAAK,KAAK,OAAO,KAAK,OAAO,OAAO,KAAK,MAAM,CAAC;AACnE,uBAAa,KAAK;AAAA,QACnB;AAAA,MACD;AACA,cAAQ,KAAK,MAAM;AAAA,IACpB;AAAA,IACA,EAAE,cAAc,WAAW,MAAM,EAAE,GAAG,WAAW,WAAW,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,EAC3E;AAEA,QAAM,OAAO;AAAA,IACZ,CAAC,MAAM,OAAO;AAAA,IACd,CAAC,WAAW,SAAS,QAAQ;AAC5B,YAAM,SAAS,UAAU,CAAC;AAC1B,YAAM,WAAW,UAAU,QAAQ,OAAO,SAAS,IAAI,OAAO,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;AACrF,cAAQ,KAAK,gBAAsB,QAAQ,EAAE,IAAI;AAAA,IAClD;AAAA,IACA,EAAE,cAAc,UAAU;AAAA,EAC3B;AACA,YAAU,OAAO;AACjB,YAAU,IAAI;AAEd,SAAO,EAAE,OAAO,SAAS,KAAK;AAC/B;","names":["node","batch"]}
@@ -0,0 +1,156 @@
1
+ import {
2
+ sugiyamaLayout
3
+ } from "./chunk-DMSNO6ZB.js";
4
+
5
+ // src/utils/topology-view/index.ts
6
+ import { Graph } from "@graphrefly/pure-ts/graph";
7
+
8
+ // src/utils/topology-view/_internal.ts
9
+ var MIN_W = 3;
10
+ var MAX_W = 24;
11
+ var NODE_H = 1;
12
+ var LAYER_GAP = 4;
13
+ var NODE_GAP = 1;
14
+ function widthOf(id) {
15
+ const local = id.includes("::") ? id.split("::").pop() ?? id : id;
16
+ return Math.max(MIN_W, Math.min(MAX_W, local.length + 2));
17
+ }
18
+ function heightOf(_id) {
19
+ return NODE_H;
20
+ }
21
+ function defaultLayout(spec, direction = "LR") {
22
+ const ids = Object.keys(spec.nodes).sort();
23
+ const edges = spec.edges.map((e) => ({ from: e.from, to: e.to }));
24
+ if (ids.length === 0) {
25
+ return { boxes: [], edges: [] };
26
+ }
27
+ const result = sugiyamaLayout({
28
+ nodes: ids,
29
+ edges,
30
+ widthCells: widthOf,
31
+ heightCells: heightOf,
32
+ layerGap: LAYER_GAP,
33
+ nodeGap: NODE_GAP,
34
+ direction
35
+ });
36
+ const boxes = result.boxes.map((b) => ({
37
+ id: b.id,
38
+ x: b.x,
39
+ y: b.y,
40
+ w: b.w,
41
+ h: b.h,
42
+ meta: spec.nodes[b.id]?.meta
43
+ }));
44
+ const seenPerTo = /* @__PURE__ */ new Map();
45
+ const edgeOut = result.edges.map((e) => {
46
+ const toDeps = spec.nodes[e.to]?.deps ?? [];
47
+ const cursorKey = `${e.to}::${e.from}`;
48
+ const startFrom = seenPerTo.get(cursorKey) ?? 0;
49
+ const depIndex = toDeps.indexOf(e.from, startFrom);
50
+ seenPerTo.set(cursorKey, depIndex >= 0 ? depIndex + 1 : startFrom);
51
+ const points = e.points.map((p) => [p.x, p.y]);
52
+ return {
53
+ from: e.from,
54
+ to: e.to,
55
+ depIndex: depIndex >= 0 ? depIndex : -1,
56
+ points
57
+ };
58
+ });
59
+ return { boxes, edges: edgeOut };
60
+ }
61
+
62
+ // src/utils/topology-view/index.ts
63
+ var TOPOLOGY_TYPES = /* @__PURE__ */ new Set([
64
+ "node-added",
65
+ "node-removed",
66
+ "mount",
67
+ "unmount"
68
+ ]);
69
+ function isTopologyChange(c) {
70
+ return TOPOLOGY_TYPES.has(c.type);
71
+ }
72
+ var TopologyViewGraph = class extends Graph {
73
+ target;
74
+ layout;
75
+ frame;
76
+ constructor(opts) {
77
+ const name = opts.name ?? "topology-view";
78
+ super(name, opts.graphOptions);
79
+ this.target = opts.graph;
80
+ this.layout = opts.layout ?? ((spec) => defaultLayout(spec, "LR"));
81
+ const changeset = this.target.observe({
82
+ changeset: true,
83
+ changesetName: "target-changeset"
84
+ });
85
+ this.add(changeset, { name: "changeset" });
86
+ const seedLayout = this._computeLayout();
87
+ const layoutNode = this.derived(
88
+ "layout",
89
+ ["changeset"],
90
+ (data, _ctx) => {
91
+ const batch0 = data[0];
92
+ if (batch0 == null || batch0.length === 0) {
93
+ return [];
94
+ }
95
+ let topologyHit = false;
96
+ for (const c of batch0) {
97
+ if (isTopologyChange(c)) {
98
+ topologyHit = true;
99
+ break;
100
+ }
101
+ }
102
+ if (!topologyHit) {
103
+ return [];
104
+ }
105
+ return [this._computeLayout()];
106
+ },
107
+ { initial: seedLayout, partial: true }
108
+ );
109
+ void layoutNode;
110
+ this.frame = this.derived(
111
+ "frame",
112
+ ["layout", "changeset"],
113
+ (data, ctx) => {
114
+ const layoutBatch = data[0];
115
+ const changesetBatch = data[1];
116
+ const layout = layoutBatch != null && layoutBatch.length > 0 ? layoutBatch.at(-1) : ctx.prevData[0];
117
+ if (layout == null) {
118
+ return [];
119
+ }
120
+ const changes = [];
121
+ if (changesetBatch != null) {
122
+ for (const c of changesetBatch) changes.push(c);
123
+ }
124
+ return [
125
+ {
126
+ boxes: layout.boxes,
127
+ edges: layout.edges,
128
+ changes
129
+ }
130
+ ];
131
+ },
132
+ {
133
+ initial: { boxes: seedLayout.boxes, edges: seedLayout.edges, changes: [] },
134
+ partial: true
135
+ }
136
+ );
137
+ }
138
+ _computeLayout() {
139
+ if (this.target.destroyed) {
140
+ return { boxes: [], edges: [] };
141
+ }
142
+ const spec = this.target.describe();
143
+ return this.layout(spec);
144
+ }
145
+ };
146
+ function topologyView(opts) {
147
+ const view = new TopologyViewGraph(opts);
148
+ view.tagFactory("topologyView");
149
+ return view;
150
+ }
151
+
152
+ export {
153
+ TopologyViewGraph,
154
+ topologyView
155
+ };
156
+ //# sourceMappingURL=chunk-APY2SS5X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/topology-view/index.ts","../src/utils/topology-view/_internal.ts"],"sourcesContent":["/**\n * `topologyView({ graph, layout? }): TopologyViewGraph` — D3 of the\n * three-layer view (`docs/optimizations.md` line \"D — Three-layer view\").\n *\n * Composes a target {@link Graph} with a pluggable layered-DAG layout into a\n * live {@link LayoutFrame} stream:\n *\n * ```text\n * target graph\n * └─ observe({ changeset: true }) → Node<GraphChange>\n * └─ filter(topology) → recompute layout\n * └─ each change → merge into a LayoutFrame\n * ```\n *\n * **Initial frame** is delivered on subscribe (push-on-subscribe per spec\n * §2.2) — the layout is seeded from `graph.describe()` at construction. A\n * consumer that wants deltas only can `pipe(skip(1))` from the output node.\n *\n * **Pluggable layout** — pass `opts.layout` to swap in `dagre`, `elk`, or\n * any layered-DAG library. The default is a minimal Sugiyama in\n * `_internal.ts` (matches the library's \"no deps, browser-safe\" ethos).\n *\n * **No timers** — animation is driven by the changeset's batch boundaries.\n * Each batch IS a frame; CSS transitions handle visual fade.\n *\n * @module\n */\n\nimport type { Node } from \"@graphrefly/pure-ts/core\";\nimport { Graph, type GraphChange, type GraphOptions } from \"@graphrefly/pure-ts/graph\";\nimport { defaultLayout } from \"./_internal.js\";\nimport type { LayoutFn, LayoutFrame } from \"./types.js\";\n\nexport type {\n\tLayoutBox,\n\tLayoutEdge,\n\tLayoutFn,\n\tLayoutFrame,\n} from \"./types.js\";\n\n/** Topology variants from {@link GraphChange} that invalidate layout. */\nconst TOPOLOGY_TYPES = new Set<GraphChange[\"type\"]>([\n\t\"node-added\",\n\t\"node-removed\",\n\t\"mount\",\n\t\"unmount\",\n]);\n\nfunction isTopologyChange(c: GraphChange): boolean {\n\treturn TOPOLOGY_TYPES.has(c.type);\n}\n\n/** Options for {@link topologyView}. */\nexport interface TopologyViewOptions {\n\t/** The target graph to observe. */\n\treadonly graph: Graph;\n\t/**\n\t * Pluggable layout function. Defaults to the bundled Sugiyama layout.\n\t * Adapt `dagre` / `elk` / etc. by wrapping their output in the\n\t * {@link LayoutFn} shape.\n\t */\n\treadonly layout?: LayoutFn;\n\t/** Optional name for the {@link TopologyViewGraph}. Defaults to `\"topology-view\"`. */\n\treadonly name?: string;\n\t/**\n\t * Forward extra options to the underlying {@link Graph} constructor\n\t * (e.g. `versioning`, `traceCapacity`).\n\t */\n\treadonly graphOptions?: GraphOptions;\n}\n\n/**\n * Live topology view — a {@link Graph} subclass that exposes a single\n * output node {@link TopologyViewGraph.frame} emitting {@link LayoutFrame}s.\n */\nexport class TopologyViewGraph extends Graph {\n\treadonly target: Graph;\n\treadonly layout: LayoutFn;\n\treadonly frame: Node<LayoutFrame>;\n\n\tconstructor(opts: TopologyViewOptions) {\n\t\tconst name = opts.name ?? \"topology-view\";\n\t\tsuper(name, opts.graphOptions);\n\t\tthis.target = opts.graph;\n\t\tthis.layout = opts.layout ?? ((spec) => defaultLayout(spec, \"LR\"));\n\n\t\t// 1. Source node — discrete GraphChange events from the target graph.\n\t\t// Every change (data + topology + batch boundaries) flows here.\n\t\tconst changeset = this.target.observe({\n\t\t\tchangeset: true,\n\t\t\tchangesetName: \"target-changeset\",\n\t\t});\n\t\tthis.add(changeset, { name: \"changeset\" });\n\n\t\t// 2. Layout — recomputes only on topology changes. Reads\n\t\t// `target.describe()` inside the fn body — this is a method call on\n\t\t// the stored Graph reference, NOT a `.cache` read of another\n\t\t// reactive node, so it does not violate spec §5.12. Initial value\n\t\t// is seeded from the construction-time describe so the first\n\t\t// push-on-subscribe delivers a valid frame before any change\n\t\t// arrives. `partial: true` opts out of the first-run gate (§2.7) —\n\t\t// the seeded `initial` is correct from construction; we don't need\n\t\t// to wait for the upstream changeset to deliver its first DATA.\n\t\tconst seedLayout = this._computeLayout();\n\t\tconst layoutNode = this.derived<Pick<LayoutFrame, \"boxes\" | \"edges\">>(\n\t\t\t\"layout\",\n\t\t\t[\"changeset\"],\n\t\t\t(data, _ctx) => {\n\t\t\t\tconst batch0 = data[0];\n\t\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\t\t// No changeset DATA this wave (or this is the seed activation\n\t\t\t\t\t// before changeset has fired). Settle as RESOLVED — caller\n\t\t\t\t\t// will read `prevData[0]` if it needs the current layout.\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\tlet topologyHit = false;\n\t\t\t\tfor (const c of batch0 as readonly GraphChange[]) {\n\t\t\t\t\tif (isTopologyChange(c)) {\n\t\t\t\t\t\ttopologyHit = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!topologyHit) {\n\t\t\t\t\t// Data-only wave: keep layout unchanged. The cached layout\n\t\t\t\t\t// (from `initial` or a prior emit) is still valid.\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\treturn [this._computeLayout()];\n\t\t\t},\n\t\t\t{ initial: seedLayout, partial: true },\n\t\t);\n\t\tvoid layoutNode;\n\n\t\t// 3. Frame — merges latest layout with the per-wave changes from the\n\t\t// changeset. Two deps: layout (slow-moving — re-emits only on\n\t\t// topology) and changeset (fast-moving — re-emits per change event).\n\t\t// The fn collapses each wave into one LayoutFrame.\n\t\t//\n\t\t// `partial: true` opts out of the first-run gate so that a\n\t\t// data-only wave (where the layout dep settles RESOLVED but\n\t\t// changeset emits DATA) still triggers fn — without it, frame\n\t\t// would never run for data events because layout settled RESOLVED\n\t\t// and `_depSettledAsResolved` does NOT exit the sentinel state on\n\t\t// a dep, leaving the gate closed indefinitely.\n\t\tthis.frame = this.derived<LayoutFrame>(\n\t\t\t\"frame\",\n\t\t\t[\"layout\", \"changeset\"],\n\t\t\t(data, ctx) => {\n\t\t\t\tconst layoutBatch = data[0];\n\t\t\t\tconst changesetBatch = data[1];\n\t\t\t\tconst layout =\n\t\t\t\t\tlayoutBatch != null && layoutBatch.length > 0\n\t\t\t\t\t\t? (layoutBatch.at(-1) as Pick<LayoutFrame, \"boxes\" | \"edges\">)\n\t\t\t\t\t\t: (ctx.prevData[0] as Pick<LayoutFrame, \"boxes\" | \"edges\"> | undefined);\n\t\t\t\tif (layout == null) {\n\t\t\t\t\t// No layout yet — defer (skip emit). With `initial:` on\n\t\t\t\t\t// `layout`, this should never happen on the activation\n\t\t\t\t\t// wave, but guard for the edge case.\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\tconst changes: GraphChange[] = [];\n\t\t\t\tif (changesetBatch != null) {\n\t\t\t\t\tfor (const c of changesetBatch) changes.push(c as GraphChange);\n\t\t\t\t}\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tboxes: layout.boxes,\n\t\t\t\t\t\tedges: layout.edges,\n\t\t\t\t\t\tchanges,\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t},\n\t\t\t{\n\t\t\t\tinitial: { boxes: seedLayout.boxes, edges: seedLayout.edges, changes: [] },\n\t\t\t\tpartial: true,\n\t\t\t},\n\t\t);\n\n\t\t// No external keepalive — the chain `frame → layout → changeset` is\n\t\t// activated by external subscribers on `frame`. When the last consumer\n\t\t// unsubscribes, the chain tears down and releases the target observe\n\t\t// handle. Producer-bound lifecycle, no leaks.\n\t}\n\n\tprivate _computeLayout(): Pick<LayoutFrame, \"boxes\" | \"edges\"> {\n\t\t// /qa F-5: short-circuit if the target was destroyed. `target.describe()`\n\t\t// on a destroyed graph returns empty topology silently — without this\n\t\t// guard, frame consumers would see a degraded layout (empty boxes /\n\t\t// edges) with no signal that the underlying graph is gone. The COMPLETE\n\t\t// propagation is handled by the changeset stream's teardown variant\n\t\t// flowing through `frame`.\n\t\tif (this.target.destroyed) {\n\t\t\treturn { boxes: [], edges: [] };\n\t\t}\n\t\tconst spec = this.target.describe();\n\t\treturn this.layout(spec);\n\t}\n}\n\n/**\n * Factory wrapper — `topologyView({ graph, layout? })`.\n */\nexport function topologyView(opts: TopologyViewOptions): TopologyViewGraph {\n\tconst view = new TopologyViewGraph(opts);\n\tview.tagFactory(\"topologyView\");\n\treturn view;\n}\n","/**\n * Default layout for `topologyView` — wraps the bundled Sugiyama-style layered\n * DAG layout from `extra/render/_layout-sugiyama.ts`.\n *\n * The library ships zero deps and is browser-safe by default; the bundled\n * layout matches that ethos. Users wanting production-quality layout can swap\n * in `dagre`, `elk`, etc. by passing `opts.layout` to {@link topologyView}.\n *\n * Direction-agnostic (defaults to `\"LR\"`). Per-node label sizing is\n * conservative: 1 cell tall, label-length-derived width capped at 24 cells.\n *\n * @module\n */\n\nimport type { GraphDescribeOutput } from \"@graphrefly/pure-ts/graph\";\nimport {\n\ttype LayoutDirection,\n\ttype LayoutEdgePoint,\n\tsugiyamaLayout,\n} from \"../../base/render/_layout-sugiyama.js\";\nimport type { LayoutFn, LayoutFrame } from \"./types.js\";\n\nconst MIN_W = 3;\nconst MAX_W = 24;\nconst NODE_H = 1;\nconst LAYER_GAP = 4;\nconst NODE_GAP = 1;\n\n/**\n * Best-effort label-width estimate (cells). Caller can override by providing\n * its own {@link LayoutFn}; this default treats every visible character as\n * one cell. Local-segment is preferred over qualified path so the label\n * stays compact on cells with deep mounts.\n */\nfunction widthOf(id: string): number {\n\tconst local = id.includes(\"::\") ? (id.split(\"::\").pop() ?? id) : id;\n\treturn Math.max(MIN_W, Math.min(MAX_W, local.length + 2));\n}\n\nfunction heightOf(_id: string): number {\n\treturn NODE_H;\n}\n\n/**\n * Default layered-DAG layout for `topologyView`. Pure fn over a describe\n * snapshot; deterministic for a given input ordering.\n */\nexport function defaultLayout(\n\tspec: GraphDescribeOutput,\n\tdirection: LayoutDirection = \"LR\",\n): Pick<LayoutFrame, \"boxes\" | \"edges\"> {\n\tconst ids = Object.keys(spec.nodes).sort();\n\tconst edges = spec.edges.map((e) => ({ from: e.from, to: e.to }));\n\tif (ids.length === 0) {\n\t\treturn { boxes: [], edges: [] };\n\t}\n\tconst result = sugiyamaLayout({\n\t\tnodes: ids,\n\t\tedges,\n\t\twidthCells: widthOf,\n\t\theightCells: heightOf,\n\t\tlayerGap: LAYER_GAP,\n\t\tnodeGap: NODE_GAP,\n\t\tdirection,\n\t});\n\n\t// Map back to the public LayoutFrame shape, attaching per-node meta from\n\t// the describe snapshot for downstream renderers (kind/factory/domain).\n\tconst boxes = result.boxes.map((b) => ({\n\t\tid: b.id,\n\t\tx: b.x,\n\t\ty: b.y,\n\t\tw: b.w,\n\t\th: b.h,\n\t\tmeta: spec.nodes[b.id]?.meta,\n\t}));\n\n\t// Build a quick \"to → ordered deps\" lookup for `depIndex` attribution. The\n\t// describe snapshot's `nodes[id].deps` is the positional dep array; the\n\t// edge's depIndex is the position of `from` in `to`'s deps.\n\t//\n\t// /qa F-22: when the same upstream appears multiple times in `to.deps`\n\t// (diamond / duplicate-dep patterns), each (from, to) edge gets a distinct\n\t// depIndex via a per-`to` running cursor over occurrences in `toDeps`.\n\tconst seenPerTo = new Map<string, number>();\n\tconst edgeOut = result.edges.map((e) => {\n\t\tconst toDeps = spec.nodes[e.to]?.deps ?? [];\n\t\tconst cursorKey = `${e.to}::${e.from}`;\n\t\tconst startFrom = seenPerTo.get(cursorKey) ?? 0;\n\t\tconst depIndex = toDeps.indexOf(e.from, startFrom);\n\t\tseenPerTo.set(cursorKey, depIndex >= 0 ? depIndex + 1 : startFrom);\n\t\tconst points = e.points.map((p: LayoutEdgePoint) => [p.x, p.y] as const);\n\t\treturn {\n\t\t\tfrom: e.from,\n\t\t\tto: e.to,\n\t\t\tdepIndex: depIndex >= 0 ? depIndex : -1,\n\t\t\tpoints: points as ReadonlyArray<readonly [number, number]>,\n\t\t};\n\t});\n\n\treturn { boxes, edges: edgeOut };\n}\n\n/** Adapter — narrows `defaultLayout` to the {@link LayoutFn} signature. */\nexport const defaultLayoutFn: LayoutFn = (spec) => defaultLayout(spec, \"LR\");\n"],"mappings":"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","names":[]}
@@ -0,0 +1,66 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
5
+ var __typeError = (msg) => {
6
+ throw TypeError(msg);
7
+ };
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
10
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
11
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
12
+ }) : x)(function(x) {
13
+ if (typeof require !== "undefined") return require.apply(this, arguments);
14
+ throw Error('Dynamic require of "' + x + '" is not supported');
15
+ });
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
21
+ var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
22
+ var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
23
+ var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) });
24
+ var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
25
+ var __runInitializers = (array, flags, self, value) => {
26
+ for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
27
+ return value;
28
+ };
29
+ var __decorateElement = (array, flags, name, decorators, target, extra) => {
30
+ var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
31
+ var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
32
+ var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
33
+ var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : { get [name]() {
34
+ return __privateGet(this, extra);
35
+ }, set [name](x) {
36
+ return __privateSet(this, extra, x);
37
+ } }, name));
38
+ k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
39
+ for (var i = decorators.length - 1; i >= 0; i--) {
40
+ ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
41
+ if (k) {
42
+ ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => name in x };
43
+ if (k ^ 3) access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
44
+ if (k > 2) access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
45
+ }
46
+ it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? void 0 : { get: desc.get, set: desc.set } : target, ctx), done._ = 1;
47
+ if (k ^ 4 || it === void 0) __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
48
+ else if (typeof it !== "object" || it === null) __typeError("Object expected");
49
+ else __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
50
+ }
51
+ return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
52
+ };
53
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
54
+ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use the "in" operator on this value') : member.has(obj);
55
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
56
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
57
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
58
+
59
+ export {
60
+ __require,
61
+ __export,
62
+ __decoratorStart,
63
+ __runInitializers,
64
+ __decorateElement
65
+ };
66
+ //# sourceMappingURL=chunk-AZDQPQ3V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,90 @@
1
+ import {
2
+ firstValueFrom
3
+ } from "./chunk-O3MT7DYI.js";
4
+
5
+ // src/base/composition/single-from-any.ts
6
+ import { COMPLETE, ERROR } from "@graphrefly/pure-ts/core";
7
+ import { fromAny } from "@graphrefly/pure-ts/extra";
8
+ function singleFromAny(factory, opts = {}) {
9
+ const keyFn = opts.keyFn ?? ((k) => String(k));
10
+ const inFlight = /* @__PURE__ */ new Map();
11
+ return (key) => {
12
+ const k = keyFn(key);
13
+ const existing = inFlight.get(k);
14
+ if (existing) return existing;
15
+ const input = factory(key);
16
+ let rawPromise;
17
+ if (input != null && typeof input.then === "function") {
18
+ rawPromise = Promise.resolve(input);
19
+ } else if (input != null && typeof input === "object" && "subscribe" in input && "cache" in input) {
20
+ rawPromise = firstValueFrom(input);
21
+ } else if (input != null && typeof input === "object" && Symbol.asyncIterator in input) {
22
+ rawPromise = (async () => {
23
+ const iter = input[Symbol.asyncIterator]();
24
+ try {
25
+ const { value, done } = await iter.next();
26
+ if (done) throw new Error("singleFromAny: factory returned empty async iterable");
27
+ return value;
28
+ } finally {
29
+ await iter.return?.();
30
+ }
31
+ })();
32
+ } else if (input != null && typeof input === "object" && Symbol.iterator in input) {
33
+ rawPromise = (async () => {
34
+ const iter = input[Symbol.iterator]();
35
+ try {
36
+ const { value, done } = iter.next();
37
+ if (done) throw new Error("singleFromAny: factory returned empty iterable");
38
+ return value;
39
+ } finally {
40
+ iter.return?.();
41
+ }
42
+ })();
43
+ } else {
44
+ rawPromise = Promise.resolve(input);
45
+ }
46
+ let tracked;
47
+ const cleanup = () => {
48
+ if (inFlight.get(k) === tracked) inFlight.delete(k);
49
+ };
50
+ tracked = rawPromise.then(
51
+ (v) => {
52
+ cleanup();
53
+ return v;
54
+ },
55
+ (e) => {
56
+ cleanup();
57
+ throw e;
58
+ }
59
+ );
60
+ inFlight.set(k, tracked);
61
+ return tracked;
62
+ };
63
+ }
64
+ function singleNodeFromAny(factory, opts = {}) {
65
+ const keyFn = opts.keyFn ?? ((k) => String(k));
66
+ const inFlight = /* @__PURE__ */ new Map();
67
+ return (key) => {
68
+ const k = keyFn(key);
69
+ const existing = inFlight.get(k);
70
+ if (existing) return existing;
71
+ const node = fromAny(factory(key));
72
+ inFlight.set(k, node);
73
+ const unsub = node.subscribe((msgs) => {
74
+ for (const m of msgs) {
75
+ if (m[0] === ERROR || m[0] === COMPLETE) {
76
+ if (inFlight.get(k) === node) inFlight.delete(k);
77
+ unsub();
78
+ return;
79
+ }
80
+ }
81
+ });
82
+ return node;
83
+ };
84
+ }
85
+
86
+ export {
87
+ singleFromAny,
88
+ singleNodeFromAny
89
+ };
90
+ //# sourceMappingURL=chunk-BU3SEFA5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/base/composition/single-from-any.ts"],"sourcesContent":["/**\n * `singleFromAny` — keyed promise/Node de-duplication (\"singleflight\").\n *\n * Given a `factory: (key) => NodeInput<T>`, returns a callable that dedupes\n * concurrent invocations sharing the same key — all callers with the same\n * key while a request is in-flight receive the same `Promise<T>`. Once the\n * underlying source settles (DATA, ERROR, or COMPLETE), the cache entry is\n * cleared so the next call re-invokes the factory.\n *\n * This is the classic \"singleflight\" pattern from Go, generalised over the\n * library's `NodeInput<T>` bridge so callers can pass Promise-returning\n * factories, Node-returning factories, or plain value factories with\n * identical semantics.\n *\n * Use cases:\n * - `withReplayCache` cache-miss thundering-herd dedup\n * - Shared HTTP fetches keyed by URL\n * - Expensive compute keyed by request fingerprint\n *\n * @example\n * ```ts\n * const fetchUser = singleFromAny<string, User>((id) => fetch(`/users/${id}`).then(r => r.json()));\n * // Two concurrent callers with id=\"42\" → one underlying fetch, two Promises resolving to the same User.\n * const [a, b] = await Promise.all([fetchUser(\"42\"), fetchUser(\"42\")]);\n * ```\n *\n * @category extra\n */\n\nimport type { Node } from \"@graphrefly/pure-ts/core\";\nimport { COMPLETE, ERROR } from \"@graphrefly/pure-ts/core\";\n// Import directly from the source sub-files (rather than the `./sources.js`\n// barrel) so the `single-from-any` module is NOT part of any cycle that runs\n// through `extra/sources/index.ts` — eager re-exports through the barrel were\n// observed to leave `firstValueFrom` / `keepalive` unresolved during nested\n// import chains under vite-node.\nimport { fromAny, type NodeInput } from \"@graphrefly/pure-ts/extra\";\nimport { firstValueFrom } from \"../sources/settled.js\";\n\nexport interface SingleFromAnyOptions<K> {\n\t/**\n\t * Convert a typed key into a cache-string. Defaults to `String(key)`, which\n\t * works for primitive keys; callers with object keys should provide a\n\t * stable serializer (e.g., canonical JSON).\n\t */\n\tkeyFn?: (key: K) => string;\n}\n\n/**\n * Dedupe concurrent `factory(key)` invocations. Returns a bound callable.\n *\n * @param factory - Produces a `NodeInput<T>` for each unique key.\n * @param opts - Optional key-stringification.\n * @returns A function `(key: K) => Promise<T>` whose inflight results are shared per key.\n */\nexport function singleFromAny<K, T>(\n\tfactory: (key: K) => NodeInput<T>,\n\topts: SingleFromAnyOptions<K> = {},\n): (key: K) => Promise<T> {\n\tconst keyFn = opts.keyFn ?? ((k: K) => String(k));\n\tconst inFlight = new Map<string, Promise<T>>();\n\n\treturn (key: K): Promise<T> => {\n\t\tconst k = keyFn(key);\n\t\tconst existing = inFlight.get(k);\n\t\tif (existing) return existing;\n\n\t\tconst input = factory(key);\n\n\t\t// Resolve the NodeInput to a Promise<T>. Different input shapes need\n\t\t// different bridges — Promise/Node/AsyncIterable/Iterable/plain value.\n\t\tlet rawPromise: Promise<T>;\n\t\tif (input != null && typeof (input as PromiseLike<T>).then === \"function\") {\n\t\t\trawPromise = Promise.resolve(input as PromiseLike<T>);\n\t\t} else if (\n\t\t\tinput != null &&\n\t\t\ttypeof input === \"object\" &&\n\t\t\t\"subscribe\" in (input as object) &&\n\t\t\t\"cache\" in (input as object)\n\t\t) {\n\t\t\t// Node: bridge via firstValueFrom.\n\t\t\trawPromise = firstValueFrom(input as Node<T>);\n\t\t} else if (\n\t\t\tinput != null &&\n\t\t\ttypeof input === \"object\" &&\n\t\t\tSymbol.asyncIterator in (input as object)\n\t\t) {\n\t\t\t// AsyncIterable — take the first value, then close the iterator so\n\t\t\t// any owned resources (HTTP body, subscription, timer) are released.\n\t\t\trawPromise = (async () => {\n\t\t\t\tconst iter = (input as AsyncIterable<T>)[Symbol.asyncIterator]();\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = await iter.next();\n\t\t\t\t\tif (done) throw new Error(\"singleFromAny: factory returned empty async iterable\");\n\t\t\t\t\treturn value as T;\n\t\t\t\t} finally {\n\t\t\t\t\tawait iter.return?.();\n\t\t\t\t}\n\t\t\t})();\n\t\t} else if (input != null && typeof input === \"object\" && Symbol.iterator in (input as object)) {\n\t\t\t// Iterable — take the first value, close the iterator.\n\t\t\trawPromise = (async () => {\n\t\t\t\tconst iter = (input as Iterable<T>)[Symbol.iterator]();\n\t\t\t\ttry {\n\t\t\t\t\tconst { value, done } = iter.next();\n\t\t\t\t\tif (done) throw new Error(\"singleFromAny: factory returned empty iterable\");\n\t\t\t\t\treturn value as T;\n\t\t\t\t} finally {\n\t\t\t\t\titer.return?.();\n\t\t\t\t}\n\t\t\t})();\n\t\t} else {\n\t\t\t// Plain value.\n\t\t\trawPromise = Promise.resolve(input as T);\n\t\t}\n\n\t\t// Install the cache entry BEFORE attaching `.finally`. Otherwise a\n\t\t// sync-resolved Promise's finally microtask could run before the\n\t\t// `inFlight.set` below, leaving a stale entry installed afterwards.\n\t\t// We wrap in a holder whose reference we capture *before* chaining.\n\t\tlet tracked!: Promise<T>;\n\t\tconst cleanup = (): void => {\n\t\t\tif (inFlight.get(k) === tracked) inFlight.delete(k);\n\t\t};\n\t\ttracked = rawPromise.then(\n\t\t\t(v) => {\n\t\t\t\tcleanup();\n\t\t\t\treturn v;\n\t\t\t},\n\t\t\t(e) => {\n\t\t\t\tcleanup();\n\t\t\t\tthrow e;\n\t\t\t},\n\t\t);\n\t\tinFlight.set(k, tracked);\n\t\treturn tracked;\n\t};\n}\n\n/**\n * Reactive variant: returns a bound callable that hands out `Node<T>` values.\n * All concurrent callers with the same key during an in-flight source share\n * the same Node. When the underlying source **terminally** settles (ERROR\n * or COMPLETE), the Node is removed from the cache so the next call\n * re-invokes `factory`. DATA is NOT terminal — callers subscribing after\n * the first DATA still receive the shared Node (and push-on-subscribe per\n * the spec's cached-DATA contract).\n *\n * Use when downstream wants reactive subscription (not a one-shot Promise).\n *\n * @category extra\n */\nexport function singleNodeFromAny<K, T>(\n\tfactory: (key: K) => NodeInput<T>,\n\topts: SingleFromAnyOptions<K> = {},\n): (key: K) => Node<T> {\n\tconst keyFn = opts.keyFn ?? ((k: K) => String(k));\n\tconst inFlight = new Map<string, Node<T>>();\n\n\treturn (key: K): Node<T> => {\n\t\tconst k = keyFn(key);\n\t\tconst existing = inFlight.get(k);\n\t\tif (existing) return existing;\n\n\t\tconst node = fromAny(factory(key));\n\t\tinFlight.set(k, node);\n\n\t\t// Evict on terminal settle only — ERROR or COMPLETE. DATA is a value\n\t\t// emission, not a lifecycle transition; multi-emitting Nodes should\n\t\t// continue to share across subscribers after the first value.\n\t\tconst unsub = node.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (m[0] === ERROR || m[0] === COMPLETE) {\n\t\t\t\t\tif (inFlight.get(k) === node) inFlight.delete(k);\n\t\t\t\t\tunsub();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn node;\n\t};\n}\n"],"mappings":";;;;;AA8BA,SAAS,UAAU,aAAa;AAMhC,SAAS,eAA+B;AAmBjC,SAAS,cACf,SACA,OAAgC,CAAC,GACR;AACzB,QAAM,QAAQ,KAAK,UAAU,CAAC,MAAS,OAAO,CAAC;AAC/C,QAAM,WAAW,oBAAI,IAAwB;AAE7C,SAAO,CAAC,QAAuB;AAC9B,UAAM,IAAI,MAAM,GAAG;AACnB,UAAM,WAAW,SAAS,IAAI,CAAC;AAC/B,QAAI,SAAU,QAAO;AAErB,UAAM,QAAQ,QAAQ,GAAG;AAIzB,QAAI;AACJ,QAAI,SAAS,QAAQ,OAAQ,MAAyB,SAAS,YAAY;AAC1E,mBAAa,QAAQ,QAAQ,KAAuB;AAAA,IACrD,WACC,SAAS,QACT,OAAO,UAAU,YACjB,eAAgB,SAChB,WAAY,OACX;AAED,mBAAa,eAAe,KAAgB;AAAA,IAC7C,WACC,SAAS,QACT,OAAO,UAAU,YACjB,OAAO,iBAAkB,OACxB;AAGD,oBAAc,YAAY;AACzB,cAAM,OAAQ,MAA2B,OAAO,aAAa,EAAE;AAC/D,YAAI;AACH,gBAAM,EAAE,OAAO,KAAK,IAAI,MAAM,KAAK,KAAK;AACxC,cAAI,KAAM,OAAM,IAAI,MAAM,sDAAsD;AAChF,iBAAO;AAAA,QACR,UAAE;AACD,gBAAM,KAAK,SAAS;AAAA,QACrB;AAAA,MACD,GAAG;AAAA,IACJ,WAAW,SAAS,QAAQ,OAAO,UAAU,YAAY,OAAO,YAAa,OAAkB;AAE9F,oBAAc,YAAY;AACzB,cAAM,OAAQ,MAAsB,OAAO,QAAQ,EAAE;AACrD,YAAI;AACH,gBAAM,EAAE,OAAO,KAAK,IAAI,KAAK,KAAK;AAClC,cAAI,KAAM,OAAM,IAAI,MAAM,gDAAgD;AAC1E,iBAAO;AAAA,QACR,UAAE;AACD,eAAK,SAAS;AAAA,QACf;AAAA,MACD,GAAG;AAAA,IACJ,OAAO;AAEN,mBAAa,QAAQ,QAAQ,KAAU;AAAA,IACxC;AAMA,QAAI;AACJ,UAAM,UAAU,MAAY;AAC3B,UAAI,SAAS,IAAI,CAAC,MAAM,QAAS,UAAS,OAAO,CAAC;AAAA,IACnD;AACA,cAAU,WAAW;AAAA,MACpB,CAAC,MAAM;AACN,gBAAQ;AACR,eAAO;AAAA,MACR;AAAA,MACA,CAAC,MAAM;AACN,gBAAQ;AACR,cAAM;AAAA,MACP;AAAA,IACD;AACA,aAAS,IAAI,GAAG,OAAO;AACvB,WAAO;AAAA,EACR;AACD;AAeO,SAAS,kBACf,SACA,OAAgC,CAAC,GACX;AACtB,QAAM,QAAQ,KAAK,UAAU,CAAC,MAAS,OAAO,CAAC;AAC/C,QAAM,WAAW,oBAAI,IAAqB;AAE1C,SAAO,CAAC,QAAoB;AAC3B,UAAM,IAAI,MAAM,GAAG;AACnB,UAAM,WAAW,SAAS,IAAI,CAAC;AAC/B,QAAI,SAAU,QAAO;AAErB,UAAM,OAAO,QAAQ,QAAQ,GAAG,CAAC;AACjC,aAAS,IAAI,GAAG,IAAI;AAKpB,UAAM,QAAQ,KAAK,UAAU,CAAC,SAAS;AACtC,iBAAW,KAAK,MAAM;AACrB,YAAI,EAAE,CAAC,MAAM,SAAS,EAAE,CAAC,MAAM,UAAU;AACxC,cAAI,SAAS,IAAI,CAAC,MAAM,KAAM,UAAS,OAAO,CAAC;AAC/C,gBAAM;AACN;AAAA,QACD;AAAA,MACD;AAAA,IACD,CAAC;AACD,WAAO;AAAA,EACR;AACD;","names":[]}