@blac/core 2.0.20 → 2.0.22

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 (295) hide show
  1. package/README.md +19 -29
  2. package/dist/{StateContainerRegistry-CSNm2Ws5.cjs → StateContainerRegistry-141uHhtF.cjs} +300 -397
  3. package/dist/StateContainerRegistry-141uHhtF.cjs.map +1 -0
  4. package/dist/{StateContainerRegistry-DVIBTxGZ.js → StateContainerRegistry-BH7aOMWV.js} +299 -406
  5. package/dist/StateContainerRegistry-BH7aOMWV.js.map +1 -0
  6. package/dist/{StateContainerRegistry-Dj77cok9.js → StateContainerRegistry-BsH_s0pJ.js} +303 -413
  7. package/dist/StateContainerRegistry-BsH_s0pJ.js.map +1 -0
  8. package/dist/{StateContainerRegistry-lIwo-0m3.cjs → StateContainerRegistry-CBLeHObO.cjs} +326 -418
  9. package/dist/StateContainerRegistry-CBLeHObO.cjs.map +1 -0
  10. package/dist/{StateContainerRegistry-D9BIRjwv.cjs → StateContainerRegistry-MkT0W4C2.cjs} +322 -411
  11. package/dist/StateContainerRegistry-MkT0W4C2.cjs.map +1 -0
  12. package/dist/{StateContainerRegistry-CvBOhAT2.js → StateContainerRegistry-vWgsD-RP.js} +277 -392
  13. package/dist/StateContainerRegistry-vWgsD-RP.js.map +1 -0
  14. package/dist/config.d.cts +2 -2
  15. package/dist/config.d.ts +2 -2
  16. package/dist/constants.d.cts +4 -20
  17. package/dist/constants.d.ts +4 -20
  18. package/dist/core/Cubit.d.ts +14 -10
  19. package/dist/core/StateContainer.d.ts +68 -8
  20. package/dist/core/StateContainerRegistry.d.ts +100 -19
  21. package/dist/core/meta.d.ts +34 -47
  22. package/dist/core/symbols.d.ts +18 -1
  23. package/dist/decorators/blac.d.ts +28 -26
  24. package/dist/{ensure-BKdq5xsY.cjs → ensure-BjhbDW8Z.cjs} +223 -40
  25. package/dist/ensure-BjhbDW8Z.cjs.map +1 -0
  26. package/dist/ensure-BnVyd6s4.js +730 -0
  27. package/dist/ensure-BnVyd6s4.js.map +1 -0
  28. package/dist/ensure-CneMkpbI.js +731 -0
  29. package/dist/ensure-CneMkpbI.js.map +1 -0
  30. package/dist/{ensure-CQimeD0I.cjs → ensure-D15vGnk5.cjs} +348 -124
  31. package/dist/ensure-D15vGnk5.cjs.map +1 -0
  32. package/dist/{ensure-B1dEDsZV.cjs → ensure-D3w6YGp9.cjs} +349 -124
  33. package/dist/ensure-D3w6YGp9.cjs.map +1 -0
  34. package/dist/{ensure-B2DYCbbI.cjs → ensure-ORVw-WRE.cjs} +214 -39
  35. package/dist/ensure-ORVw-WRE.cjs.map +1 -0
  36. package/dist/{ensure-B59ri8oo.js → ensure-dsqWhIuO.js} +192 -39
  37. package/dist/ensure-dsqWhIuO.js.map +1 -0
  38. package/dist/{ensure-BSJHkUNX.js → ensure-k-6q7O25.js} +183 -38
  39. package/dist/ensure-k-6q7O25.js.map +1 -0
  40. package/dist/index.cjs +212 -32
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +4 -6
  43. package/dist/index.d.ts +4 -6
  44. package/dist/index.js +192 -12
  45. package/dist/index.js.map +1 -1
  46. package/dist/plugin/BlacPlugin.d.ts +14 -0
  47. package/dist/plugin/PluginManager.d.ts +21 -11
  48. package/dist/plugins.cjs +403 -3
  49. package/dist/plugins.cjs.map +1 -0
  50. package/dist/plugins.d.cts +6 -2
  51. package/dist/plugins.d.ts +6 -2
  52. package/dist/plugins.js +401 -1
  53. package/dist/plugins.js.map +1 -0
  54. package/dist/registry/acquire.d.ts +2 -2
  55. package/dist/registry/config.d.ts +9 -0
  56. package/dist/registry/management.d.ts +3 -0
  57. package/dist/registry/queries.d.ts +15 -0
  58. package/dist/registry/release.d.ts +3 -3
  59. package/dist/testing.cjs +13 -15
  60. package/dist/testing.cjs.map +1 -1
  61. package/dist/testing.d.cts +1 -1
  62. package/dist/testing.d.ts +1 -1
  63. package/dist/testing.js +2 -4
  64. package/dist/testing.js.map +1 -1
  65. package/dist/types/branded.d.ts +3 -3
  66. package/dist/types/utilities.d.ts +45 -18
  67. package/dist/utils/static-props.d.ts +25 -1
  68. package/dist/utils/structural-key.d.ts +0 -7
  69. package/dist/watch/index.d.ts +1 -1
  70. package/dist/watch/watch.d.ts +22 -3
  71. package/package.json +16 -55
  72. package/dist/StateContainerRegistry-4Ljd9EJx.js +0 -1018
  73. package/dist/StateContainerRegistry-4Ljd9EJx.js.map +0 -1
  74. package/dist/StateContainerRegistry-8zNFMAf7.js +0 -1067
  75. package/dist/StateContainerRegistry-8zNFMAf7.js.map +0 -1
  76. package/dist/StateContainerRegistry-B1GYx9Xo.js +0 -975
  77. package/dist/StateContainerRegistry-B1GYx9Xo.js.map +0 -1
  78. package/dist/StateContainerRegistry-B_ViBLvJ.js +0 -975
  79. package/dist/StateContainerRegistry-B_ViBLvJ.js.map +0 -1
  80. package/dist/StateContainerRegistry-Bx2ly-ba.cjs +0 -1162
  81. package/dist/StateContainerRegistry-Bx2ly-ba.cjs.map +0 -1
  82. package/dist/StateContainerRegistry-C0dCNlTF.js +0 -1005
  83. package/dist/StateContainerRegistry-C0dCNlTF.js.map +0 -1
  84. package/dist/StateContainerRegistry-CEWpc1bj.cjs +0 -1113
  85. package/dist/StateContainerRegistry-CEWpc1bj.cjs.map +0 -1
  86. package/dist/StateContainerRegistry-CS18y4au.cjs +0 -1163
  87. package/dist/StateContainerRegistry-CS18y4au.cjs.map +0 -1
  88. package/dist/StateContainerRegistry-CSNm2Ws5.cjs.map +0 -1
  89. package/dist/StateContainerRegistry-CchRjnjX.cjs +0 -1094
  90. package/dist/StateContainerRegistry-CchRjnjX.cjs.map +0 -1
  91. package/dist/StateContainerRegistry-CvBOhAT2.js.map +0 -1
  92. package/dist/StateContainerRegistry-D8nu7Z0T.js +0 -1068
  93. package/dist/StateContainerRegistry-D8nu7Z0T.js.map +0 -1
  94. package/dist/StateContainerRegistry-D9BIRjwv.cjs.map +0 -1
  95. package/dist/StateContainerRegistry-DJQqLrli.cjs +0 -1046
  96. package/dist/StateContainerRegistry-DJQqLrli.cjs.map +0 -1
  97. package/dist/StateContainerRegistry-DVIBTxGZ.js.map +0 -1
  98. package/dist/StateContainerRegistry-Dj77cok9.js.map +0 -1
  99. package/dist/StateContainerRegistry-FWKzPfS-.cjs +0 -1046
  100. package/dist/StateContainerRegistry-FWKzPfS-.cjs.map +0 -1
  101. package/dist/StateContainerRegistry-lIwo-0m3.cjs.map +0 -1
  102. package/dist/acquire-B1LYXSGj.js +0 -35
  103. package/dist/acquire-B1LYXSGj.js.map +0 -1
  104. package/dist/acquire-B1Wuqla6.cjs +0 -46
  105. package/dist/acquire-B1Wuqla6.cjs.map +0 -1
  106. package/dist/acquire-BJ3xUEmh.cjs +0 -46
  107. package/dist/acquire-BJ3xUEmh.cjs.map +0 -1
  108. package/dist/acquire-BP-ZfUH2.js +0 -35
  109. package/dist/acquire-BP-ZfUH2.js.map +0 -1
  110. package/dist/acquire-BRIJVJaA.js +0 -35
  111. package/dist/acquire-BRIJVJaA.js.map +0 -1
  112. package/dist/acquire-BZIs6tpN.cjs +0 -46
  113. package/dist/acquire-BZIs6tpN.cjs.map +0 -1
  114. package/dist/acquire-B_p1fNEh.cjs +0 -46
  115. package/dist/acquire-B_p1fNEh.cjs.map +0 -1
  116. package/dist/acquire-BdsVZBSe.js +0 -35
  117. package/dist/acquire-BdsVZBSe.js.map +0 -1
  118. package/dist/acquire-C3nOb3XR.cjs +0 -46
  119. package/dist/acquire-C3nOb3XR.cjs.map +0 -1
  120. package/dist/acquire-C4WAS13G.cjs +0 -46
  121. package/dist/acquire-C4WAS13G.cjs.map +0 -1
  122. package/dist/acquire-C7beGI55.cjs +0 -46
  123. package/dist/acquire-C7beGI55.cjs.map +0 -1
  124. package/dist/acquire-CbMz7gWs.cjs +0 -46
  125. package/dist/acquire-CbMz7gWs.cjs.map +0 -1
  126. package/dist/acquire-CwB083au.js +0 -35
  127. package/dist/acquire-CwB083au.js.map +0 -1
  128. package/dist/acquire-DHEOEVcj.cjs +0 -46
  129. package/dist/acquire-DHEOEVcj.cjs.map +0 -1
  130. package/dist/acquire-DXEQDZGr.js +0 -35
  131. package/dist/acquire-DXEQDZGr.js.map +0 -1
  132. package/dist/acquire-Dg-uXwjF.js +0 -35
  133. package/dist/acquire-Dg-uXwjF.js.map +0 -1
  134. package/dist/acquire-Don7499S.js +0 -35
  135. package/dist/acquire-Don7499S.js.map +0 -1
  136. package/dist/acquire-G8aB3GAx.js +0 -35
  137. package/dist/acquire-G8aB3GAx.js.map +0 -1
  138. package/dist/branded-BybA0_xw.cjs +0 -18
  139. package/dist/branded-BybA0_xw.cjs.map +0 -1
  140. package/dist/branded-DkbUzncc.js +0 -13
  141. package/dist/branded-DkbUzncc.js.map +0 -1
  142. package/dist/config-8pyOC5gv.js +0 -16
  143. package/dist/config-8pyOC5gv.js.map +0 -1
  144. package/dist/config-B1l8ZGlU.cjs +0 -32
  145. package/dist/config-B1l8ZGlU.cjs.map +0 -1
  146. package/dist/config-C7Ktkjh2.cjs +0 -32
  147. package/dist/config-C7Ktkjh2.cjs.map +0 -1
  148. package/dist/config-COT4Xkbc.js +0 -16
  149. package/dist/config-COT4Xkbc.js.map +0 -1
  150. package/dist/config-CzcoAvBo.js +0 -16
  151. package/dist/config-CzcoAvBo.js.map +0 -1
  152. package/dist/config-D6BoWWPv.js +0 -16
  153. package/dist/config-D6BoWWPv.js.map +0 -1
  154. package/dist/config-DOO82lbZ.js +0 -16
  155. package/dist/config-DOO82lbZ.js.map +0 -1
  156. package/dist/config-DVM_ESQt.js +0 -16
  157. package/dist/config-DVM_ESQt.js.map +0 -1
  158. package/dist/config-DVMnlHLv.cjs +0 -32
  159. package/dist/config-DVMnlHLv.cjs.map +0 -1
  160. package/dist/config-DWUq7zEQ.cjs +0 -32
  161. package/dist/config-DWUq7zEQ.cjs.map +0 -1
  162. package/dist/config-DXI3kzmA.js +0 -16
  163. package/dist/config-DXI3kzmA.js.map +0 -1
  164. package/dist/config-Dk1FxfXj.js +0 -16
  165. package/dist/config-Dk1FxfXj.js.map +0 -1
  166. package/dist/config-b2z51Y_C.cjs +0 -32
  167. package/dist/config-b2z51Y_C.cjs.map +0 -1
  168. package/dist/config-buwpT7l3.js +0 -16
  169. package/dist/config-buwpT7l3.js.map +0 -1
  170. package/dist/config-cwaTn5oy.cjs +0 -32
  171. package/dist/config-cwaTn5oy.cjs.map +0 -1
  172. package/dist/config-d9_U58ef.cjs +0 -32
  173. package/dist/config-d9_U58ef.cjs.map +0 -1
  174. package/dist/config-hWTayX76.cjs +0 -32
  175. package/dist/config-hWTayX76.cjs.map +0 -1
  176. package/dist/config-sCPKPYxZ.cjs +0 -32
  177. package/dist/config-sCPKPYxZ.cjs.map +0 -1
  178. package/dist/debug.cjs +0 -14
  179. package/dist/debug.d.cts +0 -34
  180. package/dist/debug.d.ts +0 -34
  181. package/dist/debug.js +0 -4
  182. package/dist/ensure-B1dEDsZV.cjs.map +0 -1
  183. package/dist/ensure-B2DYCbbI.cjs.map +0 -1
  184. package/dist/ensure-B59ri8oo.js.map +0 -1
  185. package/dist/ensure-B9oOqpOB.cjs +0 -558
  186. package/dist/ensure-B9oOqpOB.cjs.map +0 -1
  187. package/dist/ensure-BKdq5xsY.cjs.map +0 -1
  188. package/dist/ensure-BSJHkUNX.js.map +0 -1
  189. package/dist/ensure-BfYnvAsI.js +0 -709
  190. package/dist/ensure-BfYnvAsI.js.map +0 -1
  191. package/dist/ensure-Bm91o37h.js +0 -536
  192. package/dist/ensure-Bm91o37h.js.map +0 -1
  193. package/dist/ensure-C1a8IFWy.js +0 -535
  194. package/dist/ensure-C1a8IFWy.js.map +0 -1
  195. package/dist/ensure-CLQEx0Nn.cjs +0 -528
  196. package/dist/ensure-CLQEx0Nn.cjs.map +0 -1
  197. package/dist/ensure-CPMiGvov.js +0 -493
  198. package/dist/ensure-CPMiGvov.js.map +0 -1
  199. package/dist/ensure-CQimeD0I.cjs.map +0 -1
  200. package/dist/ensure-DEXSmA-N.js +0 -526
  201. package/dist/ensure-DEXSmA-N.js.map +0 -1
  202. package/dist/ensure-DTTTd2h8.js +0 -536
  203. package/dist/ensure-DTTTd2h8.js.map +0 -1
  204. package/dist/ensure-Dx86f80B.cjs +0 -567
  205. package/dist/ensure-Dx86f80B.cjs.map +0 -1
  206. package/dist/ensure-DzqGej43.js +0 -526
  207. package/dist/ensure-DzqGej43.js.map +0 -1
  208. package/dist/ensure-VuiNPccZ.cjs +0 -559
  209. package/dist/ensure-VuiNPccZ.cjs.map +0 -1
  210. package/dist/ensure-_Oh8XPm4.cjs +0 -732
  211. package/dist/ensure-_Oh8XPm4.cjs.map +0 -1
  212. package/dist/ensure-fsQMjaQL.cjs +0 -567
  213. package/dist/ensure-fsQMjaQL.cjs.map +0 -1
  214. package/dist/ensure-vxAGa2v3.js +0 -536
  215. package/dist/ensure-vxAGa2v3.js.map +0 -1
  216. package/dist/management-14vsHr4t.cjs +0 -85
  217. package/dist/management-14vsHr4t.cjs.map +0 -1
  218. package/dist/management-444tdCBG.js +0 -38
  219. package/dist/management-444tdCBG.js.map +0 -1
  220. package/dist/management-7jLjVHJd.js +0 -38
  221. package/dist/management-7jLjVHJd.js.map +0 -1
  222. package/dist/management-AFuqQEwz.js +0 -38
  223. package/dist/management-AFuqQEwz.js.map +0 -1
  224. package/dist/management-BodVLAfJ.cjs +0 -85
  225. package/dist/management-BodVLAfJ.cjs.map +0 -1
  226. package/dist/management-BqGBdL01.js +0 -38
  227. package/dist/management-BqGBdL01.js.map +0 -1
  228. package/dist/management-BvUAjril.js +0 -38
  229. package/dist/management-BvUAjril.js.map +0 -1
  230. package/dist/management-C-WGcwPD.js +0 -38
  231. package/dist/management-C-WGcwPD.js.map +0 -1
  232. package/dist/management-C2wv4vGS.cjs +0 -85
  233. package/dist/management-C2wv4vGS.cjs.map +0 -1
  234. package/dist/management-D2pjr38g.js +0 -38
  235. package/dist/management-D2pjr38g.js.map +0 -1
  236. package/dist/management-D5WsZoTV.js +0 -38
  237. package/dist/management-D5WsZoTV.js.map +0 -1
  238. package/dist/management-DAV9sN-k.cjs +0 -85
  239. package/dist/management-DAV9sN-k.cjs.map +0 -1
  240. package/dist/management-Df7Y2sF1.cjs +0 -85
  241. package/dist/management-Df7Y2sF1.cjs.map +0 -1
  242. package/dist/management-DwO0nBzL.cjs +0 -85
  243. package/dist/management-DwO0nBzL.cjs.map +0 -1
  244. package/dist/management-GcnNJjnm.cjs +0 -85
  245. package/dist/management-GcnNJjnm.cjs.map +0 -1
  246. package/dist/management-P_Vi_cvw.js +0 -38
  247. package/dist/management-P_Vi_cvw.js.map +0 -1
  248. package/dist/management-QWLpbXlW.cjs +0 -85
  249. package/dist/management-QWLpbXlW.cjs.map +0 -1
  250. package/dist/management-iE4x6IQY.cjs +0 -85
  251. package/dist/management-iE4x6IQY.cjs.map +0 -1
  252. package/dist/types.cjs +0 -3
  253. package/dist/types.d.cts +0 -8
  254. package/dist/types.d.ts +0 -8
  255. package/dist/types.js +0 -2
  256. package/dist/watch-B0pUfh-v.cjs +0 -119
  257. package/dist/watch-B0pUfh-v.cjs.map +0 -1
  258. package/dist/watch-B91opmva.cjs +0 -70
  259. package/dist/watch-B91opmva.cjs.map +0 -1
  260. package/dist/watch-BHfCtbn1.cjs +0 -119
  261. package/dist/watch-BHfCtbn1.cjs.map +0 -1
  262. package/dist/watch-BmC-Tyqg.js +0 -59
  263. package/dist/watch-BmC-Tyqg.js.map +0 -1
  264. package/dist/watch-Bx0y-Kcc.js +0 -108
  265. package/dist/watch-Bx0y-Kcc.js.map +0 -1
  266. package/dist/watch-CKWt788i.cjs +0 -70
  267. package/dist/watch-CKWt788i.cjs.map +0 -1
  268. package/dist/watch-CfrSSrRY.js +0 -59
  269. package/dist/watch-CfrSSrRY.js.map +0 -1
  270. package/dist/watch-Cnh3PtQA.cjs +0 -70
  271. package/dist/watch-Cnh3PtQA.cjs.map +0 -1
  272. package/dist/watch-D01MdwKy.js +0 -108
  273. package/dist/watch-D01MdwKy.js.map +0 -1
  274. package/dist/watch-D8hwbFU1.js +0 -59
  275. package/dist/watch-D8hwbFU1.js.map +0 -1
  276. package/dist/watch-DPVUwPUY.js +0 -59
  277. package/dist/watch-DPVUwPUY.js.map +0 -1
  278. package/dist/watch-DVmvZBMD.cjs +0 -70
  279. package/dist/watch-DVmvZBMD.cjs.map +0 -1
  280. package/dist/watch-DkDGmGAx.cjs +0 -119
  281. package/dist/watch-DkDGmGAx.cjs.map +0 -1
  282. package/dist/watch-DttHqefn.js +0 -108
  283. package/dist/watch-DttHqefn.js.map +0 -1
  284. package/dist/watch-DxdIZjpt.cjs +0 -119
  285. package/dist/watch-DxdIZjpt.cjs.map +0 -1
  286. package/dist/watch-DztcJuUy.cjs +0 -119
  287. package/dist/watch-DztcJuUy.cjs.map +0 -1
  288. package/dist/watch-IrR8G28N.js +0 -108
  289. package/dist/watch-IrR8G28N.js.map +0 -1
  290. package/dist/watch-entry.cjs +0 -4
  291. package/dist/watch-entry.d.cts +0 -24
  292. package/dist/watch-entry.d.ts +0 -24
  293. package/dist/watch-entry.js +0 -2
  294. package/dist/watch-hx0r92Zc.js +0 -108
  295. package/dist/watch-hx0r92Zc.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-D3w6YGp9.cjs","names":["globalRegistry","#c","getBlacName","#hydration","StructuralContainer","APPLY_DEPS","IS_DEV","REMOVE_DEPS_OWNER","ON_DISPOSE","SET_ACTIVE","WITH_TRACKED_STATE","getBlacConfig","getBlacName","ALL_PATHS","INIT_CONFIG","getClassEquality"],"sources":["../src/utils/idGenerator.ts","../src/registry/config.ts","../src/core/meta.ts","../src/core/StateContainer.ts","../src/core/Cubit.ts","../src/registry/acquire.ts","../src/registry/ensure.ts"],"sourcesContent":["/**\n * Centralized ID Generation\n *\n * Provides consistent, collision-resistant ID generation for all BlaC subsystems.\n * Uses timestamp + counter + random suffix for uniqueness.\n */\n\n/**\n * Generate simple ID with timestamp and random (no counter tracking)\n *\n * Format: `${prefix}:${timestamp}_${random}`\n *\n * @param prefix - Prefix for the ID\n * @returns Branded ID string\n *\n * @example\n * ```ts\n * const id = generateSimpleId('CounterBloc');\n * // Returns: \"CounterBloc:1698765432100_a3k9d7f2q\"\n * ```\n */\nexport function generateSimpleId(prefix: string, affix?: string): string {\n if (affix) {\n return `${prefix}:${affix}`;\n }\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 11);\n return `${prefix}:${timestamp}_${random}`;\n}\n","import {\n globalRegistry,\n StateContainerRegistry,\n} from '../core/StateContainerRegistry';\n\nlet _registry = globalRegistry;\n\n/**\n * @public\n */\nexport function getRegistry(): StateContainerRegistry {\n return _registry;\n}\n\n/**\n * @public\n */\nexport function setRegistry(registry: StateContainerRegistry): void {\n _registry = registry;\n}\n\n/**\n * @public\n */\nexport function getStats(): {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n} {\n return _registry.getStats();\n}\n","/**\n * `$blac` meta namespace for `StateContainer`.\n *\n * `BlacMeta` and `BlacHydration` are classes whose accessors live on the\n * prototype and read the container through one `#private` back-reference, so\n * a container allocates a single small object here instead of a literal with\n * seven closures. Members are therefore not own-enumerable: `Object.keys` and\n * `JSON.stringify` see an empty object. Read the fields by name.\n */\n\nimport { generateSimpleId } from '../utils/idGenerator';\nimport { getBlacName } from '../utils/static-props';\nimport type { HydrationStatus } from './StateContainer';\nimport type { StateContainerConstructor } from '../types/utilities';\n\n/**\n * Non-enumerable brand carried on every `$blac` object. Used by the clobber\n * guard in `StateContainer` to detect a subclass class-field shadowing the\n * base's own `$blac` property, and by the meta tests. Intentionally NOT\n * re-exported from the package barrel.\n */\nexport const META_BRAND = Symbol('blac.meta');\n\nconst EMPTY_DEPS: ReadonlyMap<StateContainerConstructor, string> = new Map();\n\n/**\n * Narrow view of the parts of `StateContainer` the meta accessors read. The\n * container's fields are TS-private (compile-time only), so they are not\n * reachable cross-module by name; the constructor performs a single internal\n * cast to this shape. This is purely a typing bridge — zero runtime indirection.\n *\n * The `$blac.hydration` surface delegates to these `_`-private methods, so the\n * container has a single source of truth for the hydration state machine.\n */\ninterface MetaInternals<S extends object> {\n readonly constructor: StateContainerConstructor;\n _name: string;\n _instanceId?: string;\n _debug: boolean;\n _createdAt: number;\n _disposed: boolean;\n _hydrationStatus: HydrationStatus;\n _hydrationError: Error | undefined;\n _changedWhileHydrating: boolean;\n _dependencies: Map<StateContainerConstructor, string> | null;\n _beginHydration(): void;\n _applyHydratedState(next: S): boolean;\n _finishHydration(): void;\n _failHydration(error: Error): void;\n _waitForHydration(): Promise<void>;\n}\n\n/**\n * Hydration sub-surface of {@link BlacMeta}. Exposes the container's\n * hydration state machine — the `begin`/`apply`/`finish`/`fail`/`wait`\n * methods and the `status`/`error`/`isHydrated`/`changedWhileHydrating`\n * getters — namespaced under `$blac`.\n */\nexport class BlacHydration<S extends object> {\n readonly #c: MetaInternals<S>;\n\n /** @internal */\n constructor(container: object) {\n this.#c = container as MetaInternals<S>;\n Object.freeze(this);\n }\n\n get status(): HydrationStatus {\n return this.#c._hydrationStatus;\n }\n\n get error(): Error | undefined {\n return this.#c._hydrationError;\n }\n\n get isHydrated(): boolean {\n return this.#c._hydrationStatus === 'hydrated';\n }\n\n get changedWhileHydrating(): boolean {\n return this.#c._changedWhileHydrating;\n }\n\n begin(): void {\n this.#c._beginHydration();\n }\n\n apply(next: S): boolean {\n return this.#c._applyHydratedState(next);\n }\n\n finish(): void {\n this.#c._finishHydration();\n }\n\n fail(error: Error): void {\n this.#c._failHydration(error);\n }\n\n wait(): Promise<void> {\n return this.#c._waitForHydration();\n }\n}\n\n/**\n * The reserved `$blac` instance member on every `StateContainer`. Gathers the\n * container's identity/lifecycle/hydration surface (`name`, `id`, `debug`,\n * `createdAt`, `disposed`, `dependencies`, and the hydration methods) under one\n * namespace, keeping the generic names free for userland blocs.\n *\n * Allocated once per container and frozen. Every accessor reads the\n * container's current `_`-private fields live — values are never snapshotted.\n */\nexport class BlacMeta<S extends object = any> {\n readonly #c: MetaInternals<S>;\n #hydration: BlacHydration<S> | undefined;\n\n /** @internal Called from the `StateContainer` field initializer. */\n constructor(container: object) {\n this.#c = container as unknown as MetaInternals<S>;\n Object.freeze(this);\n }\n\n get name(): string {\n return this.#c._name;\n }\n\n get id(): string {\n // Generated on first read — the container leaves it undefined so an\n // instance nobody registers or inspects never pays for one.\n const c = this.#c;\n return (c._instanceId ??= generateSimpleId(\n getBlacName(c.constructor),\n 'main',\n ));\n }\n\n get debug(): boolean {\n return this.#c._debug;\n }\n\n get createdAt(): number {\n return this.#c._createdAt;\n }\n\n get disposed(): boolean {\n return this.#c._disposed;\n }\n\n get dependencies(): ReadonlyMap<StateContainerConstructor, string> {\n return this.#c._dependencies ?? EMPTY_DEPS;\n }\n\n /** Built on first access; identity-stable afterwards. */\n get hydration(): BlacHydration<S> {\n return (this.#hydration ??= new BlacHydration(this.#c));\n }\n}\n\nObject.defineProperty(BlacMeta.prototype, META_BRAND, {\n value: true,\n enumerable: false,\n writable: false,\n configurable: false,\n});\n","import {\n ALL_PATHS,\n StructuralContainer,\n type DeepPartial,\n type StructuralContainerOptions,\n} from '@dirtytalk/structural';\nimport { generateSimpleId } from '../utils/idGenerator';\nimport { IS_DEV } from '../constants';\nimport { getRegistry } from '../registry/config';\nimport type { StateContainerRegistry } from './StateContainerRegistry';\nimport type {\n ExtractArgs,\n ExtractState,\n StateContainerConstructor,\n} from '../types/utilities';\nimport {\n APPLY_DEPS,\n INIT_CONFIG,\n ON_DISPOSE,\n REMOVE_DEPS_OWNER,\n SET_ACTIVE,\n WITH_TRACKED_STATE,\n} from './symbols';\nimport { type EqualityFn, getBlacConfig } from '../config';\nimport { getClassEquality, getBlacName } from '../utils/static-props';\nimport { BlacMeta, META_BRAND } from './meta';\n\n/**\n * Brand symbol carried (non-enumerable) on every handle returned by\n * `depend()`. Framework adapters (`@blac/react`) use this to detect handles\n * inside a tracked-proxy and swap in a session-bound wrapper.\n *\n * @internal — exported for `@blac/react`; not part of the public API.\n */\nexport const DEP_BRAND = Symbol('blac.depHandle');\n\n/**\n * Per-access options for a {@link DepHandle}. `args` resolves the specific dep\n * instance for this call; omit it to fall back to the default args passed to\n * `depend()`. Args resolve at call time so they can derive from current state.\n */\nexport interface DepAccessOptions<T extends StateContainerConstructor> {\n args?: ExtractArgs<T>;\n}\n\n/**\n * Branded handle returned by `StateContainer.depend()`. Two intention-revealing\n * accessors, no callable surface:\n *\n * - `handle.track(options?)` — base impl: returns `[instance.state, instance]`\n * live with no subscription. The React layer replaces `.track()` per-consumer\n * so that cross-bloc state changes trigger re-renders of the reading component.\n * - `handle.untracked(options?)` — returns the live dep instance with no\n * tracking. Use for imperative calls (`.untracked().doThing()`) and one-off\n * state reads that should not subscribe the reader.\n * - `handle[DEP_BRAND]` — carries `{ Type, defaultArgs }` for framework use.\n */\nexport interface DepHandle<T extends StateContainerConstructor> {\n track(options?: DepAccessOptions<T>): [ExtractState<T>, InstanceType<T>];\n untracked(options?: DepAccessOptions<T>): InstanceType<T>;\n readonly [DEP_BRAND]: { Type: T; defaultArgs?: ExtractArgs<T> };\n}\n\nexport interface StateContainerConfig {\n name?: string;\n debug?: boolean;\n instanceId?: string;\n /** Args passed at acquire time; forwarded to init(). */\n args?: unknown;\n /**\n * The registry that created this instance. Lifecycle events, deps and\n * `depend()` route here instead of the module-global, which is what makes a\n * scoped registry isolating.\n * @internal\n */\n registry?: StateContainerRegistry;\n}\n\nexport type HydrationStatus = 'idle' | 'hydrating' | 'hydrated' | 'error';\n\nexport type SystemEvent = 'stateChanged' | 'dispose' | 'hydrationChanged';\n\nexport interface SystemEventPayloads<S> {\n stateChanged: { state: S; previousState: S };\n dispose: void;\n hydrationChanged: {\n status: HydrationStatus;\n previousStatus: HydrationStatus;\n error?: Error;\n changedWhileHydrating: boolean;\n };\n}\n\ntype SystemEventHandler<S, E extends SystemEvent> = (\n payload: SystemEventPayloads<S>[E],\n) => void;\n\n// Shared initial values for per-instance records that are replaced, never\n// mutated, so no container pays for an empty object it may never fill.\nconst EMPTY_RECORD: Readonly<Record<string, never>> = Object.freeze({});\n\nlet deactivatedReason: DOMException | undefined;\n\n/**\n * Shallow per-key `Object.is` comparison of two plain records. Keys are\n * considered: a key present in one but not the other (regardless of value)\n * makes the records unequal. Used to detect real deps changes.\n */\nfunction shallowEqualRecord(\n a: Record<string, unknown>,\n b: Record<string, unknown>,\n): boolean {\n if (a === b) return true;\n const aKeys = Object.keys(a);\n if (aKeys.length !== Object.keys(b).length) return false;\n for (const key of aKeys) {\n if (!(key in b)) return false;\n if (!Object.is(a[key], b[key])) return false;\n }\n return true;\n}\n\n/**\n * BlaC's lifecycle/identity/dependency layer on top of `StructuralContainer`.\n *\n * StructuralContainer provides:\n * - `state` getter\n * - `emit` / `patch` / `update` (path-tracked, microtask-flushed)\n * - `channel` (the underlying `DirtyChannel`)\n * - `registerConsumerPaths` / `unregisterConsumer` (for fine-grained consumers)\n * - per-class `PathInterner`\n *\n * StateContainer layers on:\n * - identity / lifecycle / hydration (exposed via `$blac: BlacMeta`)\n * - cross-bloc deps (`depend()`, `$blac.dependencies`)\n * - per-consumer deps slices (`APPLY_DEPS` / `REMOVE_DEPS_OWNER` / `onDepsChanged`)\n * - registry integration (config-driven equality, emit-rate circuit breaker)\n *\n * Subscribers can attach via:\n * - `onSystemEvent('stateChanged' | 'dispose' | 'hydrationChanged', cb)` —\n * coarse lifecycle events.\n * - `this.channel.subscribe(interest, cb)` — path-scoped.\n */\nexport abstract class StateContainer<\n S extends object = any,\n Args = void,\n Deps extends object = Record<string, never>,\n> extends StructuralContainer<S> {\n static __excludeFromDevTools = false;\n\n /** @internal phantom — the args type this bloc is constructed with (see init()) */\n declare readonly __args: Args;\n /** @internal phantom — the injected deps type */\n declare readonly __deps: Deps;\n\n // ---------------------------------------------------------------------------\n // Per-consumer deps slices (APPLY_DEPS / REMOVE_DEPS_OWNER)\n //\n // Framework adapters wire these per consumer:\n // `@blac/react/src/useBloc.ts` reads APPLY_DEPS / REMOVE_DEPS_OWNER.\n // ---------------------------------------------------------------------------\n\n private _depsByOwner: Map<string, Partial<Deps>> | null = null;\n private _deps: Partial<Deps> = EMPTY_RECORD as Partial<Deps>;\n\n get deps(): Readonly<Deps> {\n return this._deps as Readonly<Deps>;\n }\n\n /**\n * @internal Apply one owner's (consumer's) deps slice. Shallow-merges the\n * slice, reconciles keys the owner dropped since its last apply (other\n * owners' keys untouched), dev-warns on cross-owner key collisions, then\n * recomputes the merged view and fires onDepsChanged if it changed.\n *\n * Idempotent: re-applying an identical slice for the same owner is a no-op.\n */\n [APPLY_DEPS](ownerId: string, slice: Partial<Deps>): void {\n if (this._disposed) return;\n\n const owners = (this._depsByOwner ??= new Map());\n const prevSlice = owners.get(ownerId);\n\n if (prevSlice && shallowEqualRecord(prevSlice, slice)) {\n return;\n }\n\n if (IS_DEV) {\n for (const key of Object.keys(slice) as (keyof Deps)[]) {\n for (const [otherOwner, otherSlice] of owners) {\n if (otherOwner === ownerId) continue;\n if (\n key in otherSlice &&\n (otherSlice as Record<keyof Deps, unknown>)[key] !==\n (slice as Record<keyof Deps, unknown>)[key]\n ) {\n console.warn(\n `[${this._name}] multiple owners writing dep \\`${String(\n key,\n )}\\`; last write wins`,\n );\n }\n }\n }\n }\n\n owners.set(ownerId, { ...slice });\n this.reconcileDeps();\n }\n\n /**\n * @internal Withdraw an owner's entire deps slice (consumer unmounted).\n */\n [REMOVE_DEPS_OWNER](ownerId: string): void {\n if (this._disposed) return;\n if (!this._depsByOwner?.delete(ownerId)) return;\n this.reconcileDeps();\n }\n\n /**\n * @internal Subscribe to this instance's own disposal. Delegates to the\n * per-instance `'dispose'` system event — used by `watch()` in place of\n * filtering the global registry `'disposed'` event.\n */\n [ON_DISPOSE](handler: () => void): () => void {\n return this.onSystemEvent('dispose', handler);\n }\n\n /**\n * @internal Drive the 0↔1 ownership transition. Idempotent: repeated calls\n * with the same value are no-ops, so the registry can call it from every\n * acquire/release without tracking edges itself.\n *\n * Returns which real transition (if any) just happened, so the registry can\n * emit the matching `activated`/`deactivated` plugin event without exposing\n * `_activation` itself — `'none'` for an idempotent no-op call.\n */\n [SET_ACTIVE](\n active: boolean,\n ): { kind: 'activated'; signal: AbortSignal } | 'deactivated' | 'none' {\n if (this._disposed) return 'none';\n if (active === (this._activation !== null)) return 'none';\n if (active) {\n this._activation = new AbortController();\n this.onActivate(this._activation.signal);\n return { kind: 'activated', signal: this._activation.signal };\n }\n this._abortActivation();\n this.onDeactivate();\n return 'deactivated';\n }\n\n private _abortActivation(): void {\n // A bare `abort()` builds a new AbortError (stack trace included) on every\n // deactivation; one shared reason keeps the same `name` without that cost.\n this._activation?.abort(\n (deactivatedReason ??= new DOMException(\n 'The bloc was deactivated',\n 'AbortError',\n )),\n );\n this._activation = null;\n }\n\n private reconcileDeps(): void {\n const prev = this._deps;\n const next: Partial<Deps> = {};\n if (this._depsByOwner) {\n for (const slice of this._depsByOwner.values()) {\n Object.assign(next, slice);\n }\n }\n for (const key of Object.keys(prev) as (keyof Deps)[]) {\n if (!(key in next)) {\n (next as Record<keyof Deps, unknown>)[key] = undefined;\n }\n }\n\n if (shallowEqualRecord(prev, next)) return;\n\n this._deps = next;\n this.onDepsChanged(next as Readonly<Deps>, prev as Readonly<Deps>);\n this._registry.emit(\n 'depsChanged',\n this,\n prev as Readonly<Record<string, unknown>>,\n next as Readonly<Record<string, unknown>>,\n );\n }\n\n protected onDepsChanged(_next: Readonly<Deps>, _prev: Readonly<Deps>): void {}\n\n // ---------------------------------------------------------------------------\n // Identity / lifecycle\n // ---------------------------------------------------------------------------\n\n private _disposed = false;\n private _hydrationStatus: HydrationStatus = 'idle';\n private _hydrationError?: Error;\n private _changedWhileHydrating = false;\n private _hydrationPromise: Promise<void> | null = null;\n private _resolveHydrationPromise?: () => void;\n private _rejectHydrationPromise?: (error: Error) => void;\n private _hydrationPromiseSettled = false;\n private _config: StateContainerConfig = EMPTY_RECORD;\n private _initCalled = false;\n private _activation: AbortController | null = null;\n\n // Dev-only emit-rate circuit breaker state (see configureBlac.maxEmitsPerSecond).\n private _emitWindowStart = 0;\n private _emitCount = 0;\n private _emitRateWarned = false;\n\n // System-event handlers (stateChanged | dispose | hydrationChanged).\n // Allocated on the first `onSystemEvent` call.\n private _systemEventHandlers: Map<\n SystemEvent,\n Set<SystemEventHandler<S, any>>\n > | null = null;\n\n // Cross-bloc dependencies recorded by depend(). Map<DepCtor, instanceKey>.\n private _dependencies: Map<StateContainerConstructor, string> | null = null;\n\n // Pending state-change capture; set by emit(), drained by the channel-bridge\n // callback on flush. Coalesced: multiple emits in one tick collapse to one\n // (prev = the first prev, next = the latest next).\n private _pendingChange: { prev: S; next: S } | null = null;\n\n // Unsubscribe from the internal bridge that turns channel flushes into\n // 'stateChanged' system events.\n private _bridgeUnsub: (() => void) | null = null;\n\n // Falls back to the module-global for a bare `new`'d container; a registry\n // that creates the instance overwrites this via `[INIT_CONFIG]`.\n private _registry = getRegistry();\n private _equalityFn: EqualityFn = getBlacConfig().equality;\n\n // Identity fields. The `$blac` meta getters close over these.\n private _name: string = getBlacName(\n this.constructor as StateContainerConstructor,\n );\n private _debug: boolean = false;\n // Left undefined until first read: generating an id costs a `Date.now()` plus\n // a random base-36 string, and a container that is never registered or\n // inspected never needs one. `$blac.id` fills it in on demand (see\n // `createMeta`), and `[INIT_CONFIG]` overwrites it when the registry supplies\n // a configured instanceId. Deliberately a plain field, not a getter —\n // devtools enumerates prototype getters to find user-defined ones, and a\n // `_instanceId` accessor would show up there as bloc state.\n private _instanceId?: string;\n private _createdAt: number = Date.now();\n\n /**\n * Reserved meta namespace: identity (`name`/`id`/`debug`/`createdAt`),\n * lifecycle (`disposed`/`dependencies`), and the `hydration` sub-surface.\n * Own, frozen, branded data property — `buildTrackedProxy` only intercepts\n * prototype getters of the container, so this own property is proxy-safe.\n * Its members are prototype accessors over the container (non-enumerable).\n */\n readonly $blac: BlacMeta<S> = new BlacMeta<S>(this);\n\n /**\n * Both set only for the duration of a `[WITH_TRACKED_STATE]` call. TS-private\n * so they stay out of the public surface.\n */\n private _stateOverride: S | undefined;\n private _depHandleHook: ((handle: object) => unknown) | undefined;\n\n override get state(): S {\n return this._stateOverride ?? super.state;\n }\n\n /**\n * @internal Run `fn` (with `this` = this instance, so a prototype getter can\n * be passed directly) while `state` reports `tracked` and dep handles read\n * off `this` route through `onDepHandle`. Restored in `finally`, and\n * nestable — getters reading other getters stay in tracked context.\n *\n * The dep hook lives here rather than in the adapter's proxy because getters\n * now run with `this` = the real instance (so ES `#private` works), which\n * means a `this.someDep` read never passes through the proxy's trap.\n */\n [WITH_TRACKED_STATE]<R>(\n tracked: S,\n fn: () => R,\n onDepHandle?: (handle: object) => unknown,\n ): R {\n const prevState = this._stateOverride;\n const prevHook = this._depHandleHook;\n this._stateOverride = tracked;\n this._depHandleHook = onDepHandle;\n try {\n return fn.call(this);\n } finally {\n this._stateOverride = prevState;\n this._depHandleHook = prevHook;\n }\n }\n\n get args(): Args | undefined {\n return this._config.args as Args | undefined;\n }\n\n /**\n * Declare a cross-bloc dependency. Returns a branded handle with two\n * accessors — the dep instance is resolved against the registry on each call,\n * which keeps the surface immune to dep-instance churn:\n *\n * - `handle.track(options?)` — reactive read. Returns `[state, instance]`.\n * Inside a getter reached through the React proxy this subscribes the\n * reading component to the dep's changes (base impl: live, no subscription).\n * - `handle.untracked(options?)` — returns the live instance with no tracking,\n * for imperative method calls and one-off reads.\n *\n * `defaultArgs` resolves the dep instance when an accessor is called without\n * its own `args`; per-call `options.args` overrides it and can derive from\n * current state. This does NOT auto-resubscribe outside the React proxy;\n * non-React consumers needing updates should subscribe explicitly.\n */\n protected depend<T extends StateContainerConstructor>(\n Type: T,\n defaultArgs?: ExtractArgs<T>,\n ): DepHandle<T> {\n if (!this._dependencies) {\n this._dependencies = new Map();\n }\n this._dependencies.set(\n Type,\n this._registry.resolveKey(Type, undefined, defaultArgs),\n );\n\n const resolve = (args?: ExtractArgs<T>): InstanceType<T> => {\n const effectiveArgs = args ?? defaultArgs;\n const key = this._registry.resolveKey(Type, undefined, effectiveArgs);\n // Same no-ref semantics as `ensure()`, but records `this` as a\n // dependent edge on the resolved entry so the registry can sweep it\n // on `this`'s disposal (see StateContainerRegistry._releaseDependent).\n return this._registry.acquire(Type, key, {\n canCreate: true,\n countRef: false,\n args: effectiveArgs,\n dependent: this,\n }) as InstanceType<T>;\n };\n\n const handle = {\n track: (\n options?: DepAccessOptions<T>,\n ): [ExtractState<T>, InstanceType<T>] => {\n // While a consumer is rendering, `.track()` must go through its\n // session-bound wrapper so the read subscribes that consumer. The\n // wrapper is only reachable via the hook, since `this.<dep>` is read\n // straight off the real instance.\n const wrapped = this._depHandleHook?.(handle) as\n | DepHandle<T>\n | undefined;\n if (wrapped !== undefined && wrapped !== handle) {\n return wrapped.track(options);\n }\n const instance = resolve(options?.args);\n return [instance.state as ExtractState<T>, instance];\n },\n untracked: (options?: DepAccessOptions<T>): InstanceType<T> =>\n resolve(options?.args),\n } as DepHandle<T>;\n\n Object.defineProperty(handle, DEP_BRAND, {\n value: { Type, defaultArgs },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n return handle;\n }\n\n constructor(initialState: S, options?: StructuralContainerOptions) {\n super(initialState, options);\n }\n\n /**\n * Called once after construction with the args passed at acquire time, before the first\n * state snapshot is read by any consumer. Override to seed args-derived state (via\n * this.emit(...)) or kick off loads.\n */\n protected init(_args: Args): void {}\n\n /**\n * Called when this instance goes from unowned to owned (first ref or first\n * `depend()` dependent). Override to start work that should only run while\n * something is actually using the instance — fetches, timers, listeners.\n *\n * `signal` aborts on the matching {@link onDeactivate} and on dispose, so\n * async work started here can be cancelled without extra bookkeeping.\n *\n * Runs before the first `useBlocDeps` slice is applied, so `this.deps` is\n * empty on first activation — use `onDepsChanged` for deps-driven work.\n */\n protected onActivate(_signal: AbortSignal): void {}\n\n /**\n * Called when this instance goes from owned back to unowned while surviving\n * in the registry (i.e. `keepAlive`). A disposed instance does NOT get this\n * callback — `dispose()` is the teardown path for that case.\n */\n protected onDeactivate(): void {}\n\n /**\n * @internal Framework-only configuration entry point (registry + testing\n * helpers). Writes the `_`-private identity fields directly, resolves\n * per-class equality, emits the registry `created` event, and runs `init()`\n * once. See {@link INIT_CONFIG}.\n */\n [INIT_CONFIG](config: StateContainerConfig): void {\n this._config = { ...config };\n const className = getBlacName(\n this.constructor as StateContainerConstructor,\n );\n this._name = this._config.name || className;\n this._debug = this._config.debug ?? false;\n this._instanceId = generateSimpleId(className, this._config.instanceId);\n // Must precede init(): init() may `depend()` or emit, and both have to\n // resolve against the owning registry.\n this._registry = this._config.registry ?? this._registry;\n const perClass = getClassEquality(\n this.constructor as StateContainerConstructor,\n );\n this._equalityFn = perClass ?? getBlacConfig().equality;\n // `created` fires AFTER init() so plugins observe a fully initialised\n // instance. Emitting it first let a plugin start hydration, which init()'s\n // seeding emits then cancelled — silently discarding persisted state.\n if (!this._initCalled) {\n this._initCalled = true;\n this.init(this._config.args as Args);\n }\n this._registry.emit('created', this);\n\n // Clobber guard: a subclass class-field `$blac = ...` initializes after\n // `super()` and would overwrite the base's own meta property. Dev-only.\n if (IS_DEV) {\n if (!(this.$blac as unknown as Record<symbol, unknown>)?.[META_BRAND]) {\n console.warn(\n `[blac] ${this.constructor.name} appears to declare its own \\`$blac\\` ` +\n `member, which shadows the reserved meta namespace. \\`$blac\\` is ` +\n `reserved by StateContainer — remove the subclass field.`,\n );\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle: dispose\n // ---------------------------------------------------------------------------\n\n dispose(): void {\n if (this._disposed) return;\n\n if (this._debug) {\n console.log(`[${this._name}] Disposing...`);\n }\n\n // Reconcile to an empty deps view so a final onDepsChanged(next, prev)\n // fires with all keys absent (undefined). After this, APPLY_DEPS /\n // REMOVE_DEPS_OWNER are guarded by _disposed.\n if (this._depsByOwner) {\n this._depsByOwner.clear();\n this.reconcileDeps();\n }\n\n this._disposed = true;\n\n if (this._hydrationStatus === 'hydrating') {\n this._failHydration(\n new Error(`Hydration cancelled because ${this._name} was disposed`),\n );\n }\n\n this.emitSystemEvent('dispose', undefined as void);\n\n // Tear down the channel bridge so we don't leak a subscription.\n this._bridgeUnsub?.();\n this._bridgeUnsub = null;\n\n // Dispose is the teardown path for an active instance: the signal aborts\n // but `onDeactivate` does NOT fire, so a container has exactly one teardown\n // callback per lifecycle rather than two.\n this._abortActivation();\n\n this._systemEventHandlers = null;\n this._pendingChange = null;\n\n this._registry.emit('disposed', this);\n\n // Tear down the channel itself (cancels any scheduled flush).\n super.dispose();\n\n if (this._debug) {\n console.log(`[${this._name}] Disposed successfully`);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Mutation: emit / patch / update.\n //\n // We override `emit` to layer in:\n // - disposed guard\n // - equality-fn short-circuit (consults getBlacConfig().equality or the\n // per-class override via @blac decorator)\n // - emit-rate circuit breaker (dev-only)\n // - `_changedWhileHydrating` flag tracking\n // - registry-level stateChanged notification (microtask-deferred)\n // - pending-change capture so the channel-bridge callback can fire the\n // 'stateChanged' system event with prev/next.\n //\n // The actual change-detection (path diff, channel mark, single-consumer\n // skip) is delegated to `super.emit`.\n // ---------------------------------------------------------------------------\n\n protected override emit(next: S): void {\n this.applyState(next, 'default');\n }\n\n /**\n * Override of `StructuralContainer.patch` that routes through the\n * StateContainer concerns: disposed guard, dev-only emit-rate check,\n * `_changedWhileHydrating` flag, pending-change capture (so `stateChanged`\n * system events see the merged prev/next), and the registry-level\n * `stateChanged` notification. We still call\n * `super.patch` so path-marking semantics (the whole point of patch) are\n * preserved.\n */\n protected override patch(partial: DeepPartial<S>): void {\n if (this._disposed) {\n this._warnDisposedMutation('patch');\n return;\n }\n // Raw state, not `this.state`: inside a tracked getter that getter reports\n // the render proxy, which must never be mistaken for a state transition.\n const prev = super.state;\n\n super.patch(partial);\n\n // `super.patch` returns `prev` by reference when the merge changed\n // nothing, so identity is the no-op test — no pre-scan needed.\n const next = super.state;\n if (Object.is(prev, next)) return;\n\n if (IS_DEV && !this._emitRateWarned) {\n this._checkEmitRate();\n }\n\n if (this._hydrationStatus === 'hydrating') {\n this._changedWhileHydrating = true;\n }\n\n if (this._bridgeUnsub !== null) {\n if (this._pendingChange) {\n this._pendingChange.next = next;\n } else {\n this._pendingChange = { prev, next };\n }\n }\n\n if (this._registry.hasStateChangedListeners) {\n this._registry.notifyStateChanged(this, prev, next);\n }\n }\n\n private applyState(next: S, source: 'default' | 'hydration'): void {\n if (this._disposed) {\n this._warnDisposedMutation('emit');\n return;\n }\n\n const prev = super.state;\n if (prev === next) return;\n if (this._equalityFn(prev, next)) return;\n\n if (IS_DEV && !this._emitRateWarned) {\n this._checkEmitRate();\n }\n\n if (this._hydrationStatus === 'hydrating' && source !== 'hydration') {\n this._changedWhileHydrating = true;\n }\n\n // Coalesce: keep the first prev seen this tick, take the latest next.\n // Only tracked when the bridge is attached; nothing reads it otherwise.\n if (this._bridgeUnsub !== null) {\n if (this._pendingChange) {\n this._pendingChange.next = next;\n } else {\n this._pendingChange = { prev, next };\n }\n }\n\n super.emit(next);\n\n if (this._registry.hasStateChangedListeners) {\n this._registry.notifyStateChanged(this, prev, next);\n }\n }\n\n /**\n * Called by the channel-bridge subscriber on each flush. Drains the\n * pending change (if any) into the 'stateChanged' system event.\n * No pending change == flush from a no-op patch == skip.\n */\n private _drainPending(): void {\n const pending = this._pendingChange;\n if (!pending) return;\n this._pendingChange = null;\n\n // Iterate against a fixed-size snapshot so a handler that subscribes a\n // new handler mid-drain does not get the late one called in this flush.\n const handlers = this._systemEventHandlers?.get('stateChanged');\n if (handlers && handlers.size > 0) {\n const payload = { state: pending.next, previousState: pending.prev };\n let count = 0;\n const size = handlers.size;\n for (const handler of handlers) {\n if (++count > size) break;\n try {\n handler(payload);\n } catch (error) {\n console.error(\n `[${this._name}] Error in system event handler:`,\n error,\n );\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Hydration\n // ---------------------------------------------------------------------------\n\n // The hydration state machine lives in these `_`-private impls. The\n // `$blac.hydration` surface delegates here, so there is a single source\n // of truth for the hydration state machine.\n\n private _beginHydration(): void {\n if (this._disposed) {\n throw new Error(\n `Cannot begin hydration for disposed container ${this._name}`,\n );\n }\n\n this._changedWhileHydrating = false;\n this._hydrationError = undefined;\n this._hydrationPromise = null;\n this._resolveHydrationPromise = undefined;\n this._rejectHydrationPromise = undefined;\n this._hydrationPromiseSettled = false;\n void this.ensureHydrationPromise();\n this.setHydrationStatus('hydrating');\n }\n\n private _warnDisposedMutation(op: 'emit' | 'patch'): void {\n if (IS_DEV) {\n console.warn(\n `[blac] ${this._name}: ${op}() after dispose ignored. This usually ` +\n `means an async method resolved after the last consumer unmounted. ` +\n `Guard with \\`if (this.$blac.disposed) return\\` after each \\`await\\`, ` +\n `or abort the work from \\`onSystemEvent('dispose', ...)\\`.`,\n );\n }\n }\n\n private _applyHydratedState(next: S): boolean {\n if (this._disposed) {\n return false;\n }\n\n if (this._hydrationStatus !== 'hydrating' || this._changedWhileHydrating) {\n if (IS_DEV && this._changedWhileHydrating) {\n console.warn(\n `[blac] ${this._name}: persisted state discarded because the ` +\n `container emitted while hydrating.`,\n );\n }\n return false;\n }\n\n this.applyState(next, 'hydration');\n return true;\n }\n\n private _finishHydration(): void {\n if (this._hydrationStatus !== 'hydrating') {\n if (this._hydrationStatus === 'hydrated') {\n return;\n }\n if (this._hydrationStatus === 'error') {\n void this.ensureHydrationPromise();\n }\n }\n\n this.setHydrationStatus('hydrated');\n this.resolveHydration();\n }\n\n private _failHydration(error: Error): void {\n const err =\n error instanceof Error\n ? error\n : new Error(`Hydration failed: ${String(error)}`);\n\n this._hydrationError = err;\n this.setHydrationStatus('error', err);\n this.rejectHydration(err);\n }\n\n private _waitForHydration(): Promise<void> {\n if (\n this._hydrationStatus === 'idle' ||\n this._hydrationStatus === 'hydrated'\n ) {\n return Promise.resolve();\n }\n\n if (this._hydrationStatus === 'error') {\n return Promise.reject(\n this._hydrationError ??\n new Error(`Hydration failed for container ${this._name}`),\n );\n }\n\n return this.ensureHydrationPromise();\n }\n\n private setHydrationStatus(status: HydrationStatus, error?: Error): void {\n const previousStatus = this._hydrationStatus;\n this._hydrationStatus = status;\n this._hydrationError = error;\n\n this.emitSystemEvent('hydrationChanged', {\n status,\n previousStatus,\n error,\n changedWhileHydrating: this._changedWhileHydrating,\n });\n this._registry.emit('hydrationChanged', this, status, previousStatus);\n }\n\n private ensureHydrationPromise(): Promise<void> {\n if (!this._hydrationPromise || this._hydrationPromiseSettled) {\n this._hydrationPromiseSettled = false;\n this._hydrationPromise = new Promise<void>((resolve, reject) => {\n this._resolveHydrationPromise = () => {\n if (this._hydrationPromiseSettled) return;\n this._hydrationPromiseSettled = true;\n resolve();\n };\n this._rejectHydrationPromise = (error: Error) => {\n if (this._hydrationPromiseSettled) return;\n this._hydrationPromiseSettled = true;\n reject(error);\n };\n });\n this._hydrationPromise.catch(() => {});\n }\n\n return this._hydrationPromise;\n }\n\n private resolveHydration(): void {\n this._resolveHydrationPromise?.();\n }\n\n private rejectHydration(error: Error): void {\n void this.ensureHydrationPromise();\n this._rejectHydrationPromise?.(error);\n }\n\n // ---------------------------------------------------------------------------\n // System events\n // ---------------------------------------------------------------------------\n\n protected onSystemEvent = <E extends SystemEvent>(\n event: E,\n handler: SystemEventHandler<S, E>,\n ): (() => void) => {\n const all = (this._systemEventHandlers ??= new Map());\n let handlers = all.get(event);\n if (!handlers) {\n handlers = new Set();\n all.set(event, handlers);\n }\n handlers.add(handler as SystemEventHandler<S, any>);\n\n // The channel bridge only exists to feed 'stateChanged'. Subscribe on the\n // first such handler so instances nobody observes stay off the channel.\n if (event === 'stateChanged' && this._bridgeUnsub === null) {\n this._bridgeUnsub = this.channel.subscribe(\n () => ALL_PATHS,\n () => this._drainPending(),\n );\n }\n\n return () => {\n handlers?.delete(handler as SystemEventHandler<S, any>);\n if (event === 'stateChanged' && handlers?.size === 0) {\n this._bridgeUnsub?.();\n this._bridgeUnsub = null;\n this._pendingChange = null;\n }\n };\n };\n\n private emitSystemEvent<E extends SystemEvent>(\n event: E,\n payload: SystemEventPayloads<S>[E],\n ): void {\n const handlers = this._systemEventHandlers?.get(event);\n if (!handlers) return;\n\n for (const handler of handlers) {\n try {\n handler(payload);\n } catch (error) {\n console.error(`[${this._name}] Error in system event handler:`, error);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Emit-rate circuit breaker (dev-only)\n // ---------------------------------------------------------------------------\n\n /**\n * Dev-only soft circuit breaker. Counts real state changes in a rolling 1s\n * window and warns once if the rate exceeds `maxEmitsPerSecond` — the\n * signature of a runaway loop (RAF/animation or emit-on-every-commit) pushing\n * high-frequency data through state, which freezes subscribers/plugins.\n */\n private _checkEmitRate(): void {\n const limit = getBlacConfig().maxEmitsPerSecond;\n if (!(limit > 0) || !Number.isFinite(limit)) return;\n\n const now = Date.now();\n if (now - this._emitWindowStart >= 1000) {\n this._emitWindowStart = now;\n this._emitCount = 1;\n return;\n }\n\n this._emitCount++;\n if (this._emitCount > limit) {\n this._emitRateWarned = true;\n console.warn(\n `[${this._name}] emitted more than ${limit} state changes in under a second. ` +\n `This is usually a runaway loop pushing high-frequency data through state ` +\n `(e.g. \\`emit\\`/\\`patch\\` inside a requestAnimationFrame loop, or an effect ` +\n `that emits on every render). It can freeze the app by saturating ` +\n `subscribers and plugins (logging/devtools). Keep high-frequency work ` +\n `imperative and emit only coarse/throttled state, or raise ` +\n `\\`configureBlac({ maxEmitsPerSecond })\\`. (This warning fires once.)`,\n );\n }\n }\n}\n","import { StateContainer } from './StateContainer';\nimport type { DeepPartial } from '@dirtytalk/structural';\n\n/**\n * `Cubit<S>` is a `StateContainer<S>` that exposes mutation publicly.\n *\n * That is the whole difference, and it is a real one: on `StateContainer`\n * `emit` / `patch` / `update` are `protected`, so a container mutates itself\n * from its own methods and callers go through the API it chooses to publish.\n * `Cubit` re-declares the three as `public` for the cases where a caller\n * legitimately drives state from outside — test helpers, devtools\n * time-travel, benchmarks.\n *\n * Reach for `StateContainer` when business logic should live in the class,\n * and `Cubit` when the caller owns the transitions.\n */\nexport abstract class Cubit<\n S extends object = any,\n Args = void,\n Deps extends object = Record<string, never>,\n> extends StateContainer<S, Args, Deps> {\n override emit(next: S): void {\n super.emit(next);\n }\n\n override patch(partial: DeepPartial<S>): void {\n super.patch(partial);\n }\n\n override update(fn: (state: S) => S): void {\n super.update(fn);\n }\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Acquire an instance with ref tracking (ownership semantics). Instance\n * identity is derived purely from `args` (via the class's `static key(args)`,\n * a structural hash of `args`, or the default sentinel when there are none).\n *\n * @param BlocClass - The StateContainer class constructor\n * @param opts - `args` derives the instance key; `refId` names the reference\n * for debugging and is auto-generated when omitted.\n */\nexport function acquire<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.acquire(BlocClass, key, {\n canCreate: true,\n countRef: true,\n refId: opts?.refId,\n args: opts?.args,\n });\n}\n\n/**\n * Resolve the storage key an instance would be acquired under, given its\n * construction `args`. This is the canonical key-computation path. Callers that\n * both acquire and release against the `@internal` registry tier (e.g.\n * `@blac/react` `useBloc`) must use this once and pass the same resolved key to\n * both, so the ref is dropped under the key it was taken.\n */\nexport function resolveInstanceKey<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, args);\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Ensure an instance exists without taking ownership (no ref added). Instance\n * identity is derived purely from `args`, matching `acquire`.\n */\nexport function ensure<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.ensure(BlocClass, key, opts?.args);\n}\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
