@logixjs/core 0.0.1 → 1.0.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 (398) hide show
  1. package/LICENSE +201 -0
  2. package/dist/{Action-mqVvtEHt.d.ts → Action-DYl88bwj.d.ts} +1 -1
  3. package/dist/{Action-BkRHy2vg.d.cts → Action-DkxsI_DK.d.cts} +1 -1
  4. package/dist/Action.cjs.map +1 -1
  5. package/dist/Action.d.cts +1 -1
  6. package/dist/Action.d.ts +1 -1
  7. package/dist/Action.js +2 -2
  8. package/dist/{Actions-AsQ07yTP.d.cts → Actions-Dicm7jdc.d.cts} +2 -2
  9. package/dist/{Actions-AsQ07yTP.d.ts → Actions-Dicm7jdc.d.ts} +2 -2
  10. package/dist/Actions.cjs.map +1 -1
  11. package/dist/Actions.d.cts +1 -1
  12. package/dist/Actions.d.ts +1 -1
  13. package/dist/Actions.js +1 -1
  14. package/dist/{Bound-BN1DQ_lM.d.ts → Bound-1OJLzVIS.d.ts} +2 -2
  15. package/dist/{Bound-BPIfH9SS.d.cts → Bound-BMLrtQ1V.d.cts} +2 -2
  16. package/dist/Bound.cjs +1737 -399
  17. package/dist/Bound.cjs.map +1 -1
  18. package/dist/Bound.d.cts +5 -5
  19. package/dist/Bound.d.ts +5 -5
  20. package/dist/Bound.js +19 -17
  21. package/dist/{Debug-B5q5Bkzx.d.ts → Debug-DKrWP5H1.d.ts} +40 -22
  22. package/dist/{Debug-Bq8Sqjcr.d.cts → Debug-hIT44XsY.d.cts} +40 -22
  23. package/dist/Debug.cjs +1348 -318
  24. package/dist/Debug.cjs.map +1 -1
  25. package/dist/Debug.d.cts +12 -11
  26. package/dist/Debug.d.ts +12 -11
  27. package/dist/Debug.js +20 -11
  28. package/dist/EffectOp.cjs +15 -6
  29. package/dist/EffectOp.cjs.map +1 -1
  30. package/dist/EffectOp.js +3 -3
  31. package/dist/Env.cjs +772 -6
  32. package/dist/Env.cjs.map +1 -1
  33. package/dist/Env.js +5 -2
  34. package/dist/ExternalStore-DqJKKRJ4.d.ts +61 -0
  35. package/dist/ExternalStore-JC-gAgEI.d.cts +61 -0
  36. package/dist/ExternalStore.cjs +774 -0
  37. package/dist/ExternalStore.cjs.map +1 -0
  38. package/dist/ExternalStore.d.cts +8 -0
  39. package/dist/ExternalStore.d.ts +8 -0
  40. package/dist/ExternalStore.js +19 -0
  41. package/dist/ExternalStore.js.map +1 -0
  42. package/dist/{Flow-BhpjE22E.d.ts → Flow-CZmXRDqp.d.cts} +13 -4
  43. package/dist/{Flow-1fZT8MpX.d.cts → Flow-DIVDxz7R.d.ts} +13 -4
  44. package/dist/Flow.cjs +765 -148
  45. package/dist/Flow.cjs.map +1 -1
  46. package/dist/Flow.d.cts +6 -6
  47. package/dist/Flow.d.ts +6 -6
  48. package/dist/Flow.js +9 -8
  49. package/dist/{Handle-D_cLW1Z3.d.ts → Handle-Bo6cAFut.d.ts} +1 -1
  50. package/dist/{Handle-D8D1zPb_.d.cts → Handle-CfDvSqN7.d.cts} +1 -1
  51. package/dist/Handle.d.cts +5 -5
  52. package/dist/Handle.d.ts +5 -5
  53. package/dist/{Kernel-8kC-jOda.d.cts → Kernel-CuXBF9S_.d.cts} +16 -7
  54. package/dist/{Kernel-CnGE1Fyk.d.ts → Kernel-D9guNwRL.d.ts} +16 -7
  55. package/dist/Kernel.cjs +814 -26
  56. package/dist/Kernel.cjs.map +1 -1
  57. package/dist/Kernel.d.cts +13 -12
  58. package/dist/Kernel.d.ts +13 -12
  59. package/dist/Kernel.js +7 -4
  60. package/dist/{Link-Db7975nU.d.ts → Link-CUM0yUCH.d.ts} +10 -3
  61. package/dist/{Link-fX8x1eCK.d.cts → Link-NAfR6uGD.d.cts} +10 -3
  62. package/dist/Link.cjs +1294 -121
  63. package/dist/Link.cjs.map +1 -1
  64. package/dist/Link.d.cts +5 -5
  65. package/dist/Link.d.ts +5 -5
  66. package/dist/Link.js +37 -29
  67. package/dist/{Logic-DRh4sDZj.d.cts → Logic-09VQpIj3.d.cts} +7 -4
  68. package/dist/{Logic-BRjEMr-W.d.ts → Logic-DKg7ghGy.d.ts} +7 -4
  69. package/dist/Logic.cjs +2 -1
  70. package/dist/Logic.cjs.map +1 -1
  71. package/dist/Logic.d.cts +5 -5
  72. package/dist/Logic.d.ts +5 -5
  73. package/dist/Logic.js +1 -1
  74. package/dist/{MatchBuilder-CJk5oCkR.d.cts → MatchBuilder-CsW5jgrL.d.ts} +1 -1
  75. package/dist/{MatchBuilder-0QOc-nlU.d.ts → MatchBuilder-Dksk07F4.d.cts} +1 -1
  76. package/dist/MatchBuilder.cjs +2 -2
  77. package/dist/MatchBuilder.cjs.map +1 -1
  78. package/dist/MatchBuilder.d.cts +6 -6
  79. package/dist/MatchBuilder.d.ts +6 -6
  80. package/dist/MatchBuilder.js +2 -2
  81. package/dist/Middleware-D8tUDLv_.d.cts +100 -0
  82. package/dist/Middleware-DS7CbTTN.d.ts +100 -0
  83. package/dist/Middleware.cjs +678 -58
  84. package/dist/Middleware.cjs.map +1 -1
  85. package/dist/Middleware.d.cts +2 -86
  86. package/dist/Middleware.d.ts +2 -86
  87. package/dist/Middleware.js +15 -12
  88. package/dist/{Module-DnzluX2J.d.ts → Module-B_Cntyms.d.ts} +54 -25
  89. package/dist/{Module-B_0xRDMR.d.cts → Module-CmNOVXzf.d.cts} +54 -25
  90. package/dist/Module.cjs +9331 -3317
  91. package/dist/Module.cjs.map +1 -1
  92. package/dist/Module.d.cts +7 -6
  93. package/dist/Module.d.ts +7 -6
  94. package/dist/Module.js +39 -31
  95. package/dist/ModuleTag-CGho_InD.d.ts +113 -0
  96. package/dist/ModuleTag-CITb8L_G.d.cts +113 -0
  97. package/dist/ModuleTag.cjs +7248 -2847
  98. package/dist/ModuleTag.cjs.map +1 -1
  99. package/dist/ModuleTag.d.cts +6 -6
  100. package/dist/ModuleTag.d.ts +6 -6
  101. package/dist/ModuleTag.js +35 -29
  102. package/dist/Observability-Bdhnx2Dv.d.ts +385 -0
  103. package/dist/Observability-DXGAFBIT.d.cts +385 -0
  104. package/dist/Observability.cjs +5093 -1556
  105. package/dist/Observability.cjs.map +1 -1
  106. package/dist/Observability.d.cts +6 -7
  107. package/dist/Observability.d.ts +6 -7
  108. package/dist/Observability.js +28 -23
  109. package/dist/{Platform-CHX8o-U4.d.ts → Platform-B4s8tg6C.d.cts} +4 -5
  110. package/dist/{Platform-C49Pv956.d.cts → Platform-BV_0MW7g.d.cts} +5 -2
  111. package/dist/{Platform-C49Pv956.d.ts → Platform-BV_0MW7g.d.ts} +5 -2
  112. package/dist/{Platform-CVlv0xLQ.d.cts → Platform-W0Mefy_e.d.ts} +4 -5
  113. package/dist/Platform.cjs +2 -1
  114. package/dist/Platform.cjs.map +1 -1
  115. package/dist/Platform.d.cts +2 -3
  116. package/dist/Platform.d.ts +2 -3
  117. package/dist/Platform.js +2 -2
  118. package/dist/{Process-CM9xbMdP.d.ts → Process-CO8G7HO9.d.cts} +30 -5
  119. package/dist/{Process-mL8fHDSB.d.cts → Process-Cyf6VNDR.d.ts} +30 -5
  120. package/dist/Process.cjs +1288 -120
  121. package/dist/Process.cjs.map +1 -1
  122. package/dist/Process.d.cts +6 -6
  123. package/dist/Process.d.ts +6 -6
  124. package/dist/Process.js +34 -26
  125. package/dist/ReadQuery-C_or5nLC.d.ts +128 -0
  126. package/dist/ReadQuery-DXLzCE0E.d.cts +614 -0
  127. package/dist/ReadQuery-DXLzCE0E.d.ts +614 -0
  128. package/dist/ReadQuery-Yve1lmUo.d.cts +128 -0
  129. package/dist/ReadQuery.cjs +290 -5
  130. package/dist/ReadQuery.cjs.map +1 -1
  131. package/dist/ReadQuery.d.cts +3 -2
  132. package/dist/ReadQuery.d.ts +3 -2
  133. package/dist/ReadQuery.js +23 -5
  134. package/dist/{Reflection-CQnKwPXj.d.ts → Reflection-B2Xi1e4Q.d.ts} +89 -7
  135. package/dist/{Reflection-Kabo1mlU.d.cts → Reflection-DNB4V4_e.d.cts} +89 -7
  136. package/dist/Reflection.cjs +3227 -1617
  137. package/dist/Reflection.cjs.map +1 -1
  138. package/dist/Reflection.d.cts +17 -15
  139. package/dist/Reflection.d.ts +17 -15
  140. package/dist/Reflection.js +33 -25
  141. package/dist/{Resource-Dy1xD_DG.d.cts → Resource-pKvQQ4x5.d.cts} +3 -3
  142. package/dist/{Resource-Dy1xD_DG.d.ts → Resource-pKvQQ4x5.d.ts} +3 -3
  143. package/dist/Resource.cjs +781 -15
  144. package/dist/Resource.cjs.map +1 -1
  145. package/dist/Resource.d.cts +1 -1
  146. package/dist/Resource.d.ts +1 -1
  147. package/dist/Resource.js +6 -3
  148. package/dist/{Root-7ADUMk4t.d.cts → Root-CCVuFHB6.d.cts} +3 -3
  149. package/dist/{Root-7ADUMk4t.d.ts → Root-CCVuFHB6.d.ts} +3 -3
  150. package/dist/Root.cjs +786 -20
  151. package/dist/Root.cjs.map +1 -1
  152. package/dist/Root.d.cts +2 -2
  153. package/dist/Root.d.ts +2 -2
  154. package/dist/Root.js +7 -3
  155. package/dist/{Runtime-CtyzZG4i.d.ts → Runtime-CRmvwK4I.d.ts} +70 -14
  156. package/dist/{Runtime-B-aL-f29.d.cts → Runtime-C_wJM9mN.d.cts} +70 -14
  157. package/dist/Runtime.cjs +4942 -1601
  158. package/dist/Runtime.cjs.map +1 -1
  159. package/dist/Runtime.d.cts +17 -15
  160. package/dist/Runtime.d.ts +17 -15
  161. package/dist/Runtime.js +44 -32
  162. package/dist/{ScopeRegistry-D1owDNSm.d.cts → ScopeRegistry-BhYzqWri.d.cts} +6 -6
  163. package/dist/{ScopeRegistry-D1owDNSm.d.ts → ScopeRegistry-BhYzqWri.d.ts} +6 -6
  164. package/dist/ScopeRegistry.cjs +776 -10
  165. package/dist/ScopeRegistry.cjs.map +1 -1
  166. package/dist/ScopeRegistry.d.cts +1 -1
  167. package/dist/ScopeRegistry.d.ts +1 -1
  168. package/dist/ScopeRegistry.js +6 -3
  169. package/dist/{State-CU50R26M.d.cts → State-rNFsFPTl.d.cts} +2 -2
  170. package/dist/{State-CU50R26M.d.ts → State-rNFsFPTl.d.ts} +2 -2
  171. package/dist/State.cjs.map +1 -1
  172. package/dist/State.d.cts +1 -1
  173. package/dist/State.d.ts +1 -1
  174. package/dist/State.js +1 -1
  175. package/dist/{StateTrait-BGsZghTz.d.ts → StateTrait-CijdwNb6.d.ts} +25 -8
  176. package/dist/{StateTrait-OWhbj12c.d.cts → StateTrait-Dltto6PU.d.cts} +25 -8
  177. package/dist/StateTrait.cjs +1890 -528
  178. package/dist/StateTrait.cjs.map +1 -1
  179. package/dist/StateTrait.d.cts +9 -7
  180. package/dist/StateTrait.d.ts +9 -7
  181. package/dist/StateTrait.js +18 -14
  182. package/dist/{TraitLifecycle-CwV5WPFX.d.cts → TraitLifecycle-BKzDqzLu.d.cts} +2 -2
  183. package/dist/{TraitLifecycle-LdIWmKlg.d.ts → TraitLifecycle-Cvo94uDB.d.ts} +2 -2
  184. package/dist/TraitLifecycle.cjs +630 -67
  185. package/dist/TraitLifecycle.cjs.map +1 -1
  186. package/dist/TraitLifecycle.d.cts +6 -6
  187. package/dist/TraitLifecycle.d.ts +6 -6
  188. package/dist/TraitLifecycle.js +8 -7
  189. package/dist/Workflow-C_OWr4dV.d.ts +415 -0
  190. package/dist/Workflow-DmydkHO8.d.cts +415 -0
  191. package/dist/Workflow.cjs +3150 -0
  192. package/dist/Workflow.cjs.map +1 -0
  193. package/dist/Workflow.d.cts +7 -0
  194. package/dist/Workflow.d.ts +7 -0
  195. package/dist/Workflow.js +58 -0
  196. package/dist/Workflow.js.map +1 -0
  197. package/dist/{action-DiMDD_0v.d.cts → action-BQxjPFEw.d.cts} +5 -5
  198. package/dist/{action-DiMDD_0v.d.ts → action-BQxjPFEw.d.ts} +5 -5
  199. package/dist/chunk-2XRLXDWR.js +276 -0
  200. package/dist/chunk-2XRLXDWR.js.map +1 -0
  201. package/dist/chunk-3L6QGFMM.js +701 -0
  202. package/dist/chunk-3L6QGFMM.js.map +1 -0
  203. package/dist/{chunk-GMPEOUP2.js → chunk-4MZ7BT3R.js} +2 -2
  204. package/dist/chunk-4MZ7BT3R.js.map +1 -0
  205. package/dist/{chunk-3IYZ5IGG.js → chunk-5WKUGEBY.js} +2 -2
  206. package/dist/{chunk-3RMKLXHX.js → chunk-63ZQ5RIN.js} +2 -2
  207. package/dist/{chunk-M3WTHJHJ.js → chunk-67DIEA53.js} +385 -148
  208. package/dist/chunk-67DIEA53.js.map +1 -0
  209. package/dist/{chunk-YS3AZQ2G.js → chunk-6HFAW2MH.js} +1 -1
  210. package/dist/chunk-6HFAW2MH.js.map +1 -0
  211. package/dist/{chunk-EY4NZKDR.js → chunk-6Y2TKCNY.js} +2 -2
  212. package/dist/{chunk-76WT3HOR.js → chunk-6YZOXFPQ.js} +25 -24
  213. package/dist/chunk-6YZOXFPQ.js.map +1 -0
  214. package/dist/{chunk-G5ZBFPNU.js → chunk-A2RQOJC7.js} +2 -2
  215. package/dist/{chunk-AUIR5O6W.js → chunk-AFSB6NKM.js} +13 -19
  216. package/dist/chunk-AFSB6NKM.js.map +1 -0
  217. package/dist/{chunk-JCXGZRMU.js → chunk-AO4JEOKD.js} +22 -23
  218. package/dist/chunk-AO4JEOKD.js.map +1 -0
  219. package/dist/{chunk-TAAPQVZN.js → chunk-AYELIQXR.js} +2 -2
  220. package/dist/{chunk-QMM6O4CD.js → chunk-BLHZW7DG.js} +15 -3
  221. package/dist/{chunk-QMM6O4CD.js.map → chunk-BLHZW7DG.js.map} +1 -1
  222. package/dist/{chunk-TQOBJYDP.js → chunk-CD4N74YC.js} +1 -1
  223. package/dist/chunk-CD4N74YC.js.map +1 -0
  224. package/dist/{chunk-ANLBCBDC.js → chunk-CGE2HBTH.js} +11 -11
  225. package/dist/chunk-CGE2HBTH.js.map +1 -0
  226. package/dist/{chunk-OFADUJWJ.js → chunk-CYYSQMLO.js} +5 -5
  227. package/dist/chunk-CYYSQMLO.js.map +1 -0
  228. package/dist/{chunk-66ALHVEX.js → chunk-EB46EYI7.js} +3 -3
  229. package/dist/{chunk-NZJKFF45.js → chunk-EKCDHWRK.js} +4 -4
  230. package/dist/chunk-EKCDHWRK.js.map +1 -0
  231. package/dist/{chunk-BABLDP24.js → chunk-EPQFNJU3.js} +152 -7
  232. package/dist/chunk-EPQFNJU3.js.map +1 -0
  233. package/dist/{chunk-OGWBVHB3.js → chunk-ESR6HGOY.js} +73 -14
  234. package/dist/chunk-ESR6HGOY.js.map +1 -0
  235. package/dist/{chunk-NBD3KUOZ.js → chunk-F6RP62H3.js} +150 -98
  236. package/dist/chunk-F6RP62H3.js.map +1 -0
  237. package/dist/chunk-FBYW3QDI.js +252 -0
  238. package/dist/chunk-FBYW3QDI.js.map +1 -0
  239. package/dist/{chunk-IPF7E66P.js → chunk-FYAODKVP.js} +2 -2
  240. package/dist/chunk-GNEN7NKO.js +908 -0
  241. package/dist/chunk-GNEN7NKO.js.map +1 -0
  242. package/dist/chunk-GWSM4KLB.js +763 -0
  243. package/dist/chunk-GWSM4KLB.js.map +1 -0
  244. package/dist/{chunk-4SO6JMZL.js → chunk-HDMXCUZL.js} +1 -1
  245. package/dist/chunk-HDMXCUZL.js.map +1 -0
  246. package/dist/{chunk-ZFY7U2FR.js → chunk-HJM5Y5NU.js} +43 -3
  247. package/dist/chunk-HJM5Y5NU.js.map +1 -0
  248. package/dist/{chunk-ZGDVUPTM.js → chunk-IOZ3VKPK.js} +129 -68
  249. package/dist/chunk-IOZ3VKPK.js.map +1 -0
  250. package/dist/{chunk-PYOE4VSI.js → chunk-IVXSVHO4.js} +303 -247
  251. package/dist/chunk-IVXSVHO4.js.map +1 -0
  252. package/dist/chunk-J3CWXIPV.js +242 -0
  253. package/dist/chunk-J3CWXIPV.js.map +1 -0
  254. package/dist/chunk-K6JQW266.js +42 -0
  255. package/dist/chunk-K6JQW266.js.map +1 -0
  256. package/dist/chunk-KMZYQF6Q.js +202 -0
  257. package/dist/chunk-KMZYQF6Q.js.map +1 -0
  258. package/dist/{chunk-JWOYLO27.js → chunk-LPPZDFTD.js} +22 -12
  259. package/dist/chunk-LPPZDFTD.js.map +1 -0
  260. package/dist/{chunk-PAYXCY6A.js → chunk-MYB2B5WX.js} +997 -576
  261. package/dist/chunk-MYB2B5WX.js.map +1 -0
  262. package/dist/chunk-MYKNINNN.js +228 -0
  263. package/dist/chunk-MYKNINNN.js.map +1 -0
  264. package/dist/chunk-NSQIRMVF.js +27 -0
  265. package/dist/{chunk-QCHIQWAJ.js.map → chunk-NSQIRMVF.js.map} +1 -1
  266. package/dist/chunk-NUDBM4MM.js +30 -0
  267. package/dist/chunk-NUDBM4MM.js.map +1 -0
  268. package/dist/chunk-NZMWWDAY.js +23 -0
  269. package/dist/chunk-NZMWWDAY.js.map +1 -0
  270. package/dist/{chunk-RNFE3ML2.js → chunk-OCUV2Y25.js} +4 -3
  271. package/dist/chunk-OCUV2Y25.js.map +1 -0
  272. package/dist/chunk-P4ZJOQA7.js +271 -0
  273. package/dist/chunk-P4ZJOQA7.js.map +1 -0
  274. package/dist/chunk-P6C5EZ3D.js +342 -0
  275. package/dist/chunk-P6C5EZ3D.js.map +1 -0
  276. package/dist/{chunk-CW6T36TN.js → chunk-PBD7BJUN.js} +62 -4
  277. package/dist/chunk-PBD7BJUN.js.map +1 -0
  278. package/dist/chunk-PBIUCQY3.js +696 -0
  279. package/dist/chunk-PBIUCQY3.js.map +1 -0
  280. package/dist/chunk-PD6YECQH.js +845 -0
  281. package/dist/chunk-PD6YECQH.js.map +1 -0
  282. package/dist/{chunk-M7IYCTJV.js → chunk-R4LFQGP3.js} +2 -2
  283. package/dist/chunk-RHJIGDUE.js +21 -0
  284. package/dist/chunk-RHJIGDUE.js.map +1 -0
  285. package/dist/{chunk-KP7MUZNX.js → chunk-RLXO27MW.js} +30 -8
  286. package/dist/chunk-RLXO27MW.js.map +1 -0
  287. package/dist/{chunk-DFNM3WX2.js → chunk-S44BEV4B.js} +168 -45
  288. package/dist/chunk-S44BEV4B.js.map +1 -0
  289. package/dist/chunk-S4S5N4BJ.js +1461 -0
  290. package/dist/chunk-S4S5N4BJ.js.map +1 -0
  291. package/dist/{chunk-BZ2SHDN2.js → chunk-SGTRAXXX.js} +3 -3
  292. package/dist/chunk-SGTRAXXX.js.map +1 -0
  293. package/dist/{chunk-M2RGJPXX.js → chunk-SJAE5PB5.js} +3 -3
  294. package/dist/{chunk-JGIWG6SR.js → chunk-SNPNHU3H.js} +3937 -1776
  295. package/dist/chunk-SNPNHU3H.js.map +1 -0
  296. package/dist/{chunk-IHVBV5C2.js → chunk-SOOBFXRR.js} +94 -71
  297. package/dist/chunk-SOOBFXRR.js.map +1 -0
  298. package/dist/{chunk-ZDTRWK5F.js → chunk-TAHFWKS6.js} +2 -2
  299. package/dist/chunk-UEFFTVPY.js +9 -0
  300. package/dist/chunk-UEFFTVPY.js.map +1 -0
  301. package/dist/{chunk-24VULZ7A.js → chunk-UR5BXLBP.js} +3 -3
  302. package/dist/chunk-UR5BXLBP.js.map +1 -0
  303. package/dist/{chunk-DMBALCE2.js → chunk-V2SBGVDO.js} +471 -186
  304. package/dist/chunk-V2SBGVDO.js.map +1 -0
  305. package/dist/chunk-VJLWD47W.js +23 -0
  306. package/dist/chunk-VJLWD47W.js.map +1 -0
  307. package/dist/{chunk-4CQAV7YB.js → chunk-W647DX5Z.js} +2 -2
  308. package/dist/{chunk-THATMZXD.js → chunk-WFIIU3YZ.js} +2 -2
  309. package/dist/{chunk-THATMZXD.js.map → chunk-WFIIU3YZ.js.map} +1 -1
  310. package/dist/chunk-YZDJMAKL.js +82 -0
  311. package/dist/chunk-YZDJMAKL.js.map +1 -0
  312. package/dist/{chunk-3TMODYZV.js → chunk-Z5XH6VHY.js} +5 -5
  313. package/dist/chunk-Z5XH6VHY.js.map +1 -0
  314. package/dist/{chunk-BE3HW4FY.js → chunk-ZBBMZMA6.js} +377 -170
  315. package/dist/chunk-ZBBMZMA6.js.map +1 -0
  316. package/dist/index.cjs +21224 -11714
  317. package/dist/index.cjs.map +1 -1
  318. package/dist/index.d.cts +195 -49
  319. package/dist/index.d.ts +195 -49
  320. package/dist/index.js +150 -74
  321. package/dist/index.js.map +1 -1
  322. package/dist/{ir-BMP7yxJJ.d.cts → ir-BSosEwc8.d.cts} +1 -1
  323. package/dist/{ir-DUOz6H-5.d.ts → ir-D-uqwL_4.d.ts} +1 -1
  324. package/dist/{module-B8CBqIZ_.d.cts → module-Ds4tarcI.d.cts} +230 -140
  325. package/dist/{module-k7m3txak.d.ts → module-Zd1Gn-Nj.d.ts} +230 -140
  326. package/package.json +20 -4
  327. package/dist/ModuleTag-C8FHY_sY.d.ts +0 -93
  328. package/dist/ModuleTag-EGbgBMpZ.d.cts +0 -93
  329. package/dist/Observability-COqEvp2C.d.cts +0 -713
  330. package/dist/Observability-cY4kLn0S.d.ts +0 -713
  331. package/dist/ReadQuery-BlMwhe-F.d.ts +0 -30
  332. package/dist/ReadQuery-CL5XlXts.d.cts +0 -30
  333. package/dist/ReadQuery-SinbStGF.d.cts +0 -38
  334. package/dist/ReadQuery-SinbStGF.d.ts +0 -38
  335. package/dist/chunk-24VULZ7A.js.map +0 -1
  336. package/dist/chunk-3QMIVH35.js +0 -43
  337. package/dist/chunk-3QMIVH35.js.map +0 -1
  338. package/dist/chunk-3TMODYZV.js.map +0 -1
  339. package/dist/chunk-4SO6JMZL.js.map +0 -1
  340. package/dist/chunk-76WT3HOR.js.map +0 -1
  341. package/dist/chunk-ANLBCBDC.js.map +0 -1
  342. package/dist/chunk-AUIR5O6W.js.map +0 -1
  343. package/dist/chunk-BABLDP24.js.map +0 -1
  344. package/dist/chunk-BE3HW4FY.js.map +0 -1
  345. package/dist/chunk-BZ2SHDN2.js.map +0 -1
  346. package/dist/chunk-CW6T36TN.js.map +0 -1
  347. package/dist/chunk-DFNM3WX2.js.map +0 -1
  348. package/dist/chunk-DMBALCE2.js.map +0 -1
  349. package/dist/chunk-EGK3KN7B.js +0 -406
  350. package/dist/chunk-EGK3KN7B.js.map +0 -1
  351. package/dist/chunk-GMPEOUP2.js.map +0 -1
  352. package/dist/chunk-IHVBV5C2.js.map +0 -1
  353. package/dist/chunk-JCXGZRMU.js.map +0 -1
  354. package/dist/chunk-JGIWG6SR.js.map +0 -1
  355. package/dist/chunk-JWOYLO27.js.map +0 -1
  356. package/dist/chunk-KIXAU3GM.js +0 -137
  357. package/dist/chunk-KIXAU3GM.js.map +0 -1
  358. package/dist/chunk-KL5ACTCT.js +0 -8
  359. package/dist/chunk-KL5ACTCT.js.map +0 -1
  360. package/dist/chunk-KP7MUZNX.js.map +0 -1
  361. package/dist/chunk-M3BFQ7HK.js +0 -13
  362. package/dist/chunk-M3BFQ7HK.js.map +0 -1
  363. package/dist/chunk-M3WTHJHJ.js.map +0 -1
  364. package/dist/chunk-NBD3KUOZ.js.map +0 -1
  365. package/dist/chunk-NQZ2OSGR.js +0 -151
  366. package/dist/chunk-NQZ2OSGR.js.map +0 -1
  367. package/dist/chunk-NZJKFF45.js.map +0 -1
  368. package/dist/chunk-OFADUJWJ.js.map +0 -1
  369. package/dist/chunk-OGWBVHB3.js.map +0 -1
  370. package/dist/chunk-PAYXCY6A.js.map +0 -1
  371. package/dist/chunk-PYOE4VSI.js.map +0 -1
  372. package/dist/chunk-QCHIQWAJ.js +0 -21
  373. package/dist/chunk-RNFE3ML2.js.map +0 -1
  374. package/dist/chunk-TKZ7MEIA.js +0 -27
  375. package/dist/chunk-TKZ7MEIA.js.map +0 -1
  376. package/dist/chunk-TQOBJYDP.js.map +0 -1
  377. package/dist/chunk-VZB726PE.js +0 -93
  378. package/dist/chunk-VZB726PE.js.map +0 -1
  379. package/dist/chunk-W3TEWHLO.js +0 -568
  380. package/dist/chunk-W3TEWHLO.js.map +0 -1
  381. package/dist/chunk-YS3AZQ2G.js.map +0 -1
  382. package/dist/chunk-ZFLHVFUC.js +0 -192
  383. package/dist/chunk-ZFLHVFUC.js.map +0 -1
  384. package/dist/chunk-ZFY7U2FR.js.map +0 -1
  385. package/dist/chunk-ZGDVUPTM.js.map +0 -1
  386. package/dist/protocol-g_1897M2.d.cts +0 -127
  387. package/dist/protocol-g_1897M2.d.ts +0 -127
  388. /package/dist/{chunk-3IYZ5IGG.js.map → chunk-5WKUGEBY.js.map} +0 -0
  389. /package/dist/{chunk-3RMKLXHX.js.map → chunk-63ZQ5RIN.js.map} +0 -0
  390. /package/dist/{chunk-EY4NZKDR.js.map → chunk-6Y2TKCNY.js.map} +0 -0
  391. /package/dist/{chunk-G5ZBFPNU.js.map → chunk-A2RQOJC7.js.map} +0 -0
  392. /package/dist/{chunk-TAAPQVZN.js.map → chunk-AYELIQXR.js.map} +0 -0
  393. /package/dist/{chunk-66ALHVEX.js.map → chunk-EB46EYI7.js.map} +0 -0
  394. /package/dist/{chunk-IPF7E66P.js.map → chunk-FYAODKVP.js.map} +0 -0
  395. /package/dist/{chunk-M7IYCTJV.js.map → chunk-R4LFQGP3.js.map} +0 -0
  396. /package/dist/{chunk-M2RGJPXX.js.map → chunk-SJAE5PB5.js.map} +0 -0
  397. /package/dist/{chunk-ZDTRWK5F.js.map → chunk-TAHFWKS6.js.map} +0 -0
  398. /package/dist/{chunk-4CQAV7YB.js.map → chunk-W647DX5Z.js.map} +0 -0