- const require_StateContainerRegistry = require("./StateContainerRegistry-CS18y4au.cjs");
2
- const require_config = require("./config-DWUq7zEQ.cjs");
1
+ const require_StateContainerRegistry = require("./StateContainerRegistry-141uHhtF.cjs");
3
2
  let _dirtytalk_structural = require("@dirtytalk/structural");
4
3
  //#region src/utils/idGenerator.ts
5
4
  /**
@@ -27,6 +26,27 @@ function generateSimpleId(prefix, affix) {
27
26
  return `${prefix}:${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
28
27
  }
29
28
  //#endregion
29
+ //#region src/registry/config.ts
30
+ let _registry = require_StateContainerRegistry.globalRegistry;
31
+ /**
32
+ * @public
33
+ */
34
+ function getRegistry() {
35
+ return _registry;
36
+ }
37
+ /**
38
+ * @public
39
+ */
40
+ function setRegistry(registry) {
41
+ _registry = registry;
42
+ }
43
+ /**
44
+ * @public
45
+ */
46
+ function getStats() {
47
+ return _registry.getStats();
48
+ }
49
+ //#endregion
30
50
  //#region src/core/meta.ts
31
51
  /**
32
52
  * Non-enumerable brand carried on every `$blac` object produced by
@@ -173,7 +193,7 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
173
193
  const owners = this._depsByOwner ??= /* @__PURE__ */ new Map();
174
194
  const prevSlice = owners.get(ownerId);
175
195
  if (prevSlice && shallowEqualRecord(prevSlice, slice)) return;
176
- if (process.env.NODE_ENV !== "production") for (const key of Object.keys(slice)) for (const [otherOwner, otherSlice] of owners) {
196
+ if (require_StateContainerRegistry.IS_DEV) for (const key of Object.keys(slice)) for (const [otherOwner, otherSlice] of owners) {
177
197
  if (otherOwner === ownerId) continue;
178
198
  if (key in otherSlice && otherSlice[key] !== slice[key]) console.warn(`[${this._name}] multiple owners writing dep \`${String(key)}\`; last write wins`);
179
199
  }
@@ -196,6 +216,34 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
196
216
  [require_StateContainerRegistry.ON_DISPOSE](handler) {
197
217
  return this.onSystemEvent("dispose", handler);
198
218
  }
219
+ /**
220
+ * @internal Drive the 0↔1 ownership transition. Idempotent: repeated calls
221
+ * with the same value are no-ops, so the registry can call it from every
222
+ * acquire/release without tracking edges itself.
223
+ *
224
+ * Returns which real transition (if any) just happened, so the registry can
225
+ * emit the matching `activated`/`deactivated` plugin event without exposing
226
+ * `_activation` itself — `'none'` for an idempotent no-op call.
227
+ */
228
+ [require_StateContainerRegistry.SET_ACTIVE](active) {
229
+ if (this._disposed) return "none";
230
+ if (active === (this._activation !== null)) return "none";
231
+ if (active) {
232
+ this._activation = new AbortController();
233
+ this.onActivate(this._activation.signal);
234
+ return {
235
+ kind: "activated",
236
+ signal: this._activation.signal
237
+ };
238
+ }
239
+ this._abortActivation();
240
+ this.onDeactivate();
241
+ return "deactivated";
242
+ }
243
+ _abortActivation() {
244
+ this._activation?.abort();
245
+ this._activation = null;
246
+ }
199
247
  reconcileDeps() {
200
248
  const prev = this._deps;
201
249
  const next = {};
@@ -207,6 +255,30 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
207
255
  this._registry.emit("depsChanged", this, prev, next);
208
256
  }
209
257
  onDepsChanged(_next, _prev) {}
258
+ get state() {
259
+ return this._stateOverride ?? super.state;
260
+ }
261
+ /**
262
+ * @internal Run `fn` with `state` reporting `tracked`, and with dep handles
263
+ * read off `this` routed through `onDepHandle`. Restored in `finally`, and
264
+ * nestable — getters reading other getters stay in tracked context.
265
+ *
266
+ * The dep hook lives here rather than in the adapter's proxy because getters
267
+ * now run with `this` = the real instance (so ES `#private` works), which
268
+ * means a `this.someDep` read never passes through the proxy's trap.
269
+ */
270
+ [require_StateContainerRegistry.WITH_TRACKED_STATE](tracked, fn, onDepHandle) {
271
+ const prevState = this._stateOverride;
272
+ const prevHook = this._depHandleHook;
273
+ this._stateOverride = tracked;
274
+ this._depHandleHook = onDepHandle;
275
+ try {
276
+ return fn();
277
+ } finally {
278
+ this._stateOverride = prevState;
279
+ this._depHandleHook = prevHook;
280
+ }
281
+ }
210
282
  get args() {
211
283
  return this._config.args;
212
284
  }
@@ -241,6 +313,8 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
241
313
  };