@@ -34,6 +34,7 @@ __export(StateTrait_exports, {
34
34
  build: () => build2,
35
35
  computed: () => computed,
36
36
  exportStaticIr: () => exportStaticIr2,
37
+ externalStore: () => externalStore,
37
38
  from: () => from,
38
39
  install: () => install2,
39
40
  link: () => link,
@@ -43,6 +44,118 @@ __export(StateTrait_exports, {
43
44
  });
44
45
  module.exports = __toCommonJS(StateTrait_exports);
45
46
 
47
+ // src/internal/field-path.ts
48
+ var isFieldPathSegment = (seg) => {
49
+ if (!seg) return false;
50
+ if (seg === "*") return false;
51
+ if (/^\d+$/.test(seg)) return false;
52
+ if (seg.includes("[") || seg.includes("]")) return false;
53
+ return true;
54
+ };
55
+ var normalizeFieldPath = (input) => {
56
+ if (typeof input === "string") {
57
+ const segs = splitSegments(input);
58
+ if (!segs || segs.length === 0) return void 0;
59
+ const normalized2 = segs.filter(isFieldPathSegment);
60
+ return normalized2.length > 0 ? normalized2 : void 0;
61
+ }
62
+ if (input.length === 0) return void 0;
63
+ let needsFilter = false;
64
+ for (const seg of input) {
65
+ if (!isFieldPathSegment(seg)) {
66
+ needsFilter = true;
67
+ break;
68
+ }
69
+ }
70
+ if (!needsFilter) return input;
71
+ const normalized = input.filter(isFieldPathSegment);
72
+ return normalized.length > 0 ? normalized : void 0;
73
+ };
74
+ var compareFieldPath = (a, b) => {
75
+ const len = Math.min(a.length, b.length);
76
+ for (let i = 0; i < len; i++) {
77
+ const as = a[i];
78
+ const bs = b[i];
79
+ if (as === bs) continue;
80
+ return as < bs ? -1 : 1;
81
+ }
82
+ return a.length - b.length;
83
+ };
84
+ var makeFieldPathIdRegistry = (fieldPaths) => {
85
+ const root = { children: /* @__PURE__ */ new Map() };
86
+ const pathStringToId = /* @__PURE__ */ new Map();
87
+ const ambiguousPathStrings = /* @__PURE__ */ new Set();
88
+ for (let id = 0; id < fieldPaths.length; id++) {
89
+ const path = fieldPaths[id];
90
+ let node2 = root;
91
+ for (const seg of path) {
92
+ const children = node2.children;
93
+ let next = children.get(seg);
94
+ if (!next) {
95
+ next = { children: /* @__PURE__ */ new Map() };
96
+ children.set(seg, next);
97
+ }
98
+ node2 = next;
99
+ }
100
+ node2.id = id;
101
+ if (path.length > 0 && path.some((seg) => seg.includes("."))) {
102
+ const key = path.join(".");
103
+ ambiguousPathStrings.add(key);
104
+ pathStringToId.delete(key);
105
+ }
106
+ if (path.length > 0 && path.every((seg) => !seg.includes(".") && !seg.includes("[") && !seg.includes("]"))) {
107
+ const key = path.join(".");
108
+ if (ambiguousPathStrings.has(key)) continue;
109
+ if (pathStringToId.has(key)) {
110
+ ambiguousPathStrings.add(key);
111
+ pathStringToId.delete(key);
112
+ continue;
113
+ }
114
+ pathStringToId.set(key, id);
115
+ }
116
+ }
117
+ return { fieldPaths, root, pathStringToId };
118
+ };
119
+ var getFieldPathId = (registry, path) => {
120
+ let node2 = registry.root;
121
+ for (const seg of path) {
122
+ const next = node2.children.get(seg);
123
+ if (!next) return void 0;
124
+ node2 = next;
125
+ }
126
+ return node2.id;
127
+ };
128
+ var splitSegments = (path) => {
129
+ if (!path) return void 0;
130
+ if (path === "*") return void 0;
131
+ const parts = path.split(".").filter((p) => p.length > 0);
132
+ const segs = [];
133
+ for (const part of parts) {
134
+ if (!part) continue;
135
+ if (part === "*") {
136
+ return void 0;
137
+ }
138
+ if (part.endsWith("[]")) {
139
+ const base = part.slice(0, -2);
140
+ if (base) segs.push(base);
141
+ continue;
142
+ }
143
+ const bracket = /^(.+)\[(\d+)\]$/.exec(part);
144
+ if (bracket) {
145
+ segs.push(bracket[1]);
146
+ continue;
147
+ }
148
+ if (/^\d+$/.test(part)) {
149
+ continue;
150
+ }
151
+ if (part.includes("[") || part.includes("]")) {
152
+ return void 0;
153
+ }
154
+ segs.push(part);
155
+ }
156
+ return segs;
157
+ };
158
+
46
159
  // src/internal/state-trait/rowid.ts
47
160
  var parseSegments = (path) => {
48
161
  if (!path) return [];
@@ -106,21 +219,31 @@ var uniqSortedStrings = (input) => {
106
219
  if (!v) continue;
107
220
  set.add(v);
108
221
  }
109
- return Array.from(set).sort((a, b) => a.localeCompare(b));
222
+ return Array.from(set).sort();
110
223
  };
111
224
  var isPlainRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
112
- var sanitizeJsonValue = (input, depth) => {
225
+ var sanitizeJsonValue = (input, depth, stats) => {
113
226
  if (input === null) return null;
114
227
  if (typeof input === "string") return input;
115
228
  if (typeof input === "boolean") return input;
116
229
  if (typeof input === "number") {
117
- return Number.isFinite(input) ? input : void 0;
230
+ if (!Number.isFinite(input)) {
231
+ stats.dropped += 1;
232
+ stats.nonSerializable += 1;
233
+ stats.nonFiniteNumber += 1;
234
+ return void 0;
235
+ }
236
+ return input;
237
+ }
238
+ if (depth >= 6) {
239
+ stats.dropped += 1;
240
+ stats.depthExceeded += 1;
241
+ return void 0;
118
242
  }
119
- if (depth >= 6) return void 0;
120
243
  if (Array.isArray(input)) {
121
244
  const out = [];
122
245
  for (const item of input) {
123
- const v = sanitizeJsonValue(item, depth + 1);
246
+ const v = sanitizeJsonValue(item, depth + 1, stats);
124
247
  if (v !== void 0) out.push(v);
125
248
  }
126
249
  return out;
@@ -129,18 +252,50 @@ var sanitizeJsonValue = (input, depth) => {
129
252
  const keys = Object.keys(input).sort();
130
253
  const out = {};
131
254
  for (const key of keys) {
132
- const v = sanitizeJsonValue(input[key], depth + 1);
255
+ const v = sanitizeJsonValue(input[key], depth + 1, stats);
133
256
  if (v !== void 0) out[key] = v;
134
257
  }
135
258
  return out;
136
259
  }
260
+ stats.dropped += 1;
261
+ stats.nonSerializable += 1;
137
262
  return void 0;
138
263
  };
139
- var sanitize = (input) => {
140
- if (input === null || input === void 0) return void 0;
141
- if (typeof input !== "object" || Array.isArray(input)) return void 0;
264
+ var pushSample = (target, value, limit) => {
265
+ if (target.length >= limit) return;
266
+ target.push(value);
267
+ };
268
+ var sanitizeWithReport = (input) => {
269
+ if (input === null || input === void 0) return {};
270
+ if (typeof input !== "object" || Array.isArray(input)) {
271
+ return { report: { invalidInput: true } };
272
+ }
142
273
  const record2 = input;
143
274
  const out = {};
275
+ const reportUnknownKeys = [];
276
+ let unknownKeyCount = 0;
277
+ const reportDroppedKeys = [];
278
+ let droppedTagItems = 0;
279
+ const reportIgnoredAnnotationKeys = [];
280
+ let ignoredAnnotationKeyCount = 0;
281
+ const reportDroppedAnnotationKeys = [];
282
+ let droppedAnnotationKeyCount = 0;
283
+ const stats = { dropped: 0, nonSerializable: 0, depthExceeded: 0, nonFiniteNumber: 0 };
284
+ const allowed = /* @__PURE__ */ new Set([
285
+ "label",
286
+ "description",
287
+ "group",
288
+ "docsUrl",
289
+ "cacheGroup",
290
+ "canonical",
291
+ "tags",
292
+ "annotations"
293
+ ]);
294
+ for (const key of Object.keys(record2)) {
295
+ if (allowed.has(key) || key.startsWith("x-")) continue;
296
+ unknownKeyCount += 1;
297
+ pushSample(reportUnknownKeys, key, 8);
298
+ }
144
299
  const pickString = (key) => {
145
300
  const value = record2[key];
146
301
  if (typeof value !== "string") return;
@@ -154,7 +309,9 @@ var sanitize = (input) => {
154
309
  pickString("docsUrl");
155
310
  pickString("cacheGroup");
156
311
  const canonical = record2.canonical;
157
- if (typeof canonical === "boolean") {
312
+ if (canonical !== void 0 && canonical !== null && typeof canonical !== "boolean") {
313
+ pushSample(reportDroppedKeys, "canonical", 8);
314
+ } else if (typeof canonical === "boolean") {
158
315
  out.canonical = canonical;
159
316
  }
160
317
  const tagsRaw = record2.tags;
@@ -162,26 +319,80 @@ var sanitize = (input) => {
162
319
  const tags = uniqSortedStrings([tagsRaw]);
163
320
  if (tags.length > 0) out.tags = tags;
164
321
  } else if (Array.isArray(tagsRaw)) {
165
- const tags = uniqSortedStrings(tagsRaw.filter((x) => typeof x === "string"));
322
+ const raw = tagsRaw.filter((x) => typeof x === "string");
323
+ droppedTagItems += tagsRaw.length - raw.length;
324
+ const tags = uniqSortedStrings(raw);
166
325
  if (tags.length > 0) out.tags = tags;
326
+ droppedTagItems += raw.length - tags.length;
327
+ } else if (tagsRaw !== void 0 && tagsRaw !== null) {
328
+ pushSample(reportDroppedKeys, "tags", 8);
167
329
  }
168
330
  const annotations = {};
169
- const annotationKeys = Object.keys(record2).filter((k) => k.startsWith("x-")).sort((a, b) => a.localeCompare(b));
331
+ const annotationKeys = Object.keys(record2).filter((k) => k.startsWith("x-")).sort();
170
332
  for (const key of annotationKeys) {
171
- const v = sanitizeJsonValue(record2[key], 0);
172
- if (v !== void 0) annotations[key] = v;
333
+ const v = sanitizeJsonValue(record2[key], 0, stats);
334
+ if (v !== void 0) {
335
+ annotations[key] = v;
336
+ } else {
337
+ droppedAnnotationKeyCount += 1;
338
+ pushSample(reportDroppedAnnotationKeys, key, 8);
339
+ }
173
340
  }
174
341
  const annotationsRaw = record2.annotations;
175
- if (isPlainRecord(annotationsRaw)) {
176
- const keys = Object.keys(annotationsRaw).filter((k) => k.startsWith("x-")).sort((a, b) => a.localeCompare(b));
342
+ if (annotationsRaw !== void 0 && annotationsRaw !== null && !isPlainRecord(annotationsRaw)) {
343
+ pushSample(reportDroppedKeys, "annotations", 8);
344
+ } else if (isPlainRecord(annotationsRaw)) {
345
+ const keys = Object.keys(annotationsRaw).sort();
177
346
  for (const key of keys) {
178
- const v = sanitizeJsonValue(annotationsRaw[key], 0);
179
- if (v !== void 0) annotations[key] = v;
347
+ if (!key.startsWith("x-")) {
348
+ ignoredAnnotationKeyCount += 1;
349
+ pushSample(reportIgnoredAnnotationKeys, key, 8);
350
+ continue;
351
+ }
352
+ const v = sanitizeJsonValue(annotationsRaw[key], 0, stats);
353
+ if (v !== void 0) {
354
+ annotations[key] = v;
355
+ } else {
356
+ droppedAnnotationKeyCount += 1;
357
+ pushSample(reportDroppedAnnotationKeys, key, 8);
358
+ }
180
359
  }
181
360
  }
182
361
  if (Object.keys(annotations).length > 0) out.annotations = annotations;
183
- return Object.keys(out).length > 0 ? out : void 0;
362
+ for (const key of ["label", "description", "group", "docsUrl", "cacheGroup"]) {
363
+ const value = record2[key];
364
+ if (value !== void 0 && value !== null && typeof value !== "string") {
365
+ pushSample(reportDroppedKeys, key, 8);
366
+ }
367
+ }
368
+ const meta = Object.keys(out).length > 0 ? out : void 0;
369
+ const report = (() => {
370
+ const hasUnknownKeys = unknownKeyCount > 0;
371
+ const hasDroppedKeys = reportDroppedKeys.length > 0;
372
+ const hasDroppedTagItems = droppedTagItems > 0;
373
+ const hasIgnoredAnnotationKeys = ignoredAnnotationKeyCount > 0;
374
+ const hasDroppedAnnotations = droppedAnnotationKeyCount > 0 || stats.dropped > 0;
375
+ if (!hasUnknownKeys && !hasDroppedKeys && !hasDroppedTagItems && !hasIgnoredAnnotationKeys && !hasDroppedAnnotations) {
376
+ return void 0;
377
+ }
378
+ return {
379
+ ...hasUnknownKeys ? { unknownKeys: reportUnknownKeys, unknownKeyCount } : {},
380
+ ...hasDroppedKeys ? { droppedKeys: uniqSortedStrings(reportDroppedKeys) } : {},
381
+ ...hasDroppedTagItems ? { droppedTagItems } : {},
382
+ ...hasIgnoredAnnotationKeys ? { ignoredAnnotationKeys: uniqSortedStrings(reportIgnoredAnnotationKeys), ignoredAnnotationKeyCount } : {},
383
+ ...hasDroppedAnnotations ? {
384
+ droppedAnnotationKeys: uniqSortedStrings(reportDroppedAnnotationKeys),
385
+ droppedAnnotationKeyCount,
386
+ droppedAnnotationValues: stats.dropped,
387
+ droppedAnnotationNonSerializable: stats.nonSerializable,
388
+ droppedAnnotationDepthExceeded: stats.depthExceeded,
389
+ droppedAnnotationNonFiniteNumber: stats.nonFiniteNumber
390
+ } : {}
391
+ };
392
+ })();
393
+ return report ? { meta, report } : { meta };
184
394
  };
395
+ var sanitize = (input) => sanitizeWithReport(input).meta;
185
396
  var stableStringify = (meta) => {
186
397
  const out = {};
187
398
  const keys = Object.keys(meta).sort();
@@ -271,6 +482,14 @@ var normalizeSpec = (spec) => {
271
482
  meta: { ...meta, deps, _fieldPath: fieldPath }
272
483
  };
273
484
  }
485
+ if (entry.kind === "externalStore") {
486
+ const meta = entry.meta;
487
+ return {
488
+ ...entry,
489
+ fieldPath,
490
+ meta: { ...meta, _fieldPath: fieldPath }
491
+ };
492
+ }
274
493
  if (entry.kind === "link") {
275
494
  const meta = entry.meta;
276
495
  const from2 = prefixDeps([meta.from], depPrefix)[0] ?? meta.from;
@@ -308,6 +527,7 @@ var normalizeSpec = (spec) => {
308
527
  expandMaybeRecord(node2.computed);
309
528
  expandMaybeRecord(node2.source);
310
529
  expandMaybeRecord(node2.link);
530
+ expandMaybeRecord(node2.externalStore);
311
531
  if (node2.check) {
312
532
  const rules = {};
313
533
  const checkDepsPrefix = options?.checkDepsPrefix ?? (joinPrefix.endsWith("[]") ? joinPrefix : "");
@@ -398,118 +618,6 @@ var collectNodeMeta = (spec) => {
398
618
  return out;
399
619
  };
400
620
 
401
- // src/internal/field-path.ts
402
- var isFieldPathSegment = (seg) => {
403
- if (!seg) return false;
404
- if (seg === "*") return false;
405
- if (/^\d+$/.test(seg)) return false;
406
- if (seg.includes("[") || seg.includes("]")) return false;
407
- return true;
408
- };
409
- var normalizeFieldPath = (input) => {
410
- if (typeof input === "string") {
411
- const segs = splitSegments(input);
412
- if (!segs || segs.length === 0) return void 0;
413
- const normalized2 = segs.filter(isFieldPathSegment);
414
- return normalized2.length > 0 ? normalized2 : void 0;
415
- }
416
- if (input.length === 0) return void 0;
417
- let needsFilter = false;
418
- for (const seg of input) {
419
- if (!isFieldPathSegment(seg)) {
420
- needsFilter = true;
421
- break;
422
- }
423
- }
424
- if (!needsFilter) return input;
425
- const normalized = input.filter(isFieldPathSegment);
426
- return normalized.length > 0 ? normalized : void 0;
427
- };
428
- var compareFieldPath = (a, b) => {
429
- const len = Math.min(a.length, b.length);
430
- for (let i = 0; i < len; i++) {
431
- const as = a[i];
432
- const bs = b[i];
433
- if (as === bs) continue;
434
- return as < bs ? -1 : 1;
435
- }
436
- return a.length - b.length;
437
- };
438
- var makeFieldPathIdRegistry = (fieldPaths) => {
439
- const root = { children: /* @__PURE__ */ new Map() };
440
- const pathStringToId = /* @__PURE__ */ new Map();
441
- const ambiguousPathStrings = /* @__PURE__ */ new Set();
442
- for (let id = 0; id < fieldPaths.length; id++) {
443
- const path = fieldPaths[id];
444
- let node2 = root;
445
- for (const seg of path) {
446
- const children = node2.children;
447
- let next = children.get(seg);
448
- if (!next) {
449
- next = { children: /* @__PURE__ */ new Map() };
450
- children.set(seg, next);
451
- }
452
- node2 = next;
453
- }
454
- node2.id = id;
455
- if (path.length > 0 && path.some((seg) => seg.includes("."))) {
456
- const key = path.join(".");
457
- ambiguousPathStrings.add(key);
458
- pathStringToId.delete(key);
459
- }
460
- if (path.length > 0 && path.every((seg) => !seg.includes(".") && !seg.includes("[") && !seg.includes("]"))) {
461
- const key = path.join(".");
462
- if (ambiguousPathStrings.has(key)) continue;
463
- if (pathStringToId.has(key)) {
464
- ambiguousPathStrings.add(key);
465
- pathStringToId.delete(key);
466
- continue;
467
- }
468
- pathStringToId.set(key, id);
469
- }
470
- }
471
- return { fieldPaths, root, pathStringToId };
472
- };
473
- var getFieldPathId = (registry, path) => {
474
- let node2 = registry.root;
475
- for (const seg of path) {
476
- const next = node2.children.get(seg);
477
- if (!next) return void 0;
478
- node2 = next;
479
- }
480
- return node2.id;
481
- };
482
- var splitSegments = (path) => {
483
- if (!path) return void 0;
484
- if (path === "*") return void 0;
485
- const parts = path.split(".").filter((p) => p.length > 0);
486
- const segs = [];
487
- for (const part of parts) {
488
- if (!part) continue;
489
- if (part === "*") {
490
- return void 0;
491
- }
492
- if (part.endsWith("[]")) {
493
- const base = part.slice(0, -2);
494
- if (base) segs.push(base);
495
- continue;
496
- }
497
- const bracket = /^(.+)\[(\d+)\]$/.exec(part);
498
- if (bracket) {
499
- segs.push(bracket[1]);
500
- continue;
501
- }
502
- if (/^\d+$/.test(part)) {
503
- continue;
504
- }
505
- if (part.includes("[") || part.includes("]")) {
506
- return void 0;
507
- }
508
- segs.push(part);
509
- }
510
- return segs;
511
- };
512
-
513
621
  // src/internal/digest.ts
514
622
  var stableStringify2 = (value) => {
515
623
  if (value === null) return "null";
@@ -522,7 +630,7 @@ var stableStringify2 = (value) => {
522
630
  }
523
631
  if (t === "object") {
524
632
  const record2 = value;
525
- const keys = Object.keys(record2).sort((a, b) => a.localeCompare(b));
633
+ const keys = Object.keys(record2).sort();
526
634
  return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify2(record2[k])}`).join(",")}}`;
527
635
  }
528
636
  return "null";
@@ -536,10 +644,47 @@ var fnv1a32 = (input) => {
536
644
  return hash.toString(16).padStart(8, "0");
537
645
  };
538
646
 
647
+ // src/internal/state-trait/converge-ir.ts
648
+ var getConvergeStaticIrDigest = (ir) => {
649
+ if (typeof ir.staticIrDigest === "string" && ir.staticIrDigest.length > 0) {
650
+ return ir.staticIrDigest;
651
+ }
652
+ const hash = fnv1a32(
653
+ stableStringify2({ writersKey: ir.writersKey, depsKey: ir.depsKey, fieldPathsKey: ir.fieldPathsKey })
654
+ );
655
+ return `converge_ir_v2:${hash}`;
656
+ };
657
+
539
658
  // src/internal/state-trait/build.ts
540
659
  var nowPerf = () => typeof globalThis.performance !== "undefined" && typeof globalThis.performance.now === "function" ? globalThis.performance.now() : Date.now();
541
- var getConvergeWriterDeps = (entry) => {
542
- if (entry.kind === "computed") {
660
+ var collectMultipleWritersError = (entries) => {
661
+ const kindsByFieldPath = /* @__PURE__ */ new Map();
662
+ for (const entry of entries) {
663
+ if (entry.kind !== "computed" && entry.kind !== "link" && entry.kind !== "source" && entry.kind !== "externalStore") {
664
+ continue;
665
+ }
666
+ const set = kindsByFieldPath.get(entry.fieldPath) ?? /* @__PURE__ */ new Set();
667
+ set.add(entry.kind);
668
+ kindsByFieldPath.set(entry.fieldPath, set);
669
+ }
670
+ const conflicts = [];
671
+ for (const [fieldPath, kinds] of kindsByFieldPath.entries()) {
672
+ if (kinds.size <= 1) continue;
673
+ conflicts.push({ fieldPath, kinds: Array.from(kinds).sort() });
674
+ }
675
+ if (conflicts.length === 0) return void 0;
676
+ conflicts.sort((a, b) => a.fieldPath < b.fieldPath ? -1 : a.fieldPath > b.fieldPath ? 1 : 0);
677
+ const fields = conflicts.map((c) => c.fieldPath);
678
+ const primary = conflicts[0];
679
+ const kindSummary = primary.kinds.join(" + ");
680
+ return {
681
+ code: "MULTIPLE_WRITERS",
682
+ message: `[StateTrait.build] Multiple writers for field "${primary.fieldPath}" (${kindSummary}). Only one of computed/link/source/externalStore can write a fieldPath.`,
683
+ fields
684
+ };
685
+ };
686
+ var getConvergeWriterDeps = (entry) => {
687
+ if (entry.kind === "computed") {
543
688
  return entry.meta?.deps ?? [];
544
689
  }
545
690
  return [entry.meta.from];
@@ -615,24 +760,11 @@ var collectSchemaFieldPaths = (schema) => {
615
760
  byKey.set(JSON.stringify(normalized), normalized);
616
761
  };
617
762
  const visit = (ast, prefix, seen) => {
618
- let current = ast;
619
- while (true) {
620
- if (SchemaAST.isSuspend(current)) {
621
- if (seen.has(current)) return;
622
- seen.add(current);
623
- current = current.f();
624
- continue;
625
- }
626
- if (SchemaAST.isRefinement(current)) {
627
- current = current.from;
628
- continue;
629
- }
630
- break;
631
- }
632
- if (SchemaAST.isTransformation(current)) {
633
- visit(current.to, prefix, seen);
634
- visit(current.from, prefix, seen);
635
- return;
763
+ let current = SchemaAST.toType(ast);
764
+ while (SchemaAST.isSuspend(current)) {
765
+ if (seen.has(current)) return;
766
+ seen.add(current);
767
+ current = SchemaAST.toType(current.thunk());
636
768
  }
637
769
  if (SchemaAST.isUnion(current)) {
638
770
  for (const t of current.types) {
@@ -640,16 +772,16 @@ var collectSchemaFieldPaths = (schema) => {
640
772
  }
641
773
  return;
642
774
  }
643
- if (SchemaAST.isTupleType(current)) {
775
+ if (SchemaAST.isArrays(current)) {
644
776
  for (const e of current.elements) {
645
- visit(e.type, prefix, seen);
777
+ visit(e, prefix, seen);
646
778
  }
647
779
  for (const r of current.rest) {
648
- visit(r.type, prefix, seen);
780
+ visit(r, prefix, seen);
649
781
  }
650
782
  return;
651
783
  }
652
- if (SchemaAST.isTypeLiteral(current)) {
784
+ if (SchemaAST.isObjects(current)) {
653
785
  for (const ps of current.propertySignatures) {
654
786
  const seg = String(ps.name);
655
787
  if (!seg) continue;
@@ -666,6 +798,7 @@ var collectSchemaFieldPaths = (schema) => {
666
798
  var buildConvergeIr = (stateSchema, entries) => {
667
799
  const startedAt = nowPerf();
668
800
  const generation = 0;
801
+ const multipleWritersError = collectMultipleWritersError(entries);
669
802
  const writers = entries.filter((e) => e.kind === "computed" || e.kind === "link");
670
803
  const writersKey = writers.map((entry) => `${entry.kind}:${entry.fieldPath}`).sort().join("|");
671
804
  const depsKey = writers.map((entry) => {
@@ -677,7 +810,7 @@ var buildConvergeIr = (stateSchema, entries) => {
677
810
  for (const entry of writers) {
678
811
  writerByPath.set(entry.fieldPath, entry);
679
812
  }
680
- const topo = writers.length > 0 ? computeConvergeTopoOrder(writers) : { order: [] };
813
+ const topo = multipleWritersError ? { order: [] } : writers.length > 0 ? computeConvergeTopoOrder(writers) : { order: [] };
681
814
  const stepsById = topo.configError ? [] : topo.order.map((path) => writerByPath.get(path));
682
815
  const fieldPathTable = /* @__PURE__ */ new Map();
683
816
  const addPath = (path) => {
@@ -701,6 +834,11 @@ var buildConvergeIr = (stateSchema, entries) => {
701
834
  const fieldPaths = Array.from(fieldPathTable.values()).sort(compareFieldPath);
702
835
  const fieldPathIdRegistry = makeFieldPathIdRegistry(fieldPaths);
703
836
  const fieldPathsKey = fnv1a32(stableStringify2(fieldPaths));
837
+ const staticIrDigest = getConvergeStaticIrDigest({
838
+ writersKey,
839
+ depsKey,
840
+ fieldPathsKey
841
+ });
704
842
  const stepOutFieldPathIdByStepId = [];
705
843
  const stepDepsFieldPathIdsByStepId = [];
706
844
  const stepSchedulingByStepId = [];
@@ -728,9 +866,10 @@ var buildConvergeIr = (stateSchema, entries) => {
728
866
  writersKey,
729
867
  depsKey,
730
868
  fieldPathsKey,
869
+ staticIrDigest,
731
870
  fieldPaths,
732
871
  fieldPathIdRegistry,
733
- ...topo.configError ? { configError: topo.configError } : null,
872
+ ...multipleWritersError ? { configError: multipleWritersError } : topo.configError ? { configError: topo.configError } : null,
734
873
  stepsById,
735
874
  stepOutFieldPathIdByStepId,
736
875
  stepDepsFieldPathIdsByStepId,
@@ -886,6 +1025,12 @@ var buildGraph = (entries, nodeMetaByFieldPath) => {
886
1025
  });
887
1026
  }
888
1027
  }
1028
+ } else if (entry.kind === "externalStore") {
1029
+ planSteps.push({
1030
+ id: `external-store:${fieldPath}`,
1031
+ kind: "external-store-sync",
1032
+ targetFieldPath: fieldPath
1033
+ });
889
1034
  } else if (entry.kind === "check") {
890
1035
  planSteps.push({
891
1036
  id: `check:${fieldPath}`,
@@ -1026,7 +1171,7 @@ var collectSchemaPaths = (entries) => {
1026
1171
  }
1027
1172
  }
1028
1173
  }
1029
- return Array.from(byKey.entries()).sort((a, b) => a[0].localeCompare(b[0])).map(([, v]) => v);
1174
+ return Array.from(byKey.entries()).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0).map(([, v]) => v);
1030
1175
  };
1031
1176
  var build = (stateSchema, spec) => {
1032
1177
  const entries = normalizeSpec(spec);
@@ -1079,70 +1224,397 @@ var build = (stateSchema, spec) => {
1079
1224
  };
1080
1225
 
1081
1226
  // src/internal/state-trait/install.ts
1082
- var import_effect11 = require("effect");
1227
+ var import_effect18 = require("effect");
1083
1228
 
1084
1229
  // src/internal/runtime/core/env.ts
1085
- var import_effect = require("effect");
1086
- var getNodeEnv = () => {
1230
+ var import_effect9 = require("effect");
1231
+
1232
+ // src/internal/runtime/core/HostScheduler.ts
1233
+ var noopCancel = () => {
1234
+ };
1235
+ var safeNowMs = () => {
1236
+ const perf = globalThis.performance;
1237
+ if (perf && typeof perf.now === "function") {
1238
+ try {
1239
+ const v = perf.now();
1240
+ if (typeof v === "number" && Number.isFinite(v)) return v;
1241
+ } catch {
1242
+ }
1243
+ }
1244
+ return Date.now();
1245
+ };
1246
+ var safeQueueMicrotask = (cb) => {
1247
+ const qm = globalThis.queueMicrotask;
1248
+ if (typeof qm === "function") {
1249
+ try {
1250
+ qm(cb);
1251
+ return;
1252
+ } catch {
1253
+ }
1254
+ }
1087
1255
  try {
1088
- const env = globalThis?.process?.env;
1089
- return typeof env?.NODE_ENV === "string" ? env.NODE_ENV : void 0;
1256
+ Promise.resolve().then(cb);
1090
1257
  } catch {
1091
- return void 0;
1258
+ setTimeout(cb, 0);
1092
1259
  }
1093
1260
  };
1094
- var isDevEnv = () => getNodeEnv() !== "production";
1095
- var StateTransactionConfigTagImpl = class extends import_effect.Context.Tag("@logixjs/core/StateTransactionRuntimeConfig")() {
1261
+ var safeSetTimeout = (ms, cb) => {
1262
+ const id = setTimeout(cb, ms);
1263
+ return () => {
1264
+ try {
1265
+ clearTimeout(id);
1266
+ } catch {
1267
+ }
1268
+ };
1096
1269
  };
1097
- var ReadQueryStrictGateConfigTagImpl = class extends import_effect.Context.Tag("@logixjs/core/ReadQueryStrictGateRuntimeConfig")() {
1270
+ var makeMessageChannelMacrotask = () => {
1271
+ const MC = globalThis.MessageChannel;
1272
+ if (typeof MC !== "function") return void 0;
1273
+ let channel;
1274
+ try {
1275
+ channel = new MC();
1276
+ } catch {
1277
+ return void 0;
1278
+ }
1279
+ const queue = [];
1280
+ let scheduled = false;
1281
+ const flush = () => {
1282
+ scheduled = false;
1283
+ const tasks = queue.splice(0, queue.length);
1284
+ for (const t of tasks) {
1285
+ if (t.canceled) continue;
1286
+ try {
1287
+ t.cb();
1288
+ } catch {
1289
+ }
1290
+ }
1291
+ };
1292
+ try {
1293
+ channel.port1.onmessage = flush;
1294
+ } catch {
1295
+ return void 0;
1296
+ }
1297
+ const schedule = (cb) => {
1298
+ const task = { canceled: false, cb };
1299
+ queue.push(task);
1300
+ if (!scheduled) {
1301
+ scheduled = true;
1302
+ try {
1303
+ channel.port2.postMessage(void 0);
1304
+ } catch {
1305
+ scheduled = false;
1306
+ return safeSetTimeout(0, cb);
1307
+ }
1308
+ }
1309
+ return () => {
1310
+ task.canceled = true;
1311
+ };
1312
+ };
1313
+ return schedule;
1098
1314
  };
1099
- var ReplayModeConfigTagImpl = class extends import_effect.Context.Tag("@logixjs/core/ReplayModeConfig")() {
1315
+ var makeSetImmediateMacrotask = () => {
1316
+ const si = globalThis.setImmediate;
1317
+ const ci = globalThis.clearImmediate;
1318
+ if (typeof si !== "function") return void 0;
1319
+ return (cb) => {
1320
+ let id;
1321
+ try {
1322
+ id = si(cb);
1323
+ } catch {
1324
+ return safeSetTimeout(0, cb);
1325
+ }
1326
+ return () => {
1327
+ if (typeof ci !== "function") return;
1328
+ try {
1329
+ ci(id);
1330
+ } catch {
1331
+ }
1332
+ };
1333
+ };
1100
1334
  };
1101
- var ReplayModeConfigTag = ReplayModeConfigTagImpl;
1102
- var StateTransactionOverridesTagImpl = class extends import_effect.Context.Tag("@logixjs/core/StateTransactionOverrides")() {
1335
+ var makeRaf = () => {
1336
+ const raf = globalThis.requestAnimationFrame;
1337
+ const cancel = globalThis.cancelAnimationFrame;
1338
+ if (typeof raf !== "function") return void 0;
1339
+ return (cb) => {
1340
+ let id;
1341
+ try {
1342
+ id = raf(cb);
1343
+ } catch {
1344
+ return noopCancel;
1345
+ }
1346
+ return () => {
1347
+ if (typeof cancel !== "function") return;
1348
+ try {
1349
+ cancel(id);
1350
+ } catch {
1351
+ }
1352
+ };
1353
+ };
1103
1354
  };
1104
- var ConcurrencyPolicyTagImpl = class extends import_effect.Context.Tag("@logixjs/core/ConcurrencyPolicy")() {
1355
+ var makeDefaultHostScheduler = () => {
1356
+ const macrotask = makeSetImmediateMacrotask() ?? makeMessageChannelMacrotask() ?? ((cb) => safeSetTimeout(0, cb));
1357
+ const raf = makeRaf();
1358
+ return {
1359
+ nowMs: safeNowMs,
1360
+ scheduleMicrotask: safeQueueMicrotask,
1361
+ scheduleMacrotask: macrotask,
1362
+ scheduleAnimationFrame: (cb) => raf?.(cb) ?? macrotask(cb),
1363
+ scheduleTimeout: safeSetTimeout
1364
+ };
1105
1365
  };
1106
- var ConcurrencyPolicyOverridesTagImpl = class extends import_effect.Context.Tag("@logixjs/core/ConcurrencyPolicyOverrides")() {
1366
+ var globalHostScheduler;
1367
+ var getGlobalHostScheduler = () => {
1368
+ globalHostScheduler ?? (globalHostScheduler = makeDefaultHostScheduler());
1369
+ return globalHostScheduler;
1107
1370
  };
1108
1371
 
1109
- // src/internal/runtime/core/runtimeInternalsAccessor.ts
1110
- var BOUND_INTERNALS = /* @__PURE__ */ Symbol.for("@logixjs/core/boundInternals");
1111
- var getBoundInternals = (bound) => {
1112
- const internals = bound[BOUND_INTERNALS];
1113
- if (!internals) {
1114
- const msg = isDevEnv() ? [
1115
- "[MissingBoundInternals] Bound internals not installed on Bound API instance.",
1116
- "fix:",
1117
- "- Ensure BoundApiRuntime attaches internals (020 foundation).",
1118
- "- If you created a mock bound for tests, attach internals or avoid calling internal-only APIs."
1119
- ].join("\n") : "Bound internals not installed";
1120
- throw new Error(msg);
1372
+ // src/internal/runtime/core/RuntimeStore.ts
1373
+ var parseTopicKey = (topicKey) => {
1374
+ const idx = topicKey.indexOf("::");
1375
+ if (idx <= 0) return void 0;
1376
+ const moduleId = topicKey.slice(0, idx);
1377
+ const rest = topicKey.slice(idx + 2);
1378
+ if (rest.length === 0) return void 0;
1379
+ const idx2 = rest.indexOf("::");
1380
+ if (idx2 < 0) {
1381
+ return { kind: "module", moduleInstanceKey: `${moduleId}::${rest}` };
1121
1382
  }
1122
- return internals;
1383
+ const instanceId = rest.slice(0, idx2);
1384
+ const suffix = rest.slice(idx2 + 2);
1385
+ if (suffix.startsWith("rq:")) {
1386
+ const selectorId = suffix.slice("rq:".length);
1387
+ if (selectorId.length === 0) return void 0;
1388
+ return {
1389
+ kind: "readQuery",
1390
+ moduleInstanceKey: `${moduleId}::${instanceId}`,
1391
+ selectorId
1392
+ };
1393
+ }
1394
+ return { kind: "module", moduleInstanceKey: `${moduleId}::${instanceId}` };
1395
+ };
1396
+ var EMPTY_LISTENER_SNAPSHOT = [];
1397
+ var NO_CHANGED_TOPIC_LISTENERS = [];
1398
+ var makeRuntimeStore = () => {
1399
+ let tickSeq = 0;
1400
+ const moduleStates = /* @__PURE__ */ new Map();
1401
+ const topicVersions = /* @__PURE__ */ new Map();
1402
+ const topicPriorities = /* @__PURE__ */ new Map();
1403
+ const listenersByTopic = /* @__PURE__ */ new Map();
1404
+ const subscriberCountByModule = /* @__PURE__ */ new Map();
1405
+ const getTopicVersion = (topicKey) => topicVersions.get(topicKey) ?? 0;
1406
+ const getTopicPriority = (topicKey) => topicPriorities.get(topicKey) ?? "normal";
1407
+ const commitTopicBump = (topicKey, priority) => {
1408
+ const prev = topicVersions.get(topicKey) ?? 0;
1409
+ topicVersions.set(topicKey, prev + 1);
1410
+ topicPriorities.set(topicKey, priority);
1411
+ };
1412
+ const refreshTopicSnapshot = (state) => {
1413
+ state.snapshot = Array.from(state.listeners);
1414
+ };
1415
+ const subscribeTopic = (topicKey, listener) => {
1416
+ const info = parseTopicKey(topicKey);
1417
+ const existing = listenersByTopic.get(topicKey);
1418
+ const state = existing ?? { listeners: /* @__PURE__ */ new Set(), snapshot: EMPTY_LISTENER_SNAPSHOT };
1419
+ const alreadyHas = state.listeners.has(listener);
1420
+ if (!alreadyHas) {
1421
+ state.listeners.add(listener);
1422
+ refreshTopicSnapshot(state);
1423
+ }
1424
+ if (!existing) {
1425
+ listenersByTopic.set(topicKey, state);
1426
+ }
1427
+ if (!alreadyHas && info) {
1428
+ const prev = subscriberCountByModule.get(info.moduleInstanceKey) ?? 0;
1429
+ subscriberCountByModule.set(info.moduleInstanceKey, prev + 1);
1430
+ }
1431
+ return () => {
1432
+ const currentState = listenersByTopic.get(topicKey);
1433
+ if (!currentState) return;
1434
+ const deleted = currentState.listeners.delete(listener);
1435
+ if (deleted && info) {
1436
+ const prev = subscriberCountByModule.get(info.moduleInstanceKey) ?? 0;
1437
+ const next = prev - 1;
1438
+ if (next <= 0) {
1439
+ subscriberCountByModule.delete(info.moduleInstanceKey);
1440
+ } else {
1441
+ subscriberCountByModule.set(info.moduleInstanceKey, next);
1442
+ }
1443
+ }
1444
+ if (currentState.listeners.size === 0) {
1445
+ listenersByTopic.delete(topicKey);
1446
+ } else if (deleted) {
1447
+ refreshTopicSnapshot(currentState);
1448
+ }
1449
+ };
1450
+ };
1451
+ const getTopicSubscriberCount = (topicKey) => listenersByTopic.get(topicKey)?.listeners.size ?? 0;
1452
+ const getModuleSubscriberCount = (moduleInstanceKey) => subscriberCountByModule.get(moduleInstanceKey) ?? 0;
1453
+ const registerModuleInstance = (args) => {
1454
+ moduleStates.set(args.moduleInstanceKey, args.initialState);
1455
+ if (!topicVersions.has(args.moduleInstanceKey)) {
1456
+ topicVersions.set(args.moduleInstanceKey, 0);
1457
+ topicPriorities.set(args.moduleInstanceKey, "normal");
1458
+ }
1459
+ };
1460
+ const unregisterModuleInstance = (moduleInstanceKey) => {
1461
+ moduleStates.delete(moduleInstanceKey);
1462
+ };
1463
+ const commitTick = (args) => {
1464
+ tickSeq = args.tickSeq;
1465
+ for (const [key, commit] of args.accepted.modules) {
1466
+ moduleStates.set(key, commit.state);
1467
+ }
1468
+ if (args.accepted.dirtyTopics.size === 0) {
1469
+ return {
1470
+ changedTopicListeners: NO_CHANGED_TOPIC_LISTENERS
1471
+ };
1472
+ }
1473
+ if (args.onListener) {
1474
+ let firstTopicListeners;
1475
+ let secondTopicListeners;
1476
+ let restTopicListeners;
1477
+ for (const [topicKey, priority] of args.accepted.dirtyTopics) {
1478
+ commitTopicBump(topicKey, priority);
1479
+ const listeners = listenersByTopic.get(topicKey)?.snapshot ?? EMPTY_LISTENER_SNAPSHOT;
1480
+ if (listeners.length === 0) {
1481
+ continue;
1482
+ }
1483
+ if (!firstTopicListeners) {
1484
+ firstTopicListeners = listeners;
1485
+ continue;
1486
+ }
1487
+ if (!secondTopicListeners) {
1488
+ secondTopicListeners = listeners;
1489
+ continue;
1490
+ }
1491
+ if (!restTopicListeners) {
1492
+ restTopicListeners = [];
1493
+ }
1494
+ restTopicListeners.push(listeners);
1495
+ }
1496
+ if (firstTopicListeners) {
1497
+ for (const listener of firstTopicListeners) {
1498
+ try {
1499
+ args.onListener(listener);
1500
+ } catch {
1501
+ }
1502
+ }
1503
+ }
1504
+ if (secondTopicListeners) {
1505
+ for (const listener of secondTopicListeners) {
1506
+ try {
1507
+ args.onListener(listener);
1508
+ } catch {
1509
+ }
1510
+ }
1511
+ }
1512
+ if (restTopicListeners) {
1513
+ for (const listeners of restTopicListeners) {
1514
+ for (const listener of listeners) {
1515
+ try {
1516
+ args.onListener(listener);
1517
+ } catch {
1518
+ }
1519
+ }
1520
+ }
1521
+ }
1522
+ return {
1523
+ changedTopicListeners: NO_CHANGED_TOPIC_LISTENERS
1524
+ };
1525
+ }
1526
+ let singleTopicListeners;
1527
+ let flattenedTopicListeners;
1528
+ for (const [topicKey, priority] of args.accepted.dirtyTopics) {
1529
+ commitTopicBump(topicKey, priority);
1530
+ const listeners = listenersByTopic.get(topicKey)?.snapshot ?? EMPTY_LISTENER_SNAPSHOT;
1531
+ if (listeners.length === 0) {
1532
+ continue;
1533
+ }
1534
+ if (flattenedTopicListeners) {
1535
+ for (const listener of listeners) {
1536
+ flattenedTopicListeners.push(listener);
1537
+ }
1538
+ continue;
1539
+ }
1540
+ if (!singleTopicListeners) {
1541
+ singleTopicListeners = listeners;
1542
+ continue;
1543
+ }
1544
+ flattenedTopicListeners = Array.from(singleTopicListeners);
1545
+ for (const listener of listeners) {
1546
+ flattenedTopicListeners.push(listener);
1547
+ }
1548
+ }
1549
+ return {
1550
+ changedTopicListeners: flattenedTopicListeners ?? singleTopicListeners ?? NO_CHANGED_TOPIC_LISTENERS
1551
+ };
1552
+ };
1553
+ const getModuleState = (moduleInstanceKey) => moduleStates.get(moduleInstanceKey);
1554
+ const dispose = () => {
1555
+ moduleStates.clear();
1556
+ topicVersions.clear();
1557
+ topicPriorities.clear();
1558
+ listenersByTopic.clear();
1559
+ subscriberCountByModule.clear();
1560
+ };
1561
+ return {
1562
+ getTickSeq: () => tickSeq,
1563
+ getModuleState,
1564
+ getTopicVersion,
1565
+ getTopicPriority,
1566
+ subscribeTopic,
1567
+ getTopicSubscriberCount,
1568
+ getModuleSubscriberCount,
1569
+ registerModuleInstance,
1570
+ unregisterModuleInstance,
1571
+ commitTick,
1572
+ dispose
1573
+ };
1123
1574
  };
1124
1575
 
1125
- // src/internal/state-trait/source.ts
1126
- var import_effect10 = require("effect");
1127
- var import_mutative = require("mutative");
1576
+ // src/internal/runtime/core/TickScheduler.ts
1577
+ var import_effect7 = require("effect");
1128
1578
 
1129
- // src/internal/effect-op.ts
1130
- var import_effect4 = require("effect");
1579
+ // src/internal/runtime/core/DebugSink.record.ts
1580
+ var import_effect3 = require("effect");
1581
+
1582
+ // src/internal/observability/jsonValue.ts
1583
+ var defaultOptions = {
1584
+ maxDepth: 6,
1585
+ maxObjectKeys: 32,
1586
+ maxArrayLength: 32,
1587
+ maxStringLength: 256,
1588
+ maxJsonBytes: 4 * 1024,
1589
+ oversizedPreviewBytes: 256
1590
+ };
1591
+
1592
+ // src/internal/runtime/core/errorSummary.ts
1593
+ var import_effect = require("effect");
1131
1594
 
1132
1595
  // src/internal/runtime/core/EffectOpCore.ts
1133
1596
  var import_effect2 = require("effect");
1134
- var currentLinkId = import_effect2.FiberRef.unsafeMake(void 0);
1135
- var EffectOpMiddlewareTag = class extends import_effect2.Context.Tag("Logix/EffectOpMiddleware")() {
1597
+ var currentLinkId = import_effect2.ServiceMap.Reference("@logixjs/core/CurrentLinkId", {
1598
+ defaultValue: () => void 0
1599
+ });
1600
+ var composeMiddlewareCache = /* @__PURE__ */ new WeakMap();
1601
+ var EffectOpMiddlewareTag = class extends import_effect2.ServiceMap.Service()("Logix/EffectOpMiddleware") {
1136
1602
  };
1137
1603
  var composeMiddleware = (stack) => {
1138
- return (op) => stack.reduceRight(
1604
+ const cached = composeMiddlewareCache.get(stack);
1605
+ if (cached) {
1606
+ return cached;
1607
+ }
1608
+ const composed = (op) => stack.reduceRight(
1139
1609
  (eff, mw) => mw({ ...op, effect: eff }),
1140
1610
  op.effect
1141
1611
  );
1612
+ composeMiddlewareCache.set(stack, composed);
1613
+ return composed;
1142
1614
  };
1143
1615
  var runWithMiddleware = (op, stack) => {
1144
1616
  return import_effect2.Effect.gen(function* () {
1145
- const existing = yield* import_effect2.FiberRef.get(currentLinkId);
1617
+ const existing = yield* import_effect2.Effect.service(currentLinkId);
1146
1618
  const metaLinkId = op.meta?.linkId;
1147
1619
  const linkId = typeof metaLinkId === "string" && metaLinkId.length > 0 ? metaLinkId : existing ?? op.id;
1148
1620
  const nextOp = {
@@ -1153,156 +1625,51 @@ var runWithMiddleware = (op, stack) => {
1153
1625
  }
1154
1626
  };
1155
1627
  const program = stack.length ? composeMiddleware(stack)(nextOp) : nextOp.effect;
1156
- return yield* import_effect2.Effect.locally(currentLinkId, linkId)(program);
1628
+ return yield* import_effect2.Effect.provideService(program, currentLinkId, linkId);
1157
1629
  });
1158
1630
  };
1159
1631
 
1160
- // src/internal/observability/runSession.ts
1161
- var import_effect3 = require("effect");
1162
-
1163
- // src/internal/observability/jsonValue.ts
1164
- var defaultOptions = {
1165
- maxDepth: 6,
1166
- maxObjectKeys: 32,
1167
- maxArrayLength: 32,
1168
- maxStringLength: 256,
1169
- maxJsonBytes: 4 * 1024,
1170
- oversizedPreviewBytes: 256
1171
- };
1172
-
1173
- // src/internal/observability/runSession.ts
1174
- var RunSessionTagImpl = class extends import_effect3.Context.Tag("@logixjs/core/RunSession")() {
1175
- };
1176
- var RunSessionTag = RunSessionTagImpl;
1177
-
1178
- // src/internal/effect-op.ts
1179
- var nextGlobalOpSeq = 0;
1180
- var nextOpSeq = () => {
1181
- nextGlobalOpSeq += 1;
1182
- return nextGlobalOpSeq;
1183
- };
1184
- var makeId = (instanceId, opSeq) => instanceId ? `${instanceId}::o${opSeq}` : `o${opSeq}`;
1185
- var make = (params) => ({
1186
- ...params.id ? { id: params.id, meta: params.meta } : (() => {
1187
- const meta = params.meta ?? {};
1188
- const instanceId = meta.instanceId;
1189
- const opSeq = typeof meta.opSeq === "number" && Number.isFinite(meta.opSeq) ? Math.floor(meta.opSeq) : nextOpSeq();
1190
- return {
1191
- id: makeId(instanceId, opSeq),
1192
- meta: meta.opSeq === opSeq ? meta : { ...meta, opSeq }
1193
- };
1194
- })(),
1195
- kind: params.kind,
1196
- name: params.name,
1197
- payload: params.payload,
1198
- effect: params.effect
1632
+ // src/internal/runtime/core/DebugSink.record.ts
1633
+ var currentDebugSinks = import_effect3.ServiceMap.Reference("@logixjs/core/Debug.currentDebugSinks", {
1634
+ defaultValue: () => []
1199
1635
  });
1200
- var run = (op, stack) => runWithMiddleware(op, stack);
1201
-
1202
- // src/internal/resource.ts
1203
- var import_effect5 = require("effect");
1204
- var stableStringify3 = (value) => {
1205
- const seen = /* @__PURE__ */ new WeakSet();
1206
- const encode = (input) => {
1207
- if (input === null) return null;
1208
- if (typeof input === "string" || typeof input === "number" || typeof input === "boolean") {
1209
- return input;
1210
- }
1211
- if (typeof input === "bigint") return input.toString();
1212
- if (typeof input === "undefined") return "__undefined__";
1213
- if (typeof input === "symbol") return `__symbol__:${String(input)}`;
1214
- if (typeof input === "function") return "__function__";
1215
- if (Array.isArray(input)) {
1216
- return input.map((v) => encode(v));
1217
- }
1218
- if (input instanceof Date) {
1219
- return `__date__:${input.toISOString()}`;
1220
- }
1221
- if (input instanceof Error) {
1222
- return {
1223
- _tag: "Error",
1224
- name: input.name,
1225
- message: input.message
1226
- };
1227
- }
1228
- if (input && typeof input === "object") {
1229
- const obj = input;
1230
- if (seen.has(obj)) return "__cycle__";
1231
- seen.add(obj);
1232
- const record2 = input;
1233
- const keys = Object.keys(record2).sort();
1234
- const out = {};
1235
- for (const k of keys) {
1236
- out[k] = encode(record2[k]);
1237
- }
1238
- return out;
1239
- }
1240
- return String(input);
1241
- };
1242
- try {
1243
- return JSON.stringify(encode(value));
1244
- } catch {
1245
- return String(value);
1636
+ var currentRuntimeLabel = import_effect3.ServiceMap.Reference("@logixjs/core/Debug.currentRuntimeLabel", {
1637
+ defaultValue: () => void 0
1638
+ });
1639
+ var currentTxnId = import_effect3.ServiceMap.Reference("@logixjs/core/Debug.currentTxnId", {
1640
+ defaultValue: () => void 0
1641
+ });
1642
+ var currentOpSeq = import_effect3.ServiceMap.Reference("@logixjs/core/Debug.currentOpSeq", {
1643
+ defaultValue: () => void 0
1644
+ });
1645
+ var currentDiagnosticsLevel = import_effect3.ServiceMap.Reference("@logixjs/core/Debug.currentDiagnosticsLevel", {
1646
+ defaultValue: () => "off"
1647
+ });
1648
+ var currentDiagnosticsMaterialization = import_effect3.ServiceMap.Reference(
1649
+ "@logixjs/core/Debug.currentDiagnosticsMaterialization",
1650
+ {
1651
+ defaultValue: () => "eager"
1246
1652
  }
1247
- };
1248
- var keyHash = (key) => stableStringify3(key);
1249
- var Snapshot = {
1250
- idle: () => ({
1251
- status: "idle",
1252
- keyHash: void 0,
1253
- data: void 0,
1254
- error: void 0
1255
- }),
1256
- loading: (params) => ({
1257
- status: "loading",
1258
- keyHash: params.keyHash,
1259
- data: void 0,
1260
- error: void 0
1261
- }),
1262
- success: (params) => ({
1263
- status: "success",
1264
- keyHash: params.keyHash,
1265
- data: params.data,
1266
- error: void 0
1267
- }),
1268
- error: (params) => ({
1269
- status: "error",
1270
- keyHash: params.keyHash,
1271
- data: void 0,
1272
- error: params.error
1273
- })
1274
- };
1275
- var ResourceRegistryTag = class extends import_effect5.Context.Tag("@logixjs/core/ResourceRegistry")() {
1276
- };
1277
- var internal = {
1278
- ResourceRegistryTag
1279
- };
1280
-
1281
- // src/internal/runtime/core/DebugSink.ts
1282
- var import_effect7 = require("effect");
1283
-
1284
- // src/internal/runtime/core/errorSummary.ts
1285
- var import_effect6 = require("effect");
1286
-
1287
- // src/internal/runtime/core/DebugSink.ts
1288
- var currentDebugSinks = import_effect7.FiberRef.unsafeMake([]);
1289
- var currentRuntimeLabel = import_effect7.FiberRef.unsafeMake(void 0);
1290
- var currentTxnId = import_effect7.FiberRef.unsafeMake(void 0);
1291
- var currentOpSeq = import_effect7.FiberRef.unsafeMake(void 0);
1292
- var currentDiagnosticsLevel = import_effect7.FiberRef.unsafeMake("off");
1293
- var currentTraitConvergeDiagnosticsSampling = import_effect7.FiberRef.unsafeMake({
1294
- sampleEveryN: 32,
1295
- topK: 3
1653
+ );
1654
+ var currentTraceMode = import_effect3.ServiceMap.Reference("@logixjs/core/Debug.currentTraceMode", {
1655
+ defaultValue: () => "on"
1296
1656
  });
1657
+ var currentTraitConvergeDiagnosticsSampling = import_effect3.ServiceMap.Reference(
1658
+ "@logixjs/core/Debug.currentTraitConvergeDiagnosticsSampling",
1659
+ {
1660
+ defaultValue: () => ({
1661
+ sampleEveryN: 32,
1662
+ topK: 3
1663
+ })
1664
+ }
1665
+ );
1297
1666
  var browserLifecycleSeen = /* @__PURE__ */ new Set();
1298
1667
  var browserDiagnosticSeen = /* @__PURE__ */ new Set();
1299
1668
  var lifecycleErrorLog = (event) => {
1300
1669
  const moduleId = event.moduleId ?? "unknown";
1301
1670
  const causePretty = (() => {
1302
1671
  try {
1303
- return import_effect7.Cause.pretty(event.cause, {
1304
- renderErrorCause: true
1305
- });
1672
+ return import_effect3.Cause.pretty(event.cause);
1306
1673
  } catch {
1307
1674
  try {
1308
1675
  return JSON.stringify(event.cause, null, 2);
@@ -1313,8 +1680,8 @@ var lifecycleErrorLog = (event) => {
1313
1680
  })();
1314
1681
  const message = `[Logix][module=${moduleId}] lifecycle:error
1315
1682
  ${causePretty}`;
1316
- return import_effect7.Effect.logError(message).pipe(
1317
- import_effect7.Effect.annotateLogs({
1683
+ return import_effect3.Effect.logError(message).pipe(
1684
+ import_effect3.Effect.annotateLogs({
1318
1685
  "logix.moduleId": moduleId,
1319
1686
  "logix.event": "lifecycle:error",
1320
1687
  "logix.cause": causePretty
@@ -1328,7 +1695,7 @@ var diagnosticLog = (event) => {
1328
1695
  hint: ${event.hint}` : ""}`;
1329
1696
  const msg = `${header}
1330
1697
  ${detail}`;
1331
- const base = event.severity === "warning" ? import_effect7.Effect.logWarning(msg) : event.severity === "info" ? import_effect7.Effect.logInfo(msg) : import_effect7.Effect.logError(msg);
1698
+ const base = event.severity === "warning" ? import_effect3.Effect.logWarning(msg) : event.severity === "info" ? import_effect3.Effect.logInfo(msg) : import_effect3.Effect.logError(msg);
1332
1699
  const annotations = {
1333
1700
  "logix.moduleId": moduleId,
1334
1701
  "logix.event": `diagnostic(${event.severity})`,
@@ -1341,24 +1708,24 @@ ${detail}`;
1341
1708
  if (event.actionTag) {
1342
1709
  annotations["logix.diagnostic.actionTag"] = event.actionTag;
1343
1710
  }
1344
- return base.pipe(import_effect7.Effect.annotateLogs(annotations));
1711
+ return base.pipe(import_effect3.Effect.annotateLogs(annotations));
1345
1712
  };
1346
- var noopLayer = import_effect7.Layer.locallyScoped(currentDebugSinks, []);
1713
+ var noopLayer = import_effect3.Layer.succeed(currentDebugSinks, []);
1347
1714
  var errorOnlySink = {
1348
- record: (event) => event.type === "lifecycle:error" ? lifecycleErrorLog(event) : event.type === "diagnostic" && event.severity !== "info" ? diagnosticLog(event) : import_effect7.Effect.void
1715
+ record: (event) => event.type === "lifecycle:error" ? lifecycleErrorLog(event) : event.type === "diagnostic" && event.severity !== "info" ? diagnosticLog(event) : import_effect3.Effect.void
1349
1716
  };
1350
- var errorOnlyLayer = import_effect7.Layer.locallyScoped(currentDebugSinks, [errorOnlySink]);
1717
+ var errorOnlyLayer = import_effect3.Layer.succeed(currentDebugSinks, [errorOnlySink]);
1351
1718
  var isErrorOnlyOnlySinks = (sinks) => sinks.length === 1 && sinks[0] === errorOnlySink;
1352
1719
  var consoleSink = {
1353
- record: (event) => event.type === "lifecycle:error" ? lifecycleErrorLog(event) : event.type === "diagnostic" ? diagnosticLog(event) : import_effect7.Effect.logDebug({ debugEvent: event })
1720
+ record: (event) => event.type === "lifecycle:error" ? lifecycleErrorLog(event) : event.type === "diagnostic" ? diagnosticLog(event) : import_effect3.Effect.logDebug({ debugEvent: event })
1354
1721
  };
1355
- var consoleLayer = import_effect7.Layer.locallyScoped(currentDebugSinks, [consoleSink]);
1722
+ var consoleLayer = import_effect3.Layer.succeed(currentDebugSinks, [consoleSink]);
1356
1723
  var isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
1357
1724
  var renderBrowserConsoleEvent = (event) => {
1358
1725
  if (typeof event.type === "string" && event.type.startsWith("trace:")) {
1359
1726
  const moduleId = event.moduleId ?? "unknown";
1360
1727
  const type = event.type;
1361
- return import_effect7.Effect.sync(() => {
1728
+ return import_effect3.Effect.sync(() => {
1362
1729
  console.groupCollapsed(
1363
1730
  "%c[Logix]%c trace %c" + moduleId + "%c " + String(type),
1364
1731
  "color:#6b7280;font-weight:bold",
@@ -1378,7 +1745,7 @@ var renderBrowserConsoleEvent = (event) => {
1378
1745
  const moduleId = event.moduleId ?? "unknown";
1379
1746
  const causePretty = (() => {
1380
1747
  try {
1381
- return import_effect7.Cause.pretty(event.cause, { renderErrorCause: true });
1748
+ return import_effect3.Cause.pretty(event.cause);
1382
1749
  } catch {
1383
1750
  try {
1384
1751
  return JSON.stringify(event.cause, null, 2);
@@ -1389,10 +1756,10 @@ var renderBrowserConsoleEvent = (event) => {
1389
1756
  })();
1390
1757
  const key = `${moduleId}|${causePretty}`;
1391
1758
  if (browserLifecycleSeen.has(key)) {
1392
- return import_effect7.Effect.void;
1759
+ return import_effect3.Effect.void;
1393
1760
  }
1394
1761
  browserLifecycleSeen.add(key);
1395
- return import_effect7.Effect.sync(() => {
1762
+ return import_effect3.Effect.sync(() => {
1396
1763
  console.groupCollapsed(
1397
1764
  "%c[Logix]%c lifecycle:error %c" + moduleId,
1398
1765
  "color:#ef4444;font-weight:bold",
@@ -1414,10 +1781,10 @@ hint: ${event.hint}` : ""}`;
1414
1781
  const label = event.severity === "warning" ? "diagnostic(warning)" : event.severity === "info" ? "diagnostic(info)" : "diagnostic(error)";
1415
1782
  const key = `${moduleId}|${event.code}|${event.message}`;
1416
1783
  if (browserDiagnosticSeen.has(key)) {
1417
- return import_effect7.Effect.void;
1784
+ return import_effect3.Effect.void;
1418
1785
  }
1419
1786
  browserDiagnosticSeen.add(key);
1420
- return import_effect7.Effect.sync(() => {
1787
+ return import_effect3.Effect.sync(() => {
1421
1788
  console.groupCollapsed(
1422
1789
  "%c[Logix]%c " + label + "%c module=" + moduleId,
1423
1790
  "color:#6b7280;font-weight:bold",
@@ -1434,55 +1801,52 @@ hint: ${event.hint}` : ""}`;
1434
1801
  console.groupEnd();
1435
1802
  });
1436
1803
  }
1437
- return import_effect7.Effect.void;
1804
+ return import_effect3.Effect.void;
1438
1805
  };
1439
1806
  var browserConsoleSink = {
1440
1807
  record: (event) => {
1441
1808
  if (!isBrowser) {
1442
- return event.type === "lifecycle:error" ? lifecycleErrorLog(event) : event.type === "diagnostic" ? diagnosticLog(event) : import_effect7.Effect.logDebug({ debugEvent: event });
1809
+ return event.type === "lifecycle:error" ? lifecycleErrorLog(event) : event.type === "diagnostic" ? diagnosticLog(event) : import_effect3.Effect.logDebug({ debugEvent: event });
1443
1810
  }
1444
1811
  return renderBrowserConsoleEvent(event);
1445
1812
  }
1446
1813
  };
1447
- var browserConsoleLayer = import_effect7.Layer.locallyScoped(currentDebugSinks, [browserConsoleSink]);
1814
+ var browserConsoleLayer = import_effect3.Layer.succeed(currentDebugSinks, [browserConsoleSink]);
1448
1815
  var browserDiagnosticConsoleSink = {
1449
1816
  record: (event) => {
1450
1817
  if (!isBrowser) {
1451
- return event.type === "lifecycle:error" ? lifecycleErrorLog(event) : event.type === "diagnostic" && event.severity !== "info" ? diagnosticLog(event) : import_effect7.Effect.void;
1818
+ return event.type === "lifecycle:error" ? lifecycleErrorLog(event) : event.type === "diagnostic" && event.severity !== "info" ? diagnosticLog(event) : import_effect3.Effect.void;
1452
1819
  }
1453
- return event.type === "lifecycle:error" || event.type === "diagnostic" && event.severity !== "info" ? renderBrowserConsoleEvent(event) : import_effect7.Effect.void;
1820
+ return event.type === "lifecycle:error" || event.type === "diagnostic" && event.severity !== "info" ? renderBrowserConsoleEvent(event) : import_effect3.Effect.void;
1454
1821
  }
1455
1822
  };
1456
- var browserDiagnosticConsoleLayer = import_effect7.Layer.locallyScoped(currentDebugSinks, [browserDiagnosticConsoleSink]);
1457
- var browserPrettyLoggerLayer = import_effect7.Logger.replace(
1458
- import_effect7.Logger.defaultLogger,
1459
- import_effect7.Logger.prettyLogger({ mode: "browser", colors: true })
1823
+ var browserDiagnosticConsoleLayer = import_effect3.Layer.succeed(currentDebugSinks, [browserDiagnosticConsoleSink]);
1824
+ var browserPrettyLoggerLayer = import_effect3.Layer.effect(
1825
+ import_effect3.Logger.CurrentLoggers,
1826
+ import_effect3.Effect.gen(function* () {
1827
+ const current = yield* import_effect3.Effect.service(import_effect3.Logger.CurrentLoggers);
1828
+ return new Set(
1829
+ [...current].filter((logger) => logger !== import_effect3.Logger.defaultLogger).concat(import_effect3.Logger.consolePretty({ mode: "browser", colors: true }))
1830
+ );
1831
+ })
1460
1832
  );
1461
- var record = (event) => import_effect7.Effect.gen(function* () {
1462
- const sinks = yield* import_effect7.FiberRef.get(currentDebugSinks);
1833
+ var record = (event) => import_effect3.Effect.gen(function* () {
1834
+ const sinks = yield* import_effect3.Effect.service(currentDebugSinks);
1463
1835
  if (isErrorOnlyOnlySinks(sinks)) {
1464
1836
  if (event.type === "lifecycle:error") {
1465
1837
  yield* lifecycleErrorLog(event);
1466
1838
  return;
1467
1839
  }
1468
- if (event.type === "diagnostic") {
1469
- if (event.severity !== "info") {
1470
- yield* diagnosticLog(event);
1471
- } else {
1472
- yield* import_effect7.Effect.void;
1473
- }
1474
- return;
1840
+ if (event.type === "diagnostic" && event.severity !== "info") {
1841
+ yield* diagnosticLog(event);
1475
1842
  }
1476
- yield* import_effect7.Effect.void;
1477
1843
  return;
1478
1844
  }
1479
1845
  if (sinks.length === 0) {
1480
1846
  if (isBrowser) {
1481
1847
  if (event.type === "lifecycle:error" || event.type === "diagnostic") {
1482
1848
  yield* renderBrowserConsoleEvent(event);
1483
- return;
1484
1849
  }
1485
- yield* import_effect7.Effect.void;
1486
1850
  return;
1487
1851
  }
1488
1852
  if (event.type === "lifecycle:error") {
@@ -1491,13 +1855,15 @@ var record = (event) => import_effect7.Effect.gen(function* () {
1491
1855
  }
1492
1856
  if (event.type === "diagnostic") {
1493
1857
  yield* diagnosticLog(event);
1494
- return;
1495
1858
  }
1496
- yield* import_effect7.Effect.void;
1497
1859
  return;
1498
1860
  }
1861
+ if (typeof event.type === "string" && event.type.startsWith("trace:")) {
1862
+ const mode = yield* import_effect3.Effect.service(currentTraceMode);
1863
+ if (mode === "off") return;
1864
+ }
1499
1865
  const enriched = event;
1500
- const diagnosticsLevel = yield* import_effect7.FiberRef.get(currentDiagnosticsLevel);
1866
+ const diagnosticsLevel = yield* import_effect3.Effect.service(currentDiagnosticsLevel);
1501
1867
  let now;
1502
1868
  const getNow = () => {
1503
1869
  if (now === void 0) now = Date.now();
@@ -1508,47 +1874,390 @@ var record = (event) => import_effect7.Effect.gen(function* () {
1508
1874
  enriched.timestamp = getNow();
1509
1875
  }
1510
1876
  if (diagnosticsLevel !== "off" && enriched.runtimeLabel === void 0) {
1511
- const runtimeLabel = yield* import_effect7.FiberRef.get(currentRuntimeLabel);
1877
+ const runtimeLabel = yield* import_effect3.Effect.service(currentRuntimeLabel);
1512
1878
  if (runtimeLabel) {
1513
1879
  ;
1514
1880
  enriched.runtimeLabel = runtimeLabel;
1515
1881
  }
1516
1882
  }
1517
1883
  if (enriched.type === "diagnostic" && enriched.txnId === void 0) {
1518
- const txnId = yield* import_effect7.FiberRef.get(currentTxnId);
1884
+ const txnId = yield* import_effect3.Effect.service(currentTxnId);
1519
1885
  if (txnId) {
1520
1886
  ;
1521
1887
  enriched.txnId = txnId;
1522
1888
  }
1523
1889
  }
1524
1890
  if (diagnosticsLevel !== "off" && enriched.type === "trace:effectop" && enriched.linkId === void 0) {
1525
- const linkId = yield* import_effect7.FiberRef.get(currentLinkId);
1526
- if (linkId) {
1891
+ const maybeLinkId = yield* import_effect3.Effect.serviceOption(currentLinkId);
1892
+ if (import_effect3.Option.isSome(maybeLinkId) && maybeLinkId.value) {
1527
1893
  ;
1528
- enriched.linkId = linkId;
1894
+ enriched.linkId = maybeLinkId.value;
1895
+ }
1896
+ }
1897
+ if (sinks.length === 1) {
1898
+ yield* sinks[0].record(enriched);
1899
+ return;
1900
+ }
1901
+ yield* import_effect3.Effect.forEach(sinks, (sink) => sink.record(enriched), { discard: true });
1902
+ });
1903
+
1904
+ // src/internal/runtime/core/TaskRunner.ts
1905
+ var import_effect6 = require("effect");
1906
+
1907
+ // src/internal/runtime/core/ModeRunner.ts
1908
+ var import_effect5 = require("effect");
1909
+
1910
+ // src/internal/runtime/core/LatestFiberSlot.ts
1911
+ var import_effect4 = require("effect");
1912
+
1913
+ // src/internal/runtime/core/TaskRunner.ts
1914
+ var inSyncTransactionFiber = import_effect6.ServiceMap.Reference("@logixjs/core/TaskRunner.inSyncTransactionFiber", {
1915
+ defaultValue: () => false
1916
+ });
1917
+ var forceSourceRefresh = import_effect6.ServiceMap.Reference("@logixjs/core/TaskRunner.forceSourceRefresh", {
1918
+ defaultValue: () => false
1919
+ });
1920
+
1921
+ // src/internal/runtime/core/DeclarativeLinkRuntime.ts
1922
+ var import_effect8 = require("effect");
1923
+ var makeDeclarativeLinkRuntime = () => {
1924
+ const moduleAsSourceById = /* @__PURE__ */ new Map();
1925
+ const moduleAsSourceIdsBySource = /* @__PURE__ */ new Map();
1926
+ const declarativeById = /* @__PURE__ */ new Map();
1927
+ const declarativeReadNodesBySource = /* @__PURE__ */ new Map();
1928
+ const registerModuleAsSourceLink = (link2) => {
1929
+ const stored = {
1930
+ ...link2,
1931
+ hasValue: false,
1932
+ lastValue: void 0
1933
+ };
1934
+ moduleAsSourceById.set(link2.id, stored);
1935
+ const set = moduleAsSourceIdsBySource.get(link2.sourceModuleInstanceKey) ?? /* @__PURE__ */ new Set();
1936
+ set.add(link2.id);
1937
+ moduleAsSourceIdsBySource.set(link2.sourceModuleInstanceKey, set);
1938
+ return () => {
1939
+ moduleAsSourceById.delete(link2.id);
1940
+ const current = moduleAsSourceIdsBySource.get(link2.sourceModuleInstanceKey);
1941
+ if (!current) return;
1942
+ current.delete(link2.id);
1943
+ if (current.size === 0) {
1944
+ moduleAsSourceIdsBySource.delete(link2.sourceModuleInstanceKey);
1945
+ }
1946
+ };
1947
+ };
1948
+ const registerDeclarativeLink = (link2) => {
1949
+ const readNodeById = /* @__PURE__ */ new Map();
1950
+ for (const n of link2.readNodes) {
1951
+ readNodeById.set(n.nodeId, n);
1952
+ }
1953
+ const dispatchNodeById = /* @__PURE__ */ new Map();
1954
+ for (const n of link2.dispatchNodes) {
1955
+ dispatchNodeById.set(n.nodeId, n);
1956
+ }
1957
+ const incomingByDispatch = /* @__PURE__ */ new Map();
1958
+ for (const e of link2.ir.edges) {
1959
+ const to = e.to;
1960
+ const isDispatch = dispatchNodeById.has(to);
1961
+ if (!isDispatch) continue;
1962
+ incomingByDispatch.set(to, (incomingByDispatch.get(to) ?? 0) + 1);
1963
+ const count = incomingByDispatch.get(to) ?? 0;
1964
+ if (count > 1) {
1965
+ throw new Error(
1966
+ `[DeclarativeLinkRuntime] Invalid DeclarativeLinkIR: dispatch node has multiple incoming edges (linkId=${link2.linkId}, nodeId=${to}).`
1967
+ );
1968
+ }
1969
+ }
1970
+ const dispatchTargetsByReadNode = /* @__PURE__ */ new Map();
1971
+ for (const e of link2.ir.edges) {
1972
+ const from2 = e.from;
1973
+ const to = e.to;
1974
+ if (!readNodeById.has(from2)) continue;
1975
+ if (!dispatchNodeById.has(to)) continue;
1976
+ const list2 = dispatchTargetsByReadNode.get(from2) ?? [];
1977
+ list2.push(to);
1978
+ dispatchTargetsByReadNode.set(from2, list2);
1979
+ }
1980
+ const stored = {
1981
+ ...link2,
1982
+ readNodeById,
1983
+ dispatchNodeById,
1984
+ dispatchTargetsByReadNode,
1985
+ readNodeState: /* @__PURE__ */ new Map()
1986
+ };
1987
+ declarativeById.set(link2.linkId, stored);
1988
+ for (const n of link2.readNodes) {
1989
+ const list2 = declarativeReadNodesBySource.get(n.moduleInstanceKey) ?? [];
1990
+ list2.push({ linkId: link2.linkId, nodeId: n.nodeId });
1991
+ declarativeReadNodesBySource.set(n.moduleInstanceKey, list2);
1992
+ }
1993
+ return () => {
1994
+ declarativeById.delete(link2.linkId);
1995
+ for (const n of link2.readNodes) {
1996
+ const list2 = declarativeReadNodesBySource.get(n.moduleInstanceKey);
1997
+ if (!list2) continue;
1998
+ const next = list2.filter((x) => !(x.linkId === link2.linkId && x.nodeId === n.nodeId));
1999
+ if (next.length === 0) {
2000
+ declarativeReadNodesBySource.delete(n.moduleInstanceKey);
2001
+ } else {
2002
+ declarativeReadNodesBySource.set(n.moduleInstanceKey, next);
2003
+ }
2004
+ }
2005
+ };
2006
+ };
2007
+ const applyForSources = (args) => import_effect8.Effect.gen(function* () {
2008
+ let scheduled = false;
2009
+ for (const sourceKey of args.changedModuleInstanceKeys) {
2010
+ const ids = moduleAsSourceIdsBySource.get(sourceKey);
2011
+ if (!ids || ids.size === 0) continue;
2012
+ const commit = args.acceptedModules.get(sourceKey);
2013
+ if (!commit) continue;
2014
+ for (const id of ids) {
2015
+ const link2 = moduleAsSourceById.get(id);
2016
+ if (!link2) continue;
2017
+ let selected;
2018
+ try {
2019
+ selected = link2.readQuery.select(commit.state);
2020
+ } catch {
2021
+ continue;
2022
+ }
2023
+ const nextValue = link2.computeValue(selected);
2024
+ if (link2.hasValue && link2.equalsValue(link2.lastValue, nextValue)) {
2025
+ continue;
2026
+ }
2027
+ link2.hasValue = true;
2028
+ link2.lastValue = nextValue;
2029
+ scheduled = true;
2030
+ yield* link2.applyValue(nextValue);
2031
+ }
2032
+ }
2033
+ for (const sourceKey of args.changedModuleInstanceKeys) {
2034
+ const refs = declarativeReadNodesBySource.get(sourceKey);
2035
+ if (!refs || refs.length === 0) continue;
2036
+ const commit = args.acceptedModules.get(sourceKey);
2037
+ if (!commit) continue;
2038
+ for (const ref of refs) {
2039
+ const link2 = declarativeById.get(ref.linkId);
2040
+ if (!link2) continue;
2041
+ const readNode = link2.readNodeById.get(ref.nodeId);
2042
+ if (!readNode) continue;
2043
+ let value;
2044
+ try {
2045
+ value = readNode.readQuery.select(commit.state);
2046
+ } catch {
2047
+ continue;
2048
+ }
2049
+ const state = link2.readNodeState.get(ref.nodeId) ?? { hasValue: false, lastValue: void 0 };
2050
+ const changed = !state.hasValue || !Object.is(state.lastValue, value);
2051
+ if (!changed) continue;
2052
+ state.hasValue = true;
2053
+ state.lastValue = value;
2054
+ link2.readNodeState.set(ref.nodeId, state);
2055
+ const targets = link2.dispatchTargetsByReadNode.get(ref.nodeId) ?? [];
2056
+ for (const dispatchNodeId of targets) {
2057
+ const node2 = link2.dispatchNodeById.get(dispatchNodeId);
2058
+ if (!node2) continue;
2059
+ scheduled = true;
2060
+ yield* node2.dispatch(value);
2061
+ }
2062
+ }
2063
+ }
2064
+ return { scheduled };
2065
+ });
2066
+ return {
2067
+ registerModuleAsSourceLink,
2068
+ registerDeclarativeLink,
2069
+ applyForSources
2070
+ };
2071
+ };
2072
+
2073
+ // src/internal/runtime/core/env.ts
2074
+ var getNodeEnv = () => {
2075
+ try {
2076
+ const env = globalThis?.process?.env;
2077
+ return typeof env?.NODE_ENV === "string" ? env.NODE_ENV : void 0;
2078
+ } catch {
2079
+ return void 0;
2080
+ }
2081
+ };
2082
+ var isDevEnv = () => getNodeEnv() !== "production";
2083
+ var StateTransactionConfigTagImpl = class extends import_effect9.ServiceMap.Service()("@logixjs/core/StateTransactionRuntimeConfig") {
2084
+ };
2085
+ var ReadQueryStrictGateConfigTagImpl = class extends import_effect9.ServiceMap.Service()("@logixjs/core/ReadQueryStrictGateRuntimeConfig") {
2086
+ };
2087
+ var ReplayModeConfigTagImpl = class extends import_effect9.ServiceMap.Service()("@logixjs/core/ReplayModeConfig") {
2088
+ };
2089
+ var ReplayModeConfigTag = ReplayModeConfigTagImpl;
2090
+ var StateTransactionOverridesTagImpl = class extends import_effect9.ServiceMap.Service()("@logixjs/core/StateTransactionOverrides") {
2091
+ };
2092
+ var SchedulingPolicySurfaceTagImpl = class extends import_effect9.ServiceMap.Service()("@logixjs/core/SchedulingPolicySurface") {
2093
+ };
2094
+ var SchedulingPolicySurfaceOverridesTagImpl = class extends import_effect9.ServiceMap.Service()("@logixjs/core/SchedulingPolicySurfaceOverrides") {
2095
+ };
2096
+ var RuntimeStoreTag = class extends import_effect9.ServiceMap.Service()("@logixjs/core/RuntimeStore") {
2097
+ };
2098
+ var runtimeStoreLayer = import_effect9.Layer.effect(
2099
+ RuntimeStoreTag,
2100
+ import_effect9.Effect.acquireRelease(
2101
+ import_effect9.Effect.sync(() => makeRuntimeStore()),
2102
+ (store) => import_effect9.Effect.sync(() => store.dispose())
2103
+ )
2104
+ );
2105
+ var HostSchedulerTag = class extends import_effect9.ServiceMap.Service()("@logixjs/core/HostScheduler") {
2106
+ };
2107
+ var hostSchedulerLayer = import_effect9.Layer.succeed(
2108
+ HostSchedulerTag,
2109
+ getGlobalHostScheduler()
2110
+ );
2111
+ var DeclarativeLinkRuntimeTag = class extends import_effect9.ServiceMap.Service()("@logixjs/core/DeclarativeLinkRuntime") {
2112
+ };
2113
+ var declarativeLinkRuntimeLayer = import_effect9.Layer.succeed(
2114
+ DeclarativeLinkRuntimeTag,
2115
+ makeDeclarativeLinkRuntime()
2116
+ );
2117
+ var TickSchedulerTag = class extends import_effect9.ServiceMap.Service()("@logixjs/core/TickScheduler") {
2118
+ };
2119
+
2120
+ // src/internal/runtime/core/runtimeInternalsAccessor.ts
2121
+ var BOUND_INTERNALS = /* @__PURE__ */ Symbol.for("@logixjs/core/boundInternals");
2122
+ var getBoundInternals = (bound) => {
2123
+ const internals = bound[BOUND_INTERNALS];
2124
+ if (!internals) {
2125
+ const msg = isDevEnv() ? [
2126
+ "[MissingBoundInternals] Bound internals not installed on Bound API instance.",
2127
+ "fix:",
2128
+ "- Ensure BoundApiRuntime attaches internals (020 foundation).",
2129
+ "- If you created a mock bound for tests, attach internals or avoid calling internal-only APIs."
2130
+ ].join("\n") : "Bound internals not installed";
2131
+ throw new Error(msg);
2132
+ }
2133
+ return internals;
2134
+ };
2135
+
2136
+ // src/internal/state-trait/source.impl.ts
2137
+ var import_effect14 = require("effect");
2138
+ var import_mutative = require("mutative");
2139
+
2140
+ // src/internal/effect-op.ts
2141
+ var import_effect11 = require("effect");
2142
+
2143
+ // src/internal/observability/runSession.ts
2144
+ var import_effect10 = require("effect");
2145
+ var RunSessionTagImpl = class extends import_effect10.ServiceMap.Service()("@logixjs/core/RunSession") {
2146
+ };
2147
+ var RunSessionTag = RunSessionTagImpl;
2148
+
2149
+ // src/internal/effect-op.ts
2150
+ var nextGlobalOpSeq = 0;
2151
+ var nextOpSeq = () => {
2152
+ nextGlobalOpSeq += 1;
2153
+ return nextGlobalOpSeq;
2154
+ };
2155
+ var makeId = (instanceId, opSeq) => instanceId ? `${instanceId}::o${opSeq}` : `o${opSeq}`;
2156
+ var make2 = (params) => ({
2157
+ ...params.id ? { id: params.id, meta: params.meta } : (() => {
2158
+ const meta = params.meta ?? {};
2159
+ const instanceId = meta.instanceId;
2160
+ const opSeq = typeof meta.opSeq === "number" && Number.isFinite(meta.opSeq) ? Math.floor(meta.opSeq) : nextOpSeq();
2161
+ return {
2162
+ id: makeId(instanceId, opSeq),
2163
+ meta: meta.opSeq === opSeq ? meta : { ...meta, opSeq }
2164
+ };
2165
+ })(),
2166
+ kind: params.kind,
2167
+ name: params.name,
2168
+ payload: params.payload,
2169
+ effect: params.effect
2170
+ });
2171
+ var run = (op, stack) => runWithMiddleware(op, stack);
2172
+
2173
+ // src/internal/resource.ts
2174
+ var import_effect12 = require("effect");
2175
+ var stableStringify3 = (value) => {
2176
+ const seen = /* @__PURE__ */ new WeakSet();
2177
+ const encode = (input) => {
2178
+ if (input === null) return null;
2179
+ if (typeof input === "string" || typeof input === "number" || typeof input === "boolean") {
2180
+ return input;
2181
+ }
2182
+ if (typeof input === "bigint") return input.toString();
2183
+ if (typeof input === "undefined") return "__undefined__";
2184
+ if (typeof input === "symbol") return `__symbol__:${String(input)}`;
2185
+ if (typeof input === "function") return "__function__";
2186
+ if (Array.isArray(input)) {
2187
+ return input.map((v) => encode(v));
2188
+ }
2189
+ if (input instanceof Date) {
2190
+ return `__date__:${input.toISOString()}`;
2191
+ }
2192
+ if (input instanceof Error) {
2193
+ return {
2194
+ _tag: "Error",
2195
+ name: input.name,
2196
+ message: input.message
2197
+ };
2198
+ }
2199
+ if (input && typeof input === "object") {
2200
+ const obj = input;
2201
+ if (seen.has(obj)) return "__cycle__";
2202
+ seen.add(obj);
2203
+ const record2 = input;
2204
+ const keys = Object.keys(record2).sort();
2205
+ const out = {};
2206
+ for (const k of keys) {
2207
+ out[k] = encode(record2[k]);
2208
+ }
2209
+ return out;
1529
2210
  }
2211
+ return String(input);
2212
+ };
2213
+ try {
2214
+ return JSON.stringify(encode(value));
2215
+ } catch {
2216
+ return String(value);
1530
2217
  }
1531
- if (sinks.length === 1) {
1532
- yield* sinks[0].record(enriched);
1533
- return;
1534
- }
1535
- yield* import_effect7.Effect.forEach(sinks, (sink) => sink.record(enriched), { discard: true });
1536
- });
1537
-
1538
- // src/internal/runtime/core/TaskRunner.ts
1539
- var import_effect8 = require("effect");
1540
- var inSyncTransactionFiber = import_effect8.FiberRef.unsafeMake(false);
1541
- var forceSourceRefresh = import_effect8.FiberRef.unsafeMake(false);
2218
+ };
2219
+ var keyHash = (key) => stableStringify3(key);
2220
+ var Snapshot = {
2221
+ idle: () => ({
2222
+ status: "idle",
2223
+ keyHash: void 0,
2224
+ data: void 0,
2225
+ error: void 0
2226
+ }),
2227
+ loading: (params) => ({
2228
+ status: "loading",
2229
+ keyHash: params.keyHash,
2230
+ data: void 0,
2231
+ error: void 0
2232
+ }),
2233
+ success: (params) => ({
2234
+ status: "success",
2235
+ keyHash: params.keyHash,
2236
+ data: params.data,
2237
+ error: void 0
2238
+ }),
2239
+ error: (params) => ({
2240
+ status: "error",
2241
+ keyHash: params.keyHash,
2242
+ data: void 0,
2243
+ error: params.error
2244
+ })
2245
+ };
2246
+ var ResourceRegistryTag = class extends import_effect12.ServiceMap.Service()("@logixjs/core/ResourceRegistry") {
2247
+ };
2248
+ var internal = {
2249
+ ResourceRegistryTag
2250
+ };
1542
2251
 
1543
2252
  // src/internal/runtime/core/ReplayLog.ts
1544
- var import_effect9 = require("effect");
1545
- var ReplayLog = class extends import_effect9.Context.Tag("@logixjs/core/ReplayLog")() {
2253
+ var import_effect13 = require("effect");
2254
+ var ReplayLog = class extends import_effect13.ServiceMap.Service()("@logixjs/core/ReplayLog") {
1546
2255
  };
1547
- var snapshot = import_effect9.Effect.gen(function* () {
2256
+ var snapshot = import_effect13.Effect.gen(function* () {
1548
2257
  const log = yield* ReplayLog;
1549
2258
  return yield* log.snapshot;
1550
2259
  });
1551
- var resetCursor = import_effect9.Effect.gen(function* () {
2260
+ var resetCursor = import_effect13.Effect.gen(function* () {
1552
2261
  const log = yield* ReplayLog;
1553
2262
  yield* log.resetCursor;
1554
2263
  });
@@ -1698,16 +2407,16 @@ var trace = (fn, state) => {
1698
2407
  };
1699
2408
  };
1700
2409
 
1701
- // src/internal/state-trait/source.ts
1702
- var onceInRunSession = (key) => import_effect10.Effect.serviceOption(RunSessionTag).pipe(
1703
- import_effect10.Effect.map((maybe) => import_effect10.Option.isSome(maybe) ? maybe.value.local.once(key) : true)
2410
+ // src/internal/state-trait/source.impl.ts
2411
+ var onceInRunSession = (key) => import_effect14.Effect.serviceOption(RunSessionTag).pipe(
2412
+ import_effect14.Effect.map((maybe) => import_effect14.Option.isSome(maybe) ? maybe.value.local.once(key) : true)
1704
2413
  );
1705
2414
  var formatList = (items, limit = 10) => {
1706
2415
  if (items.length === 0) return "";
1707
2416
  if (items.length <= limit) return items.join(", ");
1708
2417
  return `${items.slice(0, limit).join(", ")}, \u2026(+${items.length - limit})`;
1709
2418
  };
1710
- var emitDepsMismatch = (params) => import_effect10.Effect.gen(function* () {
2419
+ var emitDepsMismatch = (params) => import_effect14.Effect.gen(function* () {
1711
2420
  const key = `${params.instanceId ?? "unknown"}::${params.kind}::${params.fieldPath}`;
1712
2421
  const shouldEmit = yield* onceInRunSession(`deps_mismatch:${key}`);
1713
2422
  if (!shouldEmit) return;
@@ -1722,8 +2431,10 @@ var emitDepsMismatch = (params) => import_effect10.Effect.gen(function* () {
1722
2431
  kind: `deps_mismatch:${params.kind}`
1723
2432
  });
1724
2433
  });
1725
- var getMiddlewareStack = () => import_effect10.Effect.serviceOption(EffectOpMiddlewareTag).pipe(
1726
- import_effect10.Effect.map((maybe) => import_effect10.Option.isSome(maybe) ? maybe.value.stack : [])
2434
+ var getMiddlewareStack = () => import_effect14.Effect.serviceOption(
2435
+ EffectOpMiddlewareTag
2436
+ ).pipe(
2437
+ import_effect14.Effect.map((maybe) => import_effect14.Option.isSome(maybe) ? maybe.value.stack : [])
1727
2438
  );
1728
2439
  var recordTraitPatch = (bound, path, reason, from2, to, traitNodeId) => {
1729
2440
  const normalized = normalizeFieldPath(path) ?? [];
@@ -1748,7 +2459,7 @@ var getBoundScope = (bound) => {
1748
2459
  return { moduleId: void 0, instanceId: void 0 };
1749
2460
  }
1750
2461
  };
1751
- var setSnapshotInTxn = (bound, fieldPath, next, reason, stepId, traitNodeId) => import_effect10.Effect.gen(function* () {
2462
+ var setSnapshotInTxn = (bound, fieldPath, next, reason, stepId, traitNodeId) => import_effect14.Effect.gen(function* () {
1752
2463
  let wrote = false;
1753
2464
  yield* bound.state.mutate((draft) => {
1754
2465
  const prev = getAtPath(draft, fieldPath);
@@ -1759,7 +2470,7 @@ var setSnapshotInTxn = (bound, fieldPath, next, reason, stepId, traitNodeId) =>
1759
2470
  });
1760
2471
  return wrote;
1761
2472
  });
1762
- var writebackIfCurrentKeyHash = (bound, fieldPath, keyHash2, next, reason, stepId, traitNodeId, replayEvent) => import_effect10.Effect.gen(function* () {
2473
+ var writebackIfCurrentKeyHash = (bound, fieldPath, keyHash2, next, reason, stepId, traitNodeId, replayEvent) => import_effect14.Effect.gen(function* () {
1763
2474
  let wrote = false;
1764
2475
  yield* bound.state.mutate((draft) => {
1765
2476
  const current = getAtPath(draft, fieldPath);
@@ -1777,7 +2488,7 @@ var writebackIfCurrentKeyHash = (bound, fieldPath, keyHash2, next, reason, stepI
1777
2488
  return wrote;
1778
2489
  });
1779
2490
  var installSourceRefresh = (bound, step, entry) => {
1780
- if (!step.targetFieldPath) return import_effect10.Effect.void;
2491
+ if (!step.targetFieldPath) return import_effect14.Effect.void;
1781
2492
  const fieldPath = step.targetFieldPath;
1782
2493
  const resourceId = step.resourceId ?? entry.meta.resource;
1783
2494
  const listItem = parseListItemFieldPath(fieldPath);
@@ -1785,12 +2496,12 @@ var installSourceRefresh = (bound, step, entry) => {
1785
2496
  try {
1786
2497
  internals = getBoundInternals(bound);
1787
2498
  } catch {
1788
- return import_effect10.Effect.void;
2499
+ return import_effect14.Effect.void;
1789
2500
  }
1790
2501
  const register = internals.traits.registerSourceRefresh;
1791
2502
  const recordSnapshot = (replayMode, replayLog, input) => {
1792
- if (!replayLog) return import_effect10.Effect.void;
1793
- if (replayMode !== "live") return import_effect10.Effect.void;
2503
+ if (!replayLog) return import_effect14.Effect.void;
2504
+ if (replayMode !== "live") return import_effect14.Effect.void;
1794
2505
  const event = input && typeof input === "object" && input._tag === "ResourceSnapshot" ? input : {
1795
2506
  _tag: "ResourceSnapshot",
1796
2507
  resourceId,
@@ -1808,12 +2519,12 @@ var installSourceRefresh = (bound, step, entry) => {
1808
2519
  if (listItem) {
1809
2520
  const store = internals.traits.rowIdStore;
1810
2521
  if (!store) {
1811
- return import_effect10.Effect.void;
2522
+ return import_effect14.Effect.void;
1812
2523
  }
1813
2524
  const listPath = listItem.listPath;
1814
2525
  const itemPath = listItem.itemPath;
1815
2526
  if (!itemPath) {
1816
- return import_effect10.Effect.void;
2527
+ return import_effect14.Effect.void;
1817
2528
  }
1818
2529
  const concurrency2 = entry.meta.concurrency;
1819
2530
  const mode2 = concurrency2 ?? "switch";
@@ -1824,7 +2535,7 @@ var installSourceRefresh = (bound, step, entry) => {
1824
2535
  trailing2.delete(rowId);
1825
2536
  inFlight2.delete(rowId);
1826
2537
  });
1827
- const setSnapshotForRowInTxn = (rowId, next, reason, stepId) => import_effect10.Effect.gen(function* () {
2538
+ const setSnapshotForRowInTxn = (rowId, next, reason, stepId) => import_effect14.Effect.gen(function* () {
1828
2539
  let wrotePath;
1829
2540
  yield* bound.state.mutate((draft) => {
1830
2541
  const index = store.getIndex(listPath, rowId);
@@ -1838,7 +2549,7 @@ var installSourceRefresh = (bound, step, entry) => {
1838
2549
  });
1839
2550
  return wrotePath;
1840
2551
  });
1841
- const writebackIfCurrentKeyHashForRow = (rowId, keyHash2, next, reason, stepId, phase) => import_effect10.Effect.gen(function* () {
2552
+ const writebackIfCurrentKeyHashForRow = (rowId, keyHash2, next, reason, stepId, phase) => import_effect14.Effect.gen(function* () {
1842
2553
  let wrotePath;
1843
2554
  yield* bound.state.mutate((draft) => {
1844
2555
  const index = store.getIndex(listPath, rowId);
@@ -1870,7 +2581,7 @@ var installSourceRefresh = (bound, step, entry) => {
1870
2581
  });
1871
2582
  return wrotePath;
1872
2583
  });
1873
- const startFetch2 = (rowId, key, keyHash2, replayMode, replayLog) => import_effect10.Effect.gen(function* () {
2584
+ const startFetch2 = (rowId, key, keyHash2, replayMode, replayLog) => import_effect14.Effect.gen(function* () {
1874
2585
  const { moduleId, instanceId } = getBoundScope(bound);
1875
2586
  const indexForLog = store.getIndex(listPath, rowId);
1876
2587
  const logFieldPath = indexForLog === void 0 ? void 0 : toListItemValuePath(listPath, indexForLog, itemPath);
@@ -1908,17 +2619,17 @@ var installSourceRefresh = (bound, step, entry) => {
1908
2619
  recordReplayEvent(bound, event);
1909
2620
  yield* recordSnapshot(replayMode, replayLog, event);
1910
2621
  }
1911
- const io = import_effect10.Effect.gen(function* () {
2622
+ const io = import_effect14.Effect.gen(function* () {
1912
2623
  if (replayMode === "replay" && replayLog) {
1913
- yield* import_effect10.Effect.yieldNow();
2624
+ yield* import_effect14.Effect.yieldNow;
1914
2625
  const consumePath = wroteLoadingPath ?? logFieldPath;
1915
- if (!consumePath) return yield* import_effect10.Effect.void;
2626
+ if (!consumePath) return yield* import_effect14.Effect.void;
1916
2627
  const replayed = yield* replayLog.consumeNextResourceSnapshot({
1917
2628
  resourceId,
1918
2629
  fieldPath: consumePath,
1919
2630
  keyHash: keyHash2
1920
2631
  });
1921
- if (!replayed) return yield* import_effect10.Effect.void;
2632
+ if (!replayed) return yield* import_effect14.Effect.void;
1922
2633
  if (replayed.phase === "success") {
1923
2634
  yield* writebackIfCurrentKeyHashForRow(
1924
2635
  rowId,
@@ -1938,14 +2649,16 @@ var installSourceRefresh = (bound, step, entry) => {
1938
2649
  "error"
1939
2650
  );
1940
2651
  }
1941
- return yield* import_effect10.Effect.void;
2652
+ return yield* import_effect14.Effect.void;
1942
2653
  }
1943
2654
  const stack = yield* getMiddlewareStack();
1944
- const registryOpt = yield* import_effect10.Effect.serviceOption(internal.ResourceRegistryTag);
1945
- const registry = import_effect10.Option.isSome(registryOpt) ? registryOpt.value : void 0;
2655
+ const registryOpt = yield* import_effect14.Effect.serviceOption(
2656
+ internal.ResourceRegistryTag
2657
+ );
2658
+ const registry = import_effect14.Option.isSome(registryOpt) ? registryOpt.value : void 0;
1946
2659
  const spec = registry?.specs.get(resourceId);
1947
2660
  if (!spec) {
1948
- return yield* import_effect10.Effect.void;
2661
+ return yield* import_effect14.Effect.void;
1949
2662
  }
1950
2663
  const loadEffect = spec.load(key);
1951
2664
  const meta = {
@@ -1960,19 +2673,19 @@ var installSourceRefresh = (bound, step, entry) => {
1960
2673
  stepId: step.id
1961
2674
  };
1962
2675
  if (!(typeof meta.opSeq === "number" && Number.isFinite(meta.opSeq))) {
1963
- const sessionOpt = yield* import_effect10.Effect.serviceOption(RunSessionTag);
1964
- if (import_effect10.Option.isSome(sessionOpt)) {
2676
+ const sessionOpt = yield* import_effect14.Effect.serviceOption(RunSessionTag);
2677
+ if (import_effect14.Option.isSome(sessionOpt)) {
1965
2678
  const seqKey = instanceId ?? "global";
1966
2679
  meta.opSeq = sessionOpt.value.local.nextSeq("opSeq", seqKey);
1967
2680
  }
1968
2681
  }
1969
- const op = make({
2682
+ const op = make2({
1970
2683
  kind: "service",
1971
2684
  name: resourceId,
1972
2685
  effect: loadEffect,
1973
2686
  meta
1974
2687
  });
1975
- const exit = yield* import_effect10.Effect.exit(run(op, stack));
2688
+ const exit = yield* import_effect14.Effect.exit(run(op, stack));
1976
2689
  if (exit._tag === "Success") {
1977
2690
  const successSnapshot = Snapshot.success({ keyHash: keyHash2, data: exit.value });
1978
2691
  const wroteSuccessPath = yield* writebackIfCurrentKeyHashForRow(
@@ -2022,47 +2735,40 @@ var installSourceRefresh = (bound, step, entry) => {
2022
2735
  });
2023
2736
  }
2024
2737
  }
2025
- }).pipe(import_effect10.Effect.catchAllCause(() => import_effect10.Effect.void));
2026
- const fiber = yield* import_effect10.Effect.forkScoped(import_effect10.Effect.locally(inSyncTransactionFiber, false)(io));
2738
+ }).pipe(import_effect14.Effect.catchCause(() => import_effect14.Effect.void));
2739
+ const fiber = yield* import_effect14.Effect.forkScoped(import_effect14.Effect.provideService(io, inSyncTransactionFiber, false));
2027
2740
  const myGen = gen2 += 1;
2028
2741
  inFlight2.set(rowId, { gen: myGen, fiber, keyHash: keyHash2 });
2029
- yield* import_effect10.Effect.forkScoped(
2030
- import_effect10.Effect.locally(
2031
- inSyncTransactionFiber,
2032
- false
2033
- )(
2034
- import_effect10.Fiber.await(fiber).pipe(
2035
- import_effect10.Effect.zipRight(
2036
- import_effect10.Effect.sync(() => {
2037
- const current = inFlight2.get(rowId);
2038
- if (current && current.gen === myGen) {
2039
- inFlight2.delete(rowId);
2040
- }
2041
- })
2042
- ),
2043
- import_effect10.Effect.zipRight(
2044
- mode2 === "exhaust-trailing" ? import_effect10.Effect.gen(function* () {
2045
- const next = trailing2.get(rowId);
2046
- trailing2.delete(rowId);
2047
- if (next) {
2048
- yield* startFetch2(rowId, next.key, next.keyHash, replayMode, replayLog);
2049
- }
2050
- }) : import_effect10.Effect.void
2051
- ),
2052
- import_effect10.Effect.catchAllCause(() => import_effect10.Effect.void)
2053
- )
2054
- )
2742
+ yield* import_effect14.Effect.forkScoped(
2743
+ import_effect14.Effect.provideService(import_effect14.Fiber.await(fiber).pipe(
2744
+ import_effect14.Effect.flatMap(() => import_effect14.Effect.sync(() => {
2745
+ const current = inFlight2.get(rowId);
2746
+ if (current && current.gen === myGen) {
2747
+ inFlight2.delete(rowId);
2748
+ }
2749
+ })),
2750
+ import_effect14.Effect.flatMap(() => mode2 === "exhaust-trailing" ? import_effect14.Effect.gen(function* () {
2751
+ const next = trailing2.get(rowId);
2752
+ trailing2.delete(rowId);
2753
+ if (next) {
2754
+ yield* startFetch2(rowId, next.key, next.keyHash, replayMode, replayLog);
2755
+ }
2756
+ }) : import_effect14.Effect.void),
2757
+ import_effect14.Effect.catchCause(() => import_effect14.Effect.void)
2758
+ ), inSyncTransactionFiber, false)
2055
2759
  );
2056
2760
  });
2057
2761
  register(
2058
2762
  fieldPath,
2059
- (state) => import_effect10.Effect.gen(function* () {
2763
+ (state) => import_effect14.Effect.gen(function* () {
2060
2764
  const { moduleId, instanceId } = getBoundScope(bound);
2061
- const replayModeOpt = yield* import_effect10.Effect.serviceOption(ReplayModeConfigTag);
2062
- const replayMode = import_effect10.Option.isSome(replayModeOpt) ? replayModeOpt.value.mode : "live";
2063
- const replayLogOpt = yield* import_effect10.Effect.serviceOption(ReplayLog);
2064
- const replayLog = import_effect10.Option.isSome(replayLogOpt) ? replayLogOpt.value : void 0;
2065
- const force = yield* import_effect10.FiberRef.get(forceSourceRefresh);
2765
+ const replayModeOpt = yield* import_effect14.Effect.serviceOption(
2766
+ ReplayModeConfigTag
2767
+ );
2768
+ const replayMode = import_effect14.Option.isSome(replayModeOpt) ? replayModeOpt.value.mode : "live";
2769
+ const replayLogOpt = yield* import_effect14.Effect.serviceOption(ReplayLog);
2770
+ const replayLog = import_effect14.Option.isSome(replayLogOpt) ? replayLogOpt.value : void 0;
2771
+ const force = yield* import_effect14.Effect.service(forceSourceRefresh).pipe(import_effect14.Effect.orDie);
2066
2772
  const listValue = getAtPath(state, listPath);
2067
2773
  const items = Array.isArray(listValue) ? listValue : [];
2068
2774
  const ids = store.ensureList(listPath, items);
@@ -2173,14 +2879,14 @@ var installSourceRefresh = (bound, step, entry) => {
2173
2879
  }
2174
2880
  })
2175
2881
  );
2176
- return import_effect10.Effect.void;
2882
+ return import_effect14.Effect.void;
2177
2883
  }
2178
2884
  let inFlight;
2179
2885
  let gen = 0;
2180
2886
  let trailing;
2181
2887
  const concurrency = entry.meta.concurrency;
2182
2888
  const mode = concurrency ?? "switch";
2183
- const startFetch = (key, keyHash2, replayMode, replayLog) => import_effect10.Effect.gen(function* () {
2889
+ const startFetch = (key, keyHash2, replayMode, replayLog) => import_effect14.Effect.gen(function* () {
2184
2890
  const { moduleId, instanceId } = getBoundScope(bound);
2185
2891
  let loadingSnapshot = Snapshot.loading({ keyHash: keyHash2 });
2186
2892
  if (replayMode === "replay" && replayLog) {
@@ -2218,15 +2924,15 @@ var installSourceRefresh = (bound, step, entry) => {
2218
2924
  recordReplayEvent(bound, event);
2219
2925
  yield* recordSnapshot(replayMode, replayLog, event);
2220
2926
  }
2221
- const io = import_effect10.Effect.gen(function* () {
2927
+ const io = import_effect14.Effect.gen(function* () {
2222
2928
  if (replayMode === "replay" && replayLog) {
2223
- yield* import_effect10.Effect.yieldNow();
2929
+ yield* import_effect14.Effect.yieldNow;
2224
2930
  const replayed = yield* replayLog.consumeNextResourceSnapshot({
2225
2931
  resourceId,
2226
2932
  fieldPath,
2227
2933
  keyHash: keyHash2
2228
2934
  });
2229
- if (!replayed) return yield* import_effect10.Effect.void;
2935
+ if (!replayed) return yield* import_effect14.Effect.void;
2230
2936
  if (replayed.phase === "success") {
2231
2937
  const event = {
2232
2938
  _tag: "ResourceSnapshot",
@@ -2274,14 +2980,14 @@ var installSourceRefresh = (bound, step, entry) => {
2274
2980
  event
2275
2981
  );
2276
2982
  }
2277
- return yield* import_effect10.Effect.void;
2983
+ return yield* import_effect14.Effect.void;
2278
2984
  }
2279
2985
  const stack = yield* getMiddlewareStack();
2280
- const registryOpt = yield* import_effect10.Effect.serviceOption(internal.ResourceRegistryTag);
2281
- const registry = import_effect10.Option.isSome(registryOpt) ? registryOpt.value : void 0;
2986
+ const registryOpt = yield* import_effect14.Effect.serviceOption(internal.ResourceRegistryTag);
2987
+ const registry = import_effect14.Option.isSome(registryOpt) ? registryOpt.value : void 0;
2282
2988
  const spec = registry?.specs.get(resourceId);
2283
2989
  if (!spec) {
2284
- return yield* import_effect10.Effect.void;
2990
+ return yield* import_effect14.Effect.void;
2285
2991
  }
2286
2992
  const loadEffect = spec.load(key);
2287
2993
  const meta = {
@@ -2295,19 +3001,19 @@ var installSourceRefresh = (bound, step, entry) => {
2295
3001
  stepId: step.id
2296
3002
  };
2297
3003
  if (!(typeof meta.opSeq === "number" && Number.isFinite(meta.opSeq))) {
2298
- const sessionOpt = yield* import_effect10.Effect.serviceOption(RunSessionTag);
2299
- if (import_effect10.Option.isSome(sessionOpt)) {
3004
+ const sessionOpt = yield* import_effect14.Effect.serviceOption(RunSessionTag);
3005
+ if (import_effect14.Option.isSome(sessionOpt)) {
2300
3006
  const seqKey = instanceId ?? "global";
2301
3007
  meta.opSeq = sessionOpt.value.local.nextSeq("opSeq", seqKey);
2302
3008
  }
2303
3009
  }
2304
- const op = make({
3010
+ const op = make2({
2305
3011
  kind: "trait-source",
2306
3012
  name: resourceId,
2307
3013
  effect: loadEffect,
2308
3014
  meta
2309
3015
  });
2310
- const exit = yield* import_effect10.Effect.exit(run(op, stack));
3016
+ const exit = yield* import_effect14.Effect.exit(run(op, stack));
2311
3017
  if (exit._tag === "Success") {
2312
3018
  const successSnapshot = Snapshot.success({ keyHash: keyHash2, data: exit.value });
2313
3019
  const event = {
@@ -2363,46 +3069,39 @@ var installSourceRefresh = (bound, step, entry) => {
2363
3069
  yield* recordSnapshot(replayMode, replayLog, event);
2364
3070
  }
2365
3071
  }
2366
- }).pipe(import_effect10.Effect.catchAllCause(() => import_effect10.Effect.void));
2367
- const fiber = yield* import_effect10.Effect.forkScoped(import_effect10.Effect.locally(inSyncTransactionFiber, false)(io));
3072
+ }).pipe(import_effect14.Effect.catchCause(() => import_effect14.Effect.void));
3073
+ const fiber = yield* import_effect14.Effect.forkScoped(import_effect14.Effect.provideService(io, inSyncTransactionFiber, false));
2368
3074
  const myGen = gen += 1;
2369
3075
  inFlight = { gen: myGen, fiber, keyHash: keyHash2 };
2370
- yield* import_effect10.Effect.forkScoped(
2371
- import_effect10.Effect.locally(
2372
- inSyncTransactionFiber,
2373
- false
2374
- )(
2375
- import_effect10.Fiber.await(fiber).pipe(
2376
- import_effect10.Effect.zipRight(
2377
- import_effect10.Effect.sync(() => {
2378
- if (inFlight && inFlight.gen === myGen) {
2379
- inFlight = void 0;
2380
- }
2381
- })
2382
- ),
2383
- import_effect10.Effect.zipRight(
2384
- mode === "exhaust-trailing" ? import_effect10.Effect.gen(function* () {
2385
- const next = trailing;
2386
- trailing = void 0;
2387
- if (next) {
2388
- yield* startFetch(next.key, next.keyHash, replayMode, replayLog);
2389
- }
2390
- }) : import_effect10.Effect.void
2391
- ),
2392
- import_effect10.Effect.catchAllCause(() => import_effect10.Effect.void)
2393
- )
2394
- )
3076
+ yield* import_effect14.Effect.forkScoped(
3077
+ import_effect14.Effect.provideService(import_effect14.Fiber.await(fiber).pipe(
3078
+ import_effect14.Effect.flatMap(() => import_effect14.Effect.sync(() => {
3079
+ if (inFlight && inFlight.gen === myGen) {
3080
+ inFlight = void 0;
3081
+ }
3082
+ })),
3083
+ import_effect14.Effect.flatMap(() => mode === "exhaust-trailing" ? import_effect14.Effect.gen(function* () {
3084
+ const next = trailing;
3085
+ trailing = void 0;
3086
+ if (next) {
3087
+ yield* startFetch(next.key, next.keyHash, replayMode, replayLog);
3088
+ }
3089
+ }) : import_effect14.Effect.void),
3090
+ import_effect14.Effect.catchCause(() => import_effect14.Effect.void)
3091
+ ), inSyncTransactionFiber, false)
2395
3092
  );
2396
3093
  });
2397
3094
  register(
2398
3095
  fieldPath,
2399
- (state) => import_effect10.Effect.gen(function* () {
3096
+ (state) => import_effect14.Effect.gen(function* () {
2400
3097
  const { moduleId, instanceId } = getBoundScope(bound);
2401
- const replayModeOpt = yield* import_effect10.Effect.serviceOption(ReplayModeConfigTag);
2402
- const replayMode = import_effect10.Option.isSome(replayModeOpt) ? replayModeOpt.value.mode : "live";
2403
- const replayLogOpt = yield* import_effect10.Effect.serviceOption(ReplayLog);
2404
- const replayLog = import_effect10.Option.isSome(replayLogOpt) ? replayLogOpt.value : void 0;
2405
- const force = yield* import_effect10.FiberRef.get(forceSourceRefresh);
3098
+ const replayModeOpt = yield* import_effect14.Effect.serviceOption(
3099
+ ReplayModeConfigTag
3100
+ );
3101
+ const replayMode = import_effect14.Option.isSome(replayModeOpt) ? replayModeOpt.value.mode : "live";
3102
+ const replayLogOpt = yield* import_effect14.Effect.serviceOption(ReplayLog);
3103
+ const replayLog = import_effect14.Option.isSome(replayLogOpt) ? replayLogOpt.value : void 0;
3104
+ const force = yield* import_effect14.Effect.service(forceSourceRefresh).pipe(import_effect14.Effect.orDie);
2406
3105
  let key;
2407
3106
  try {
2408
3107
  key = entry.meta.key(state);
@@ -2428,7 +3127,7 @@ var installSourceRefresh = (bound, step, entry) => {
2428
3127
  }
2429
3128
  if (key === void 0) {
2430
3129
  if (inFlight) {
2431
- yield* import_effect10.Fiber.interruptFork(inFlight.fiber);
3130
+ yield* import_effect14.Fiber.interrupt(inFlight.fiber);
2432
3131
  inFlight = void 0;
2433
3132
  }
2434
3133
  trailing = void 0;
@@ -2501,15 +3200,629 @@ var installSourceRefresh = (bound, step, entry) => {
2501
3200
  return;
2502
3201
  }
2503
3202
  if (mode === "switch" && inFlight) {
2504
- yield* import_effect10.Fiber.interruptFork(inFlight.fiber);
3203
+ yield* import_effect14.Fiber.interrupt(inFlight.fiber);
2505
3204
  inFlight = void 0;
2506
3205
  trailing = void 0;
2507
3206
  }
2508
3207
  yield* startFetch(key, h, replayMode, replayLog);
2509
3208
  })
2510
3209
  );
2511
- return import_effect10.Effect.void;
3210
+ return import_effect14.Effect.void;
3211
+ };
3212
+
3213
+ // src/internal/state-trait/external-store.ts
3214
+ var import_effect15 = require("effect");
3215
+ var import_mutative2 = require("mutative");
3216
+
3217
+ // src/internal/external-store-descriptor.ts
3218
+ var EXTERNAL_STORE_DESCRIPTOR = /* @__PURE__ */ Symbol.for("@logixjs/core/externalStoreDescriptor");
3219
+ var getExternalStoreDescriptor = (store) => {
3220
+ if (!store || typeof store !== "object" && typeof store !== "function") return void 0;
3221
+ return store[EXTERNAL_STORE_DESCRIPTOR];
3222
+ };
3223
+
3224
+ // src/internal/state-trait/external-store.ts
3225
+ var isFn = (value) => typeof value === "function";
3226
+ var writebackCoordinatorByInternals = /* @__PURE__ */ new WeakMap();
3227
+ var getOrCreateExternalStoreWritebackCoordinator = (args) => import_effect15.Effect.gen(function* () {
3228
+ const cached = writebackCoordinatorByInternals.get(args.internals);
3229
+ if (cached) return cached;
3230
+ let closed = false;
3231
+ let inFlight = false;
3232
+ let pendingWrites = /* @__PURE__ */ new Map();
3233
+ const drainPendingWrites = () => {
3234
+ if (pendingWrites.size === 0) return [];
3235
+ const drained = pendingWrites;
3236
+ pendingWrites = /* @__PURE__ */ new Map();
3237
+ return Array.from(drained.values());
3238
+ };
3239
+ const applyWritebackBatch = (batch) => import_effect15.Effect.gen(function* () {
3240
+ if (batch.length === 0) return;
3241
+ if (batch.length === 1) {
3242
+ const req = batch[0];
3243
+ const prevState2 = yield* args.bound.state.read;
3244
+ const prevValue = getAtPath(prevState2, req.fieldPath);
3245
+ if (req.isEqual(prevValue, req.nextValue)) return;
3246
+ const nextDraft2 = (0, import_mutative2.create)(prevState2, (draft) => {
3247
+ setAtPathMutating(draft, req.fieldPath, req.nextValue);
3248
+ });
3249
+ args.internals.txn.recordStatePatch(
3250
+ req.normalizedPatchPath,
3251
+ "trait-external-store",
3252
+ prevValue,
3253
+ req.nextValue,
3254
+ req.traitNodeId
3255
+ );
3256
+ args.internals.txn.updateDraft(nextDraft2);
3257
+ return;
3258
+ }
3259
+ const prevState = yield* args.bound.state.read;
3260
+ const changes = [];
3261
+ for (let i = 0; i < batch.length; i++) {
3262
+ const req = batch[i];
3263
+ const prevValue = getAtPath(prevState, req.fieldPath);
3264
+ if (req.isEqual(prevValue, req.nextValue)) continue;
3265
+ changes.push({ request: req, prevValue });
3266
+ }
3267
+ if (changes.length === 0) return;
3268
+ const nextDraft = (0, import_mutative2.create)(prevState, (draft) => {
3269
+ for (let i = 0; i < changes.length; i++) {
3270
+ const { request } = changes[i];
3271
+ setAtPathMutating(draft, request.fieldPath, request.nextValue);
3272
+ }
3273
+ });
3274
+ for (let i = 0; i < changes.length; i++) {
3275
+ const { request, prevValue } = changes[i];
3276
+ args.internals.txn.recordStatePatch(
3277
+ request.normalizedPatchPath,
3278
+ "trait-external-store",
3279
+ prevValue,
3280
+ request.nextValue,
3281
+ request.traitNodeId
3282
+ );
3283
+ }
3284
+ args.internals.txn.updateDraft(nextDraft);
3285
+ });
3286
+ const coordinator = {
3287
+ enqueue: (request) => import_effect15.Effect.gen(function* () {
3288
+ if (closed) return;
3289
+ pendingWrites.set(request.fieldPath, request);
3290
+ if (inFlight) return;
3291
+ inFlight = true;
3292
+ try {
3293
+ while (true) {
3294
+ const batch = drainPendingWrites();
3295
+ if (batch.length === 0) return;
3296
+ const commitPriority = batch.some((x) => x.commitPriority === "normal") ? "normal" : "low";
3297
+ const originName = batch.length === 1 ? batch[0].fieldPath : "externalStore:batched";
3298
+ yield* args.internals.txn.runWithStateTransaction(
3299
+ {
3300
+ kind: "trait-external-store",
3301
+ name: originName,
3302
+ details: {
3303
+ stateCommit: {
3304
+ priority: commitPriority
3305
+ }
3306
+ }
3307
+ },
3308
+ () => applyWritebackBatch(batch).pipe(import_effect15.Effect.asVoid)
3309
+ ).pipe(import_effect15.Effect.provide(args.env));
3310
+ }
3311
+ } finally {
3312
+ inFlight = false;
3313
+ }
3314
+ })
3315
+ };
3316
+ writebackCoordinatorByInternals.set(args.internals, coordinator);
3317
+ yield* import_effect15.Effect.addFinalizer(
3318
+ () => import_effect15.Effect.sync(() => {
3319
+ closed = true;
3320
+ pendingWrites.clear();
3321
+ })
3322
+ );
3323
+ return coordinator;
3324
+ });
3325
+ var resolveStore = (entry) => import_effect15.Effect.gen(function* () {
3326
+ const store = entry.meta?.store;
3327
+ const descriptor = getExternalStoreDescriptor(store);
3328
+ if (descriptor?.kind === "service") {
3329
+ const service = yield* import_effect15.Effect.service(descriptor.tag).pipe(import_effect15.Effect.orDie);
3330
+ return descriptor.map(service);
3331
+ }
3332
+ return store;
3333
+ });
3334
+ var installExternalStoreSync = (bound, step, entry) => import_effect15.Effect.gen(function* () {
3335
+ const fieldPath = step.targetFieldPath;
3336
+ if (!fieldPath) return;
3337
+ const env = yield* import_effect15.Effect.services();
3338
+ let internals;
3339
+ try {
3340
+ internals = getBoundInternals(bound);
3341
+ } catch {
3342
+ return;
3343
+ }
3344
+ const select = entry.meta?.select;
3345
+ const equals2 = entry.meta?.equals;
3346
+ const computeValue = (snapshot2) => isFn(select) ? select(snapshot2) : snapshot2;
3347
+ const isEqual = (a, b) => isFn(equals2) ? equals2(a, b) : Object.is(a, b);
3348
+ const traitLane = entry.meta?.priority;
3349
+ const rawStore = entry.meta?.store;
3350
+ const rawDescriptor = getExternalStoreDescriptor(rawStore);
3351
+ const makeScopedDescriptorStore = () => import_effect15.Effect.gen(function* () {
3352
+ if (rawDescriptor?.kind === "subscriptionRef") {
3353
+ let current = yield* import_effect15.Effect.provideService(rawDescriptor.ref.get, inSyncTransactionFiber, false);
3354
+ const listeners = /* @__PURE__ */ new Set();
3355
+ const notify = () => {
3356
+ for (const listener of listeners) {
3357
+ listener();
3358
+ }
3359
+ };
3360
+ const fiber2 = yield* import_effect15.Effect.forkDetach(
3361
+ import_effect15.Effect.provideService(import_effect15.Stream.runForEach(
3362
+ rawDescriptor.ref.changes,
3363
+ (value) => import_effect15.Effect.sync(() => {
3364
+ current = value;
3365
+ notify();
3366
+ })
3367
+ ).pipe(import_effect15.Effect.catchCause(() => import_effect15.Effect.void)), inSyncTransactionFiber, false),
3368
+ { startImmediately: true }
3369
+ );
3370
+ internals.lifecycle.registerDestroy(import_effect15.Fiber.interrupt(fiber2).pipe(import_effect15.Effect.asVoid), { name: `externalStore:${fieldPath}:subscriptionRef` });
3371
+ return {
3372
+ getSnapshot: () => current,
3373
+ subscribe: (listener) => {
3374
+ listeners.add(listener);
3375
+ return () => {
3376
+ listeners.delete(listener);
3377
+ };
3378
+ }
3379
+ };
3380
+ }
3381
+ if (rawDescriptor?.kind === "stream") {
3382
+ let current = rawDescriptor.initial;
3383
+ const listeners = /* @__PURE__ */ new Set();
3384
+ const notify = () => {
3385
+ for (const listener of listeners) {
3386
+ listener();
3387
+ }
3388
+ };
3389
+ const fiber2 = yield* import_effect15.Effect.forkDetach(
3390
+ import_effect15.Effect.provideService(import_effect15.Stream.runForEach(
3391
+ rawDescriptor.stream,
3392
+ (value) => import_effect15.Effect.sync(() => {
3393
+ current = value;
3394
+ notify();
3395
+ })
3396
+ ).pipe(import_effect15.Effect.catchCause(() => import_effect15.Effect.void)), inSyncTransactionFiber, false),
3397
+ { startImmediately: true }
3398
+ );
3399
+ internals.lifecycle.registerDestroy(import_effect15.Fiber.interrupt(fiber2).pipe(import_effect15.Effect.asVoid), { name: `externalStore:${fieldPath}:stream` });
3400
+ return {
3401
+ getSnapshot: () => current,
3402
+ subscribe: (listener) => {
3403
+ listeners.add(listener);
3404
+ return () => {
3405
+ listeners.delete(listener);
3406
+ };
3407
+ }
3408
+ };
3409
+ }
3410
+ return void 0;
3411
+ });
3412
+ if (rawDescriptor?.kind === "module") {
3413
+ const linkRuntimeOpt = yield* import_effect15.Effect.serviceOption(
3414
+ DeclarativeLinkRuntimeTag
3415
+ );
3416
+ if (import_effect15.Option.isNone(linkRuntimeOpt)) {
3417
+ return yield* import_effect15.Effect.die(new Error("[StateTrait.externalStore] Missing DeclarativeLinkRuntime service (073)."));
3418
+ }
3419
+ const module2 = rawDescriptor.module;
3420
+ const sourceRuntime = (() => {
3421
+ if (module2 && typeof module2 === "object") {
3422
+ const moduleId = module2.moduleId;
3423
+ const instanceId = module2.instanceId;
3424
+ const getState = module2.getState;
3425
+ if (typeof moduleId === "string" && moduleId.length > 0 && typeof instanceId === "string" && instanceId.length > 0 && getState) {
3426
+ return module2;
3427
+ }
3428
+ const tag = module2.tag;
3429
+ if (tag && import_effect15.ServiceMap.isKey(tag)) {
3430
+ return internals.imports.get(tag);
3431
+ }
3432
+ if (import_effect15.ServiceMap.isKey(module2)) {
3433
+ return internals.imports.get(module2);
3434
+ }
3435
+ }
3436
+ return void 0;
3437
+ })();
3438
+ if (!sourceRuntime) {
3439
+ return yield* import_effect15.Effect.die(new Error(`[StateTrait.externalStore] Module-as-Source store is unresolved for "${fieldPath}". Fix: include the source ModuleTag in module imports (moduleId=${rawDescriptor.moduleId}).`));
3440
+ }
3441
+ if (rawDescriptor.instanceId && rawDescriptor.instanceId !== sourceRuntime.instanceId) {
3442
+ return yield* import_effect15.Effect.die(new Error(`[StateTrait.externalStore] Module-as-Source instanceId mismatch for "${fieldPath}". descriptor.instanceId=${rawDescriptor.instanceId}, resolved.instanceId=${sourceRuntime.instanceId}`));
3443
+ }
3444
+ if (sourceRuntime.moduleId !== rawDescriptor.moduleId) {
3445
+ return yield* import_effect15.Effect.die(new Error(`[StateTrait.externalStore] Module-as-Source moduleId mismatch for "${fieldPath}". descriptor.moduleId=${rawDescriptor.moduleId}, resolved.moduleId=${sourceRuntime.moduleId}`));
3446
+ }
3447
+ const staticIr = rawDescriptor.readQuery.staticIr;
3448
+ const isRecognizableStatic = staticIr.lane === "static" && staticIr.readsDigest != null && staticIr.fallbackReason == null;
3449
+ if (!isRecognizableStatic) {
3450
+ yield* record({
3451
+ type: "diagnostic",
3452
+ moduleId: internals.moduleId,
3453
+ instanceId: internals.instanceId,
3454
+ code: "external_store::module_source_degraded",
3455
+ severity: "warning",
3456
+ message: "[StateTrait.externalStore] Module-as-Source selector is not fully IR-recognizable; falling back to module-topic edge (may reduce perf).",
3457
+ hint: "Fix: provide a static ReadQuery (ReadQuery.make) or annotate selector.fieldPaths to get a stable readsDigest; avoid dynamic lane.",
3458
+ kind: "module_as_source_degraded",
3459
+ trigger: {
3460
+ kind: "trait",
3461
+ name: "externalStore.moduleSource",
3462
+ details: {
3463
+ sourceModuleId: rawDescriptor.moduleId,
3464
+ selectorId: staticIr.selectorId,
3465
+ lane: staticIr.lane,
3466
+ fallbackReason: staticIr.fallbackReason,
3467
+ readsDigest: staticIr.readsDigest
3468
+ }
3469
+ }
3470
+ });
3471
+ }
3472
+ const moduleInstanceKey = `${sourceRuntime.moduleId}::${sourceRuntime.instanceId}`;
3473
+ const writeValue = (nextValue) => import_effect15.Effect.gen(function* () {
3474
+ const inTxn = yield* import_effect15.Effect.service(inSyncTransactionFiber).pipe(import_effect15.Effect.orDie);
3475
+ const body = import_effect15.Effect.gen(function* () {
3476
+ const prevState = yield* bound.state.read;
3477
+ const prevValue = getAtPath(prevState, fieldPath);
3478
+ if (isEqual(prevValue, nextValue)) {
3479
+ return;
3480
+ }
3481
+ const nextDraft = (0, import_mutative2.create)(prevState, (draft) => {
3482
+ setAtPathMutating(draft, fieldPath, nextValue);
3483
+ });
3484
+ const normalized = normalizeFieldPath(fieldPath) ?? [];
3485
+ internals.txn.recordStatePatch(normalized, "trait-external-store", prevValue, nextValue, step.id);
3486
+ internals.txn.updateDraft(nextDraft);
3487
+ });
3488
+ if (inTxn) {
3489
+ return yield* body;
3490
+ }
3491
+ const stateCommitPriority = traitLane === "nonUrgent" ? "low" : "normal";
3492
+ return yield* internals.txn.runWithStateTransaction(
3493
+ {
3494
+ kind: "trait-external-store",
3495
+ name: fieldPath,
3496
+ details: {
3497
+ stateCommit: {
3498
+ priority: stateCommitPriority
3499
+ }
3500
+ }
3501
+ },
3502
+ () => body.pipe(import_effect15.Effect.asVoid)
3503
+ );
3504
+ }).pipe(import_effect15.Effect.provideServices(env));
3505
+ const unregister = linkRuntimeOpt.value.registerModuleAsSourceLink({
3506
+ id: `${internals.instanceId}::externalStore:${step.id}`,
3507
+ sourceModuleInstanceKey: moduleInstanceKey,
3508
+ readQuery: rawDescriptor.readQuery,
3509
+ computeValue,
3510
+ equalsValue: isEqual,
3511
+ applyValue: writeValue
3512
+ });
3513
+ yield* import_effect15.Effect.addFinalizer(
3514
+ () => import_effect15.Effect.sync(() => {
3515
+ unregister();
3516
+ })
3517
+ );
3518
+ const initialState = yield* sourceRuntime.getState;
3519
+ const initialSelected = rawDescriptor.readQuery.select(initialState);
3520
+ yield* writeValue(computeValue(initialSelected));
3521
+ return;
3522
+ }
3523
+ const scopedDescriptorStore = yield* makeScopedDescriptorStore();
3524
+ const store = scopedDescriptorStore ?? (rawDescriptor?.kind === "service" ? yield* resolveStore(entry) : rawStore);
3525
+ if (!store || typeof store !== "object") {
3526
+ return yield* import_effect15.Effect.die(new Error(`[StateTrait.externalStore] Invalid store for "${fieldPath}". Expected { getSnapshot, subscribe }.`));
3527
+ }
3528
+ if (!isFn(store.getSnapshot) || !isFn(store.subscribe)) {
3529
+ return yield* import_effect15.Effect.die(new Error(`[StateTrait.externalStore] Invalid store for "${fieldPath}". Expected { getSnapshot, subscribe }.`));
3530
+ }
3531
+ let fused = false;
3532
+ let fuseCause;
3533
+ let fuseRecorded = false;
3534
+ let pending = false;
3535
+ let resume;
3536
+ const recordFuseDiagnostic = import_effect15.Effect.gen(function* () {
3537
+ if (fuseRecorded) return;
3538
+ fuseRecorded = true;
3539
+ const errorMessage = (() => {
3540
+ if (fuseCause instanceof Error) return fuseCause.message;
3541
+ if (typeof fuseCause === "string") return fuseCause;
3542
+ return "unknown";
3543
+ })();
3544
+ yield* record({
3545
+ type: "diagnostic",
3546
+ moduleId: internals.moduleId,
3547
+ instanceId: internals.instanceId,
3548
+ code: "external_store::snapshot_threw",
3549
+ severity: "warning",
3550
+ message: `[StateTrait.externalStore] store.getSnapshot() threw; trait is fused and will stop syncing for "${fieldPath}".`,
3551
+ hint: "Fix: ensure getSnapshot is synchronous and non-throwing; async resources should use StateTrait.source or ExternalStore.fromStream({ current/initial }).",
3552
+ kind: "external_store_fused:get_snapshot",
3553
+ trigger: {
3554
+ kind: "trait",
3555
+ name: "externalStore.getSnapshot",
3556
+ details: {
3557
+ fieldPath,
3558
+ traitId: step.id,
3559
+ storeKind: rawDescriptor?.kind ?? "raw",
3560
+ error: errorMessage
3561
+ }
3562
+ }
3563
+ });
3564
+ });
3565
+ const signal = () => {
3566
+ if (fused) return;
3567
+ if (resume) {
3568
+ const r = resume;
3569
+ pending = false;
3570
+ r();
3571
+ return;
3572
+ }
3573
+ pending = true;
3574
+ };
3575
+ const awaitSignal = () => {
3576
+ if (pending) {
3577
+ pending = false;
3578
+ return import_effect15.Effect.void;
3579
+ }
3580
+ return import_effect15.Effect.promise(
3581
+ (signal2) => new Promise((resolve) => {
3582
+ let done = false;
3583
+ const r = () => {
3584
+ if (done) return;
3585
+ done = true;
3586
+ resume = void 0;
3587
+ resolve();
3588
+ };
3589
+ resume = r;
3590
+ signal2.addEventListener(
3591
+ "abort",
3592
+ () => {
3593
+ if (resume === r) {
3594
+ resume = void 0;
3595
+ }
3596
+ },
3597
+ { once: true }
3598
+ );
3599
+ })
3600
+ );
3601
+ };
3602
+ const getSnapshotOrFuse = () => {
3603
+ try {
3604
+ return store.getSnapshot();
3605
+ } catch (err) {
3606
+ fused = true;
3607
+ fuseCause = err;
3608
+ return void 0;
3609
+ }
3610
+ };
3611
+ const readSnapshotOrFuse = import_effect15.Effect.provideService(import_effect15.Effect.sync(getSnapshotOrFuse), inSyncTransactionFiber, false);
3612
+ const before = yield* readSnapshotOrFuse;
3613
+ if (fused) {
3614
+ yield* recordFuseDiagnostic;
3615
+ return;
3616
+ }
3617
+ const unsubscribe = store.subscribe(signal);
3618
+ yield* import_effect15.Effect.addFinalizer(
3619
+ () => import_effect15.Effect.sync(() => {
3620
+ try {
3621
+ unsubscribe?.();
3622
+ } catch {
3623
+ }
3624
+ })
3625
+ );
3626
+ const after = yield* readSnapshotOrFuse;
3627
+ if (fused) {
3628
+ yield* recordFuseDiagnostic;
3629
+ return;
3630
+ }
3631
+ const coordinator = yield* getOrCreateExternalStoreWritebackCoordinator({ internals, bound, env });
3632
+ const normalizedPatchPath = normalizeFieldPath(fieldPath) ?? [];
3633
+ const commitPriority = traitLane === "nonUrgent" ? "low" : "normal";
3634
+ const writeValueSync = (nextValue) => import_effect15.Effect.gen(function* () {
3635
+ const inTxn = yield* import_effect15.Effect.service(inSyncTransactionFiber).pipe(import_effect15.Effect.orDie);
3636
+ const body = import_effect15.Effect.gen(function* () {
3637
+ const prevState = yield* bound.state.read;
3638
+ const prevValue = getAtPath(prevState, fieldPath);
3639
+ if (isEqual(prevValue, nextValue)) {
3640
+ return;
3641
+ }
3642
+ const nextDraft = (0, import_mutative2.create)(prevState, (draft) => {
3643
+ setAtPathMutating(draft, fieldPath, nextValue);
3644
+ });
3645
+ internals.txn.recordStatePatch(normalizedPatchPath, "trait-external-store", prevValue, nextValue, step.id);
3646
+ internals.txn.updateDraft(nextDraft);
3647
+ });
3648
+ if (inTxn) {
3649
+ return yield* body;
3650
+ }
3651
+ return yield* internals.txn.runWithStateTransaction(
3652
+ {
3653
+ kind: "trait-external-store",
3654
+ name: fieldPath,
3655
+ details: {
3656
+ stateCommit: {
3657
+ priority: commitPriority
3658
+ }
3659
+ }
3660
+ },
3661
+ () => body.pipe(import_effect15.Effect.asVoid)
3662
+ );
3663
+ }).pipe(import_effect15.Effect.provideServices(env));
3664
+ const enqueueWriteValue = (nextValue) => coordinator.enqueue({
3665
+ fieldPath,
3666
+ traitNodeId: step.id,
3667
+ normalizedPatchPath,
3668
+ nextValue,
3669
+ isEqual,
3670
+ commitPriority
3671
+ });
3672
+ yield* writeValueSync(computeValue(after));
3673
+ if (!isEqual(before, after)) {
3674
+ signal();
3675
+ }
3676
+ const fiber = yield* import_effect15.Effect.forkDetach(
3677
+ import_effect15.Effect.provideService(import_effect15.Effect.gen(function* () {
3678
+ while (true) {
3679
+ yield* awaitSignal();
3680
+ if (fused) return;
3681
+ const snapshot2 = yield* readSnapshotOrFuse;
3682
+ if (fused) {
3683
+ yield* recordFuseDiagnostic;
3684
+ return;
3685
+ }
3686
+ yield* enqueueWriteValue(computeValue(snapshot2));
3687
+ }
3688
+ }), inSyncTransactionFiber, false),
3689
+ { startImmediately: true }
3690
+ );
3691
+ internals.lifecycle.registerDestroy(import_effect15.Fiber.interrupt(fiber).pipe(import_effect15.Effect.asVoid), { name: `externalStore:${fieldPath}:writeback` });
3692
+ });
3693
+
3694
+ // src/internal/state-trait/meta-diagnostics.ts
3695
+ var import_effect17 = require("effect");
3696
+
3697
+ // src/internal/state-trait/converge-diagnostics.ts
3698
+ var import_effect16 = require("effect");
3699
+ var SchemaAST2 = __toESM(require("effect/SchemaAST"), 1);
3700
+ var onceKeysFallback = /* @__PURE__ */ new Set();
3701
+ var onceInRunSession2 = (key) => import_effect16.Effect.serviceOption(RunSessionTag).pipe(
3702
+ import_effect16.Effect.map((maybe) => {
3703
+ if (import_effect16.Option.isSome(maybe)) {
3704
+ return maybe.value.local.once(key);
3705
+ }
3706
+ if (onceKeysFallback.has(key)) return false;
3707
+ onceKeysFallback.add(key);
3708
+ return true;
3709
+ })
3710
+ );
3711
+
3712
+ // src/internal/state-trait/meta-diagnostics.ts
3713
+ var formatList2 = (items, limit = 6) => {
3714
+ if (!items || items.length === 0) return void 0;
3715
+ if (items.length <= limit) return items.join(", ");
3716
+ return `${items.slice(0, limit).join(", ")}, \u2026(+${items.length - limit})`;
3717
+ };
3718
+ var formatPart = (label, value) => {
3719
+ if (value === void 0) return void 0;
3720
+ return `${label}=${value}`;
3721
+ };
3722
+ var formatIssue = (issue) => {
3723
+ const r = issue.report;
3724
+ const parts = [];
3725
+ if (r.invalidInput) parts.push("invalidInput=true");
3726
+ const unknownKeys = formatList2(r.unknownKeys, 6);
3727
+ if (unknownKeys) {
3728
+ parts.push(
3729
+ `unknownKeys=[${unknownKeys}]${typeof r.unknownKeyCount === "number" && r.unknownKeyCount > r.unknownKeys.length ? ` total=${r.unknownKeyCount}` : ""}`
3730
+ );
3731
+ }
3732
+ const droppedKeys = formatList2(r.droppedKeys, 6);
3733
+ if (droppedKeys) parts.push(`droppedKeys=[${droppedKeys}]`);
3734
+ if (typeof r.droppedTagItems === "number" && r.droppedTagItems > 0) {
3735
+ parts.push(`droppedTagItems=${r.droppedTagItems}`);
3736
+ }
3737
+ const ignoredAnnotationKeys = formatList2(r.ignoredAnnotationKeys, 6);
3738
+ if (ignoredAnnotationKeys) {
3739
+ parts.push(
3740
+ `ignoredAnnotationKeys=[${ignoredAnnotationKeys}]${typeof r.ignoredAnnotationKeyCount === "number" && r.ignoredAnnotationKeyCount > r.ignoredAnnotationKeys.length ? ` total=${r.ignoredAnnotationKeyCount}` : ""}`
3741
+ );
3742
+ }
3743
+ const droppedAnnotationKeys = formatList2(r.droppedAnnotationKeys, 6);
3744
+ if (droppedAnnotationKeys) {
3745
+ parts.push(
3746
+ `droppedAnnotationKeys=[${droppedAnnotationKeys}]${typeof r.droppedAnnotationKeyCount === "number" && r.droppedAnnotationKeyCount > r.droppedAnnotationKeys.length ? ` total=${r.droppedAnnotationKeyCount}` : ""}`
3747
+ );
3748
+ }
3749
+ const droppedValues = formatPart("droppedAnnotationValues", r.droppedAnnotationValues);
3750
+ if (droppedValues) parts.push(droppedValues);
3751
+ const nonSerializable = formatPart("nonSerializable", r.droppedAnnotationNonSerializable);
3752
+ const depthExceeded = formatPart("depthExceeded", r.droppedAnnotationDepthExceeded);
3753
+ const nonFiniteNumber = formatPart("nonFiniteNumber", r.droppedAnnotationNonFiniteNumber);
3754
+ const reasons = [nonSerializable, depthExceeded, nonFiniteNumber].filter((x) => x !== void 0);
3755
+ if (reasons.length > 0) parts.push(`reasons={${reasons.join(", ")}}`);
3756
+ return `[${issue.origin}] ${parts.join(" ")}`;
3757
+ };
3758
+ var collectNodeMetaIssues = (program) => {
3759
+ const spec = program.spec;
3760
+ if (!spec || typeof spec !== "object") return [];
3761
+ const isNode = (value) => typeof value === "object" && value !== null && value._tag === "StateTraitNode";
3762
+ const isList = (value) => typeof value === "object" && value !== null && value._tag === "StateTraitList";
3763
+ const issues = [];
3764
+ const add = (origin, meta) => {
3765
+ const { report } = sanitizeWithReport(meta);
3766
+ if (report) issues.push({ origin, report });
3767
+ };
3768
+ for (const key of Object.keys(spec)) {
3769
+ const raw = spec[key];
3770
+ if (!raw) continue;
3771
+ if (isList(raw)) {
3772
+ if (raw.item && isNode(raw.item) && raw.item.meta !== void 0) {
3773
+ add(`node:${key}[]`, raw.item.meta);
3774
+ }
3775
+ if (raw.list && isNode(raw.list) && raw.list.meta !== void 0) {
3776
+ add(`node:${key}`, raw.list.meta);
3777
+ }
3778
+ continue;
3779
+ }
3780
+ if (isNode(raw)) {
3781
+ if (raw.meta === void 0) continue;
3782
+ add(`node:${key === "$root" ? "$root" : key}`, raw.meta);
3783
+ continue;
3784
+ }
3785
+ }
3786
+ return issues;
2512
3787
  };
3788
+ var collectEntryMetaIssues = (program) => {
3789
+ const issues = [];
3790
+ for (const entry of program.entries) {
3791
+ if (entry.kind !== "source" && entry.kind !== "externalStore") continue;
3792
+ const rawMeta = entry.meta?.meta;
3793
+ if (rawMeta === void 0) continue;
3794
+ const origin = entry.kind === "source" ? `source:${entry.fieldPath}` : `externalStore:${entry.fieldPath}`;
3795
+ const { report } = sanitizeWithReport(rawMeta);
3796
+ if (report) issues.push({ origin, report });
3797
+ }
3798
+ return issues;
3799
+ };
3800
+ var emitMetaSanitizeDiagnostics = (program, ctx) => import_effect17.Effect.gen(function* () {
3801
+ if (!isDevEnv()) return;
3802
+ const level = yield* import_effect17.Effect.service(currentDiagnosticsLevel).pipe(import_effect17.Effect.orDie);
3803
+ if (level === "off") return;
3804
+ const moduleId = ctx.moduleId ?? "unknown";
3805
+ const shouldEmit = yield* onceInRunSession2(`meta_sanitize:${moduleId}`);
3806
+ if (!shouldEmit) return;
3807
+ const issues = [...collectNodeMetaIssues(program), ...collectEntryMetaIssues(program)];
3808
+ if (issues.length === 0) return;
3809
+ const limit = level === "light" || level === "sampled" ? 8 : 24;
3810
+ const lines = issues.slice(0, limit).map(formatIssue);
3811
+ if (issues.length > limit) {
3812
+ lines.push(`\u2026(+${issues.length - limit})`);
3813
+ }
3814
+ yield* record({
3815
+ type: "diagnostic",
3816
+ moduleId: ctx.moduleId,
3817
+ instanceId: ctx.instanceId,
3818
+ code: "state_trait::meta_sanitized",
3819
+ severity: "warning",
3820
+ message: `[meta] TraitMeta contains non-exportable fields/values and will be sanitized (total ${issues.length}):
3821
+ ${lines.join("\n")}`,
3822
+ hint: "TraitMeta is export-only (Devtools/Static IR) and MUST be JsonValue. Use `annotations` with `x-*` keys for extension hints; avoid closures/functions/Effect/Fiber/Tag/DOM/BigInt/circular refs. See specs/016 and docs/ssot/platform/contracts/03-control-surface-manifest.md.",
3823
+ kind: "meta_sanitized"
3824
+ });
3825
+ });
2513
3826
 
2514
3827
  // src/internal/state-trait/install.ts
2515
3828
  var buildEntryIndex = (entries) => {
@@ -2522,32 +3835,41 @@ var buildEntryIndex = (entries) => {
2522
3835
  return index;
2523
3836
  };
2524
3837
  var install = (bound, program) => {
2525
- try {
2526
- const internals = getBoundInternals(bound);
2527
- internals.traits.registerStateTraitProgram(program, {
2528
- bumpReason: "logic_installed"
2529
- });
2530
- } catch {
2531
- }
2532
- const entryIndex = buildEntryIndex(program.entries);
2533
- const installStep = (step) => {
2534
- if (!step.targetFieldPath) {
2535
- return import_effect11.Effect.void;
2536
- }
2537
- if (step.kind !== "source-refresh") {
2538
- return import_effect11.Effect.void;
2539
- }
2540
- const candidates = entryIndex.get(step.targetFieldPath);
2541
- if (!candidates || candidates.length === 0) {
2542
- return import_effect11.Effect.void;
3838
+ return import_effect18.Effect.gen(function* () {
3839
+ let internals;
3840
+ try {
3841
+ internals = getBoundInternals(bound);
3842
+ internals.traits.registerStateTraitProgram(program, {
3843
+ bumpReason: "logic_installed"
3844
+ });
3845
+ } catch {
2543
3846
  }
2544
- const entry = candidates.find((e) => e.kind === "source");
2545
- if (!entry) {
2546
- return import_effect11.Effect.void;
3847
+ if (internals) {
3848
+ yield* emitMetaSanitizeDiagnostics(program, {
3849
+ moduleId: internals.moduleId,
3850
+ instanceId: internals.instanceId
3851
+ });
2547
3852
  }
2548
- return installSourceRefresh(bound, step, entry);
2549
- };
2550
- return import_effect11.Effect.forEach(program.plan.steps, (step) => installStep(step)).pipe(import_effect11.Effect.asVoid);
3853
+ const entryIndex = buildEntryIndex(program.entries);
3854
+ const installStep = (step) => {
3855
+ if (!step.targetFieldPath) {
3856
+ return import_effect18.Effect.void;
3857
+ }
3858
+ if (step.kind !== "source-refresh" && step.kind !== "external-store-sync") {
3859
+ return import_effect18.Effect.void;
3860
+ }
3861
+ const candidates = entryIndex.get(step.targetFieldPath);
3862
+ if (!candidates || candidates.length === 0) {
3863
+ return import_effect18.Effect.void;
3864
+ }
3865
+ const entry = step.kind === "source-refresh" ? candidates.find((e) => e.kind === "source") : candidates.find((e) => e.kind === "externalStore");
3866
+ if (!entry) {
3867
+ return import_effect18.Effect.void;
3868
+ }
3869
+ return step.kind === "source-refresh" ? installSourceRefresh(bound, step, entry) : installExternalStoreSync(bound, step, entry);
3870
+ };
3871
+ yield* import_effect18.Effect.forEach(program.plan.steps, (step) => installStep(step)).pipe(import_effect18.Effect.asVoid);
3872
+ }).pipe(import_effect18.Effect.asVoid);
2551
3873
  };
2552
3874
 
2553
3875
  // src/internal/state-trait/ir.ts
@@ -2569,6 +3891,8 @@ var toNodeKind = (step) => {
2569
3891
  return "link";
2570
3892
  case "source-refresh":
2571
3893
  return "source";
3894
+ case "external-store-sync":
3895
+ return "externalStore";
2572
3896
  case "check-validate":
2573
3897
  return "check";
2574
3898
  }
@@ -2593,6 +3917,9 @@ var getReadsForEntry = (entry) => {
2593
3917
  const from2 = entry.meta.from;
2594
3918
  return from2 ? [from2] : [];
2595
3919
  }
3920
+ if (entry.kind === "externalStore") {
3921
+ return [];
3922
+ }
2596
3923
  if (entry.kind === "check") {
2597
3924
  const rules = entry.meta?.rules ?? {};
2598
3925
  const out = [];
@@ -2640,11 +3967,40 @@ var exportStaticIr = (params) => {
2640
3967
  const write = normalizeFieldPath2(target);
2641
3968
  const writes = write ? [write] : [];
2642
3969
  const meta = target ? metaByField.get(target) : void 0;
3970
+ const externalStorePolicy = () => {
3971
+ if (kind !== "externalStore") return void 0;
3972
+ if (!entry || entry.kind !== "externalStore") return void 0;
3973
+ const descriptor = getExternalStoreDescriptor(entry.meta.store);
3974
+ const storeId = descriptor?.storeId;
3975
+ const priorityRaw = entry.meta?.priority;
3976
+ const lane = priorityRaw === "nonUrgent" ? "nonUrgent" : "urgent";
3977
+ const meta2 = sanitize(entry.meta.meta);
3978
+ const source2 = descriptor?.kind === "module" ? {
3979
+ kind: "module",
3980
+ storeId,
3981
+ moduleId: descriptor.moduleId,
3982
+ ...descriptor.instanceId ? { instanceKey: descriptor.instanceId } : {},
3983
+ selectorId: descriptor.readQuery.staticIr.selectorId,
3984
+ readsDigest: descriptor.readQuery.staticIr.readsDigest,
3985
+ fallbackReason: descriptor.readQuery.staticIr.fallbackReason
3986
+ } : descriptor ? { kind: "external", storeId } : { kind: "external", storeId: "unknown" };
3987
+ const coalesceWindowMs = entry.meta?.coalesceWindowMs;
3988
+ return {
3989
+ traitId: step.id,
3990
+ storeId: storeId ?? "unknown",
3991
+ source: source2,
3992
+ ownership: "external-owned",
3993
+ lane,
3994
+ ...typeof coalesceWindowMs === "number" && Number.isFinite(coalesceWindowMs) && coalesceWindowMs > 0 ? { coalesceWindowMs } : {},
3995
+ ...meta2 ? { meta: meta2 } : {}
3996
+ };
3997
+ };
2643
3998
  const base2 = {
2644
3999
  nodeId: step.id,
2645
4000
  kind,
2646
4001
  reads,
2647
4002
  writes: kind === "check" ? [] : writes,
4003
+ ...kind === "externalStore" ? { policy: externalStorePolicy() } : {},
2648
4004
  meta
2649
4005
  };
2650
4006
  if (kind !== "check" && target && !write) {
@@ -2709,6 +4065,11 @@ var source = (input) => {
2709
4065
  meta: { ...input, key }
2710
4066
  };
2711
4067
  };
4068
+ var externalStore = (input) => ({
4069
+ fieldPath: void 0,
4070
+ kind: "externalStore",
4071
+ meta: input
4072
+ });
2712
4073
  var link = (meta) => ({
2713
4074
  fieldPath: void 0,
2714
4075
  kind: "link",
@@ -2727,6 +4088,7 @@ var exportStaticIr2 = (program, moduleId, options) => exportStaticIr({
2727
4088
  build,
2728
4089
  computed,
2729
4090
  exportStaticIr,
4091
+ externalStore,
2730
4092
  from,
2731
4093
  install,
2732
4094
  link,