242
314
  const handle = {
243
315
  track: (options) => {
316
+ const wrapped = this._depHandleHook?.(handle);
317
+ if (wrapped !== void 0 && wrapped !== handle) return wrapped.track(options);
244
318
  const instance = resolve(options?.args);
245
319
  return [instance.state, instance];
246
320
  },
@@ -268,6 +342,7 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
268
342
  this._hydrationPromiseSettled = false;
269
343
  this._config = {};
270
344
  this._initCalled = false;
345
+ this._activation = null;
271
346
  this._emitWindowStart = 0;
272
347
  this._emitCount = 0;
273
348
  this._emitRateWarned = false;
@@ -275,11 +350,11 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
275
350
  this._dependencies = null;
276
351
  this._pendingChange = null;
277
352
  this._bridgeUnsub = null;
278
- this._registry = require_config.getRegistry();
353
+ this._registry = getRegistry();
279
354
  this._equalityFn = require_StateContainerRegistry.getBlacConfig().equality;
280
- this._name = this.constructor.name;
355
+ this._name = require_StateContainerRegistry.getBlacName(this.constructor);
281
356
  this._debug = false;
282
- this._instanceId = generateSimpleId(this.constructor.name, "main");
357
+ this._instanceId = generateSimpleId(require_StateContainerRegistry.getBlacName(this.constructor), "main");
283
358
  this._createdAt = Date.now();
284
359
  this.$blac = createMeta(this);
285
360
  this.onSystemEvent = (event, handler) => {
@@ -289,11 +364,16 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
289
364
  this._systemEventHandlers.set(event, handlers);
290
365
  }
291
366
  handlers.add(handler);
367
+ if (event === "stateChanged" && this._bridgeUnsub === null) this._bridgeUnsub = this.channel.subscribe(() => _dirtytalk_structural.ALL_PATHS, () => this._drainPending());
292
368
  return () => {
293
369
  handlers?.delete(handler);
370
+ if (event === "stateChanged" && handlers?.size === 0) {
371
+ this._bridgeUnsub?.();
372
+ this._bridgeUnsub = null;
373
+ this._pendingChange = null;
374
+ }
294
375
  };
295
376
  };
296
- this._bridgeUnsub = this.channel.subscribe(() => _dirtytalk_structural.ALL_PATHS, () => this._drainPending());
297
377
  }
298
378
  /**
299
379
  * Called once after construction with the args passed at acquire time, before the first
@@ -302,6 +382,24 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
302
382
  */
303
383
  init(_args) {}
304
384
  /**
385
+ * Called when this instance goes from unowned to owned (first ref or first
386
+ * `depend()` dependent). Override to start work that should only run while
387
+ * something is actually using the instance — fetches, timers, listeners.
388
+ *
389
+ * `signal` aborts on the matching {@link onDeactivate} and on dispose, so
390
+ * async work started here can be cancelled without extra bookkeeping.
391
+ *
392
+ * Runs before the first `useBlocDeps` slice is applied, so `this.deps` is
393
+ * empty on first activation — use `onDepsChanged` for deps-driven work.
394
+ */
395
+ onActivate(_signal) {}
396
+ /**
397
+ * Called when this instance goes from owned back to unowned while surviving
398
+ * in the registry (i.e. `keepAlive`). A disposed instance does NOT get this
399
+ * callback — `dispose()` is the teardown path for that case.
400
+ */
401
+ onDeactivate() {}
402
+ /**
305
403
  * @internal Framework-only configuration entry point (registry + testing
306
404
  * helpers). Writes the `_`-private identity fields directly, resolves
307
405
  * per-class equality, emits the registry `created` event, and runs `init()`
@@ -309,17 +407,17 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
309
407
  */
310
408
  [require_StateContainerRegistry.INIT_CONFIG](config) {
311
409
  this._config = { ...config };
312
- this._name = this._config.name || this.constructor.name;
410
+ this._name = this._config.name || require_StateContainerRegistry.getBlacName(this.constructor);
313
411
  this._debug = this._config.debug ?? false;
314
- this._instanceId = generateSimpleId(this.constructor.name, this._config.instanceId);
412
+ this._instanceId = generateSimpleId(require_StateContainerRegistry.getBlacName(this.constructor), this._config.instanceId);
315
413
  const perClass = require_StateContainerRegistry.getClassEquality(this.constructor);
316
414
  this._equalityFn = perClass ?? require_StateContainerRegistry.getBlacConfig().equality;
317
- this._registry.emit("created", this);
318
415
  if (!this._initCalled) {
319
416
  this._initCalled = true;
320
417
  this.init(this._config.args);
321
418
  }
322
- if (process.env.NODE_ENV !== "production") {
419
+ this._registry.emit("created", this);
420
+ if (require_StateContainerRegistry.IS_DEV) {
323
421
  if (!this.$blac?.[META_BRAND]) console.warn(`[blac] ${this.constructor.name} appears to declare its own \`$blac\` member, which shadows the reserved meta namespace. \`$blac\` is reserved by StateContainer — remove the subclass field.`);
324
422
  }
325
423
  }
@@ -335,9 +433,11 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
335
433
  this.emitSystemEvent("dispose", void 0);
336
434
  this._bridgeUnsub?.();
337
435
  this._bridgeUnsub = null;
436
+ this._abortActivation();
338
437
  this._systemEventHandlers.clear();
339
438
  this._pendingChange = null;
340
439
  this._registry.emit("disposed", this);
440
+ super.dispose();
341
441
  if (this._debug) console.log(`[${this._name}] Disposed successfully`);
342
442
  }
343
443
  emit(next) {
@@ -353,22 +453,17 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
353
453
  * preserved.
354
454
  */
355
455
  patch(partial) {
356
- if (this._disposed) throw new Error(`Cannot emit state from disposed container ${this._name}`);
357
- const partialKeys = Object.keys(partial);
358
- if (partialKeys.length === 0) return;
359
- const prev = this.state;
360
- let allEqual = true;
361
- for (const key of partialKeys) if (!Object.is(prev[key], partial[key])) {
362
- allEqual = false;
363
- break;
456
+ if (this._disposed) {
457
+ this._warnDisposedMutation("patch");
458
+ return;
364
459
  }
365
- if (allEqual) return;
366
- if (process.env.NODE_ENV !== "production") this._checkEmitRate();
460
+ const prev = this.state;
367
461
  super.patch(partial);
368
462
  const next = this.state;
369
463
  if (Object.is(prev, next)) return;
464
+ if (require_StateContainerRegistry.IS_DEV) this._checkEmitRate();
370
465
  if (this._hydrationStatus === "hydrating") this._changedWhileHydrating = true;
371
- if (this._pendingChange) this._pendingChange.next = next;
466
+ if (this._bridgeUnsub !== null) if (this._pendingChange) this._pendingChange.next = next;
372
467
  else this._pendingChange = {
373
468
  prev,
374
469
  next
@@ -376,13 +471,16 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
376
471
  if (this._registry.hasStateChangedListeners) this._registry.notifyStateChanged(this, prev, next);
377
472
  }
378
473
  applyState(next, source) {
379
- if (this._disposed) throw new Error(`Cannot emit state from disposed container ${this._name}`);
474
+ if (this._disposed) {
475
+ this._warnDisposedMutation("emit");
476
+ return;
477
+ }
380
478
  const prev = this.state;
381
479
  if (prev === next) return;
382
480
  if (this._equalityFn(prev, next)) return;
383
- if (process.env.NODE_ENV !== "production") this._checkEmitRate();
481
+ if (require_StateContainerRegistry.IS_DEV) this._checkEmitRate();
384
482
  if (this._hydrationStatus === "hydrating" && source !== "hydration") this._changedWhileHydrating = true;
385
- if (this._pendingChange) this._pendingChange.next = next;
483
+ if (this._bridgeUnsub !== null) if (this._pendingChange) this._pendingChange.next = next;
386
484
  else this._pendingChange = {
387
485
  prev,
388
486
  next
@@ -428,9 +526,15 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
428
526
  this.ensureHydrationPromise();
429
527
  this.setHydrationStatus("hydrating");
430
528
  }
529
+ _warnDisposedMutation(op) {
530
+ if (require_StateContainerRegistry.IS_DEV) console.warn(`[blac] ${this._name}: ${op}() after dispose ignored. This usually means an async method resolved after the last consumer unmounted. Guard with \`if (this.$blac.disposed) return\` after each \`await\`, or abort the work from \`onSystemEvent('dispose', ...)\`.`);
531
+ }
431
532
  _applyHydratedState(next) {
432
533
  if (this._disposed) return false;
433
- if (this._hydrationStatus !== "hydrating" || this._changedWhileHydrating) return false;
534
+ if (this._hydrationStatus !== "hydrating" || this._changedWhileHydrating) {
535
+ if (require_StateContainerRegistry.IS_DEV && this._changedWhileHydrating) console.warn(`[blac] ${this._name}: persisted state discarded because the container emitted while hydrating.`);
536
+ return false;
537
+ }
434
538
  this.applyState(next, "hydration");
435
539
  return true;
436
540
  }
@@ -525,19 +629,60 @@ var StateContainer = class extends _dirtytalk_structural.StructuralContainer {
525
629
  //#endregion
526
630
  //#region src/core/Cubit.ts
527
631
  /**
528
- * `Cubit<S>` is a `StateContainer<S>` with `emit` / `patch` exposed as
529
- * public mutation surface. Today it adds nothing structurally beyond
530
- * `StateContainer` — both are inherited from the underlying
531
- * `StructuralContainer<S>`. Kept as a real class (not a type alias) because
532
- * downstream code does `instance instanceof Cubit` checks.
632
+ * `Cubit<S>` is a `StateContainer<S>` that exposes mutation publicly.
533
633
  *
534
- * The class body is intentionally empty: a no-op `emit` override would
535
- * still go through `applyState`, and `patch` is inherited from
536
- * `StructuralContainer` (path-diffed, microtask-flushed). A caller that
537
- * wants "skip if no real change" patch semantics can wrap `patch`
538
- * themselves or call `emit` after a manual equality check.
634
+ * That is the whole difference, and it is a real one: on `StateContainer`
635
+ * `emit` / `patch` / `update` are `protected`, so a container mutates itself
636
+ * from its own methods and callers go through the API it chooses to publish.
637
+ * `Cubit` re-declares the three as `public` for the cases where a caller
638
+ * legitimately drives state from outside — test helpers, devtools
639
+ * time-travel, benchmarks.
640
+ *
641
+ * Reach for `StateContainer` when business logic should live in the class,
642
+ * and `Cubit` when the caller owns the transitions.
643
+ */
644
+ var Cubit = class extends StateContainer {
645
+ emit(next) {
646
+ super.emit(next);
647
+ }
648
+ patch(partial) {
649
+ super.patch(partial);
650
+ }
651
+ update(fn) {
652
+ super.update(fn);
653
+ }
654
+ };
655
+ //#endregion
656
+ //#region src/registry/acquire.ts
657
+ /**
658
+ * Acquire an instance with ref tracking (ownership semantics). Instance
659
+ * identity is derived purely from `args` (via the class's `static key(args)`,
660
+ * a structural hash of `args`, or the default sentinel when there are none).
661
+ *
662
+ * @param BlocClass - The StateContainer class constructor
663
+ * @param opts - `args` derives the instance key; `refId` names the reference
664
+ * for debugging and is auto-generated when omitted.
665
+ */
666
+ function acquire(BlocClass, opts) {
667
+ const registry = getRegistry();
668
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
669
+ return registry.acquire(BlocClass, key, {
670
+ canCreate: true,
671
+ countRef: true,
672
+ refId: opts?.refId,
673
+ args: opts?.args
674
+ });
675
+ }
676
+ /**
677
+ * Resolve the storage key an instance would be acquired under, given its
678
+ * construction `args`. This is the canonical key-computation path. Callers that
679
+ * both acquire and release against the `@internal` registry tier (e.g.
680
+ * `@blac/react` `useBloc`) must use this once and pass the same resolved key to
681
+ * both, so the ref is dropped under the key it was taken.
539
682
  */
540
- var Cubit = class extends StateContainer {};
683
+ function resolveInstanceKey(BlocClass, args) {
684
+ return getRegistry().resolveKey(BlocClass, void 0, args);
685
+ }
541
686
  //#endregion
542
687
  //#region src/registry/ensure.ts
543
688
  /**
@@ -545,7 +690,7 @@ var Cubit = class extends StateContainer {};
545
690
  * identity is derived purely from `args`, matching `acquire`.
546
691
  */
547
692
  function ensure(BlocClass, opts) {
548
- const registry = require_config.getRegistry();
693
+ const registry = getRegistry();
549
694
  const key = registry.resolveKey(BlocClass, void 0, opts?.args);
550
695
  return registry.ensure(BlocClass, key, opts?.args);
551
696
  }
@@ -568,11 +713,41 @@ Object.defineProperty(exports, "StateContainer", {
568
713
  return StateContainer;
569
714
  }
570
715
  });
716
+ Object.defineProperty(exports, "acquire", {
717
+ enumerable: true,
718
+ get: function() {
719
+ return acquire;
720
+ }
721
+ });
571
722
  Object.defineProperty(exports, "ensure", {
572
723
  enumerable: true,
573
724
  get: function() {
574
725
  return ensure;
575
726
  }
576
727
  });
728
+ Object.defineProperty(exports, "getRegistry", {
729
+ enumerable: true,
730
+ get: function() {
731
+ return getRegistry;
732
+ }
733
+ });
734
+ Object.defineProperty(exports, "getStats", {
735
+ enumerable: true,
736
+ get: function() {
737
+ return getStats;
738
+ }
739
+ });
740
+ Object.defineProperty(exports, "resolveInstanceKey", {
741
+ enumerable: true,
742
+ get: function() {
743
+ return resolveInstanceKey;
744
+ }
745
+ });
746
+ Object.defineProperty(exports, "setRegistry", {
747
+ enumerable: true,
748
+ get: function() {
749
+ return setRegistry;
750
+ }
751
+ });
577
752
 
578
- //# sourceMappingURL=ensure-B2DYCbbI.cjs.map
753
+ //# sourceMappingURL=ensure-ORVw-WRE.cjs.map