@blac/core 2.0.19 → 2.0.21

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 (236) 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-CvBOhAT2.js → StateContainerRegistry-vWgsD-RP.js} +277 -392
  5. package/dist/StateContainerRegistry-vWgsD-RP.js.map +1 -0
  6. package/dist/config.d.cts +2 -2
  7. package/dist/config.d.ts +2 -2
  8. package/dist/constants.d.cts +11 -20
  9. package/dist/constants.d.ts +11 -20
  10. package/dist/core/Cubit.d.ts +14 -10
  11. package/dist/core/StateContainer.d.ts +61 -4
  12. package/dist/core/StateContainerRegistry.d.ts +119 -16
  13. package/dist/core/meta.d.ts +5 -11
  14. package/dist/core/symbols.d.ts +24 -1
  15. package/dist/decorators/blac.d.ts +28 -26
  16. package/dist/{ensure-CQimeD0I.cjs → ensure-ORVw-WRE.cjs} +234 -40
  17. package/dist/ensure-ORVw-WRE.cjs.map +1 -0
  18. package/dist/{ensure-DTTTd2h8.js → ensure-k-6q7O25.js} +203 -39
  19. package/dist/ensure-k-6q7O25.js.map +1 -0
  20. package/dist/index.cjs +213 -32
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +6 -8
  23. package/dist/index.d.ts +6 -8
  24. package/dist/index.js +192 -12
  25. package/dist/index.js.map +1 -1
  26. package/dist/plugin/BlacPlugin.d.ts +14 -0
  27. package/dist/plugin/PluginManager.d.ts +23 -7
  28. package/dist/plugins.cjs +400 -3
  29. package/dist/plugins.cjs.map +1 -0
  30. package/dist/plugins.d.cts +6 -2
  31. package/dist/plugins.d.ts +6 -2
  32. package/dist/plugins.js +398 -1
  33. package/dist/plugins.js.map +1 -0
  34. package/dist/registry/acquire.d.ts +2 -2
  35. package/dist/registry/config.d.ts +9 -0
  36. package/dist/registry/management.d.ts +3 -0
  37. package/dist/registry/queries.d.ts +15 -0
  38. package/dist/registry/release.d.ts +3 -3
  39. package/dist/testing.cjs +13 -15
  40. package/dist/testing.cjs.map +1 -1
  41. package/dist/testing.d.cts +1 -1
  42. package/dist/testing.d.ts +1 -1
  43. package/dist/testing.js +2 -4
  44. package/dist/testing.js.map +1 -1
  45. package/dist/types/branded.d.ts +3 -3
  46. package/dist/types/utilities.d.ts +45 -18
  47. package/dist/utils/idGenerator.d.ts +0 -36
  48. package/dist/utils/static-props.d.ts +25 -1
  49. package/dist/utils/structural-key.d.ts +0 -7
  50. package/dist/watch/index.d.ts +1 -1
  51. package/dist/watch/watch.d.ts +22 -3
  52. package/package.json +17 -55
  53. package/dist/StateContainerRegistry-4Ljd9EJx.js +0 -1018
  54. package/dist/StateContainerRegistry-4Ljd9EJx.js.map +0 -1
  55. package/dist/StateContainerRegistry-B1GYx9Xo.js +0 -975
  56. package/dist/StateContainerRegistry-B1GYx9Xo.js.map +0 -1
  57. package/dist/StateContainerRegistry-B_ViBLvJ.js +0 -975
  58. package/dist/StateContainerRegistry-B_ViBLvJ.js.map +0 -1
  59. package/dist/StateContainerRegistry-C0dCNlTF.js +0 -1005
  60. package/dist/StateContainerRegistry-C0dCNlTF.js.map +0 -1
  61. package/dist/StateContainerRegistry-CEWpc1bj.cjs +0 -1113
  62. package/dist/StateContainerRegistry-CEWpc1bj.cjs.map +0 -1
  63. package/dist/StateContainerRegistry-CSNm2Ws5.cjs.map +0 -1
  64. package/dist/StateContainerRegistry-CchRjnjX.cjs +0 -1094
  65. package/dist/StateContainerRegistry-CchRjnjX.cjs.map +0 -1
  66. package/dist/StateContainerRegistry-CvBOhAT2.js.map +0 -1
  67. package/dist/StateContainerRegistry-D9BIRjwv.cjs +0 -1088
  68. package/dist/StateContainerRegistry-D9BIRjwv.cjs.map +0 -1
  69. package/dist/StateContainerRegistry-DJQqLrli.cjs +0 -1046
  70. package/dist/StateContainerRegistry-DJQqLrli.cjs.map +0 -1
  71. package/dist/StateContainerRegistry-DVIBTxGZ.js +0 -999
  72. package/dist/StateContainerRegistry-DVIBTxGZ.js.map +0 -1
  73. package/dist/StateContainerRegistry-Dj77cok9.js +0 -1005
  74. package/dist/StateContainerRegistry-Dj77cok9.js.map +0 -1
  75. package/dist/StateContainerRegistry-FWKzPfS-.cjs +0 -1046
  76. package/dist/StateContainerRegistry-FWKzPfS-.cjs.map +0 -1
  77. package/dist/StateContainerRegistry-lIwo-0m3.cjs +0 -1094
  78. package/dist/StateContainerRegistry-lIwo-0m3.cjs.map +0 -1
  79. package/dist/acquire-B1Wuqla6.cjs +0 -46
  80. package/dist/acquire-B1Wuqla6.cjs.map +0 -1
  81. package/dist/acquire-BP-ZfUH2.js +0 -35
  82. package/dist/acquire-BP-ZfUH2.js.map +0 -1
  83. package/dist/acquire-BRIJVJaA.js +0 -35
  84. package/dist/acquire-BRIJVJaA.js.map +0 -1
  85. package/dist/acquire-BZIs6tpN.cjs +0 -46
  86. package/dist/acquire-BZIs6tpN.cjs.map +0 -1
  87. package/dist/acquire-C3nOb3XR.cjs +0 -46
  88. package/dist/acquire-C3nOb3XR.cjs.map +0 -1
  89. package/dist/acquire-C4WAS13G.cjs +0 -46
  90. package/dist/acquire-C4WAS13G.cjs.map +0 -1
  91. package/dist/acquire-C7beGI55.cjs +0 -46
  92. package/dist/acquire-C7beGI55.cjs.map +0 -1
  93. package/dist/acquire-CbMz7gWs.cjs +0 -46
  94. package/dist/acquire-CbMz7gWs.cjs.map +0 -1
  95. package/dist/acquire-CwB083au.js +0 -35
  96. package/dist/acquire-CwB083au.js.map +0 -1
  97. package/dist/acquire-DHEOEVcj.cjs +0 -46
  98. package/dist/acquire-DHEOEVcj.cjs.map +0 -1
  99. package/dist/acquire-DXEQDZGr.js +0 -35
  100. package/dist/acquire-DXEQDZGr.js.map +0 -1
  101. package/dist/acquire-Dg-uXwjF.js +0 -35
  102. package/dist/acquire-Dg-uXwjF.js.map +0 -1
  103. package/dist/acquire-Don7499S.js +0 -35
  104. package/dist/acquire-Don7499S.js.map +0 -1
  105. package/dist/acquire-G8aB3GAx.js +0 -35
  106. package/dist/acquire-G8aB3GAx.js.map +0 -1
  107. package/dist/branded-BybA0_xw.cjs +0 -18
  108. package/dist/branded-BybA0_xw.cjs.map +0 -1
  109. package/dist/branded-DkbUzncc.js +0 -13
  110. package/dist/branded-DkbUzncc.js.map +0 -1
  111. package/dist/config-8pyOC5gv.js +0 -16
  112. package/dist/config-8pyOC5gv.js.map +0 -1
  113. package/dist/config-B1l8ZGlU.cjs +0 -32
  114. package/dist/config-B1l8ZGlU.cjs.map +0 -1
  115. package/dist/config-C7Ktkjh2.cjs +0 -32
  116. package/dist/config-C7Ktkjh2.cjs.map +0 -1
  117. package/dist/config-COT4Xkbc.js +0 -16
  118. package/dist/config-COT4Xkbc.js.map +0 -1
  119. package/dist/config-CzcoAvBo.js +0 -16
  120. package/dist/config-CzcoAvBo.js.map +0 -1
  121. package/dist/config-D6BoWWPv.js +0 -16
  122. package/dist/config-D6BoWWPv.js.map +0 -1
  123. package/dist/config-DVM_ESQt.js +0 -16
  124. package/dist/config-DVM_ESQt.js.map +0 -1
  125. package/dist/config-DVMnlHLv.cjs +0 -32
  126. package/dist/config-DVMnlHLv.cjs.map +0 -1
  127. package/dist/config-Dk1FxfXj.js +0 -16
  128. package/dist/config-Dk1FxfXj.js.map +0 -1
  129. package/dist/config-b2z51Y_C.cjs +0 -32
  130. package/dist/config-b2z51Y_C.cjs.map +0 -1
  131. package/dist/config-buwpT7l3.js +0 -16
  132. package/dist/config-buwpT7l3.js.map +0 -1
  133. package/dist/config-d9_U58ef.cjs +0 -32
  134. package/dist/config-d9_U58ef.cjs.map +0 -1
  135. package/dist/config-hWTayX76.cjs +0 -32
  136. package/dist/config-hWTayX76.cjs.map +0 -1
  137. package/dist/config-sCPKPYxZ.cjs +0 -32
  138. package/dist/config-sCPKPYxZ.cjs.map +0 -1
  139. package/dist/debug.cjs +0 -14
  140. package/dist/debug.d.cts +0 -34
  141. package/dist/debug.d.ts +0 -34
  142. package/dist/debug.js +0 -4
  143. package/dist/ensure-B1dEDsZV.cjs +0 -559
  144. package/dist/ensure-B1dEDsZV.cjs.map +0 -1
  145. package/dist/ensure-B9oOqpOB.cjs +0 -558
  146. package/dist/ensure-B9oOqpOB.cjs.map +0 -1
  147. package/dist/ensure-BfYnvAsI.js +0 -709
  148. package/dist/ensure-BfYnvAsI.js.map +0 -1
  149. package/dist/ensure-Bm91o37h.js +0 -536
  150. package/dist/ensure-Bm91o37h.js.map +0 -1
  151. package/dist/ensure-C1a8IFWy.js +0 -535
  152. package/dist/ensure-C1a8IFWy.js.map +0 -1
  153. package/dist/ensure-CLQEx0Nn.cjs +0 -528
  154. package/dist/ensure-CLQEx0Nn.cjs.map +0 -1
  155. package/dist/ensure-CPMiGvov.js +0 -493
  156. package/dist/ensure-CPMiGvov.js.map +0 -1
  157. package/dist/ensure-CQimeD0I.cjs.map +0 -1
  158. package/dist/ensure-DEXSmA-N.js +0 -526
  159. package/dist/ensure-DEXSmA-N.js.map +0 -1
  160. package/dist/ensure-DTTTd2h8.js.map +0 -1
  161. package/dist/ensure-Dx86f80B.cjs +0 -567
  162. package/dist/ensure-Dx86f80B.cjs.map +0 -1
  163. package/dist/ensure-DzqGej43.js +0 -526
  164. package/dist/ensure-DzqGej43.js.map +0 -1
  165. package/dist/ensure-VuiNPccZ.cjs +0 -559
  166. package/dist/ensure-VuiNPccZ.cjs.map +0 -1
  167. package/dist/ensure-_Oh8XPm4.cjs +0 -732
  168. package/dist/ensure-_Oh8XPm4.cjs.map +0 -1
  169. package/dist/ensure-fsQMjaQL.cjs +0 -567
  170. package/dist/ensure-fsQMjaQL.cjs.map +0 -1
  171. package/dist/ensure-vxAGa2v3.js +0 -536
  172. package/dist/ensure-vxAGa2v3.js.map +0 -1
  173. package/dist/management-14vsHr4t.cjs +0 -85
  174. package/dist/management-14vsHr4t.cjs.map +0 -1
  175. package/dist/management-444tdCBG.js +0 -38
  176. package/dist/management-444tdCBG.js.map +0 -1
  177. package/dist/management-7jLjVHJd.js +0 -38
  178. package/dist/management-7jLjVHJd.js.map +0 -1
  179. package/dist/management-AFuqQEwz.js +0 -38
  180. package/dist/management-AFuqQEwz.js.map +0 -1
  181. package/dist/management-BodVLAfJ.cjs +0 -85
  182. package/dist/management-BodVLAfJ.cjs.map +0 -1
  183. package/dist/management-BqGBdL01.js +0 -38
  184. package/dist/management-BqGBdL01.js.map +0 -1
  185. package/dist/management-BvUAjril.js +0 -38
  186. package/dist/management-BvUAjril.js.map +0 -1
  187. package/dist/management-C2wv4vGS.cjs +0 -85
  188. package/dist/management-C2wv4vGS.cjs.map +0 -1
  189. package/dist/management-D2pjr38g.js +0 -38
  190. package/dist/management-D2pjr38g.js.map +0 -1
  191. package/dist/management-D5WsZoTV.js +0 -38
  192. package/dist/management-D5WsZoTV.js.map +0 -1
  193. package/dist/management-DAV9sN-k.cjs +0 -85
  194. package/dist/management-DAV9sN-k.cjs.map +0 -1
  195. package/dist/management-Df7Y2sF1.cjs +0 -85
  196. package/dist/management-Df7Y2sF1.cjs.map +0 -1
  197. package/dist/management-DwO0nBzL.cjs +0 -85
  198. package/dist/management-DwO0nBzL.cjs.map +0 -1
  199. package/dist/management-GcnNJjnm.cjs +0 -85
  200. package/dist/management-GcnNJjnm.cjs.map +0 -1
  201. package/dist/types.cjs +0 -3
  202. package/dist/types.d.cts +0 -8
  203. package/dist/types.d.ts +0 -8
  204. package/dist/types.js +0 -2
  205. package/dist/watch-B91opmva.cjs +0 -70
  206. package/dist/watch-B91opmva.cjs.map +0 -1
  207. package/dist/watch-BHfCtbn1.cjs +0 -119
  208. package/dist/watch-BHfCtbn1.cjs.map +0 -1
  209. package/dist/watch-BmC-Tyqg.js +0 -59
  210. package/dist/watch-BmC-Tyqg.js.map +0 -1
  211. package/dist/watch-CKWt788i.cjs +0 -70
  212. package/dist/watch-CKWt788i.cjs.map +0 -1
  213. package/dist/watch-CfrSSrRY.js +0 -59
  214. package/dist/watch-CfrSSrRY.js.map +0 -1
  215. package/dist/watch-Cnh3PtQA.cjs +0 -70
  216. package/dist/watch-Cnh3PtQA.cjs.map +0 -1
  217. package/dist/watch-D01MdwKy.js +0 -108
  218. package/dist/watch-D01MdwKy.js.map +0 -1
  219. package/dist/watch-D8hwbFU1.js +0 -59
  220. package/dist/watch-D8hwbFU1.js.map +0 -1
  221. package/dist/watch-DPVUwPUY.js +0 -59
  222. package/dist/watch-DPVUwPUY.js.map +0 -1
  223. package/dist/watch-DVmvZBMD.cjs +0 -70
  224. package/dist/watch-DVmvZBMD.cjs.map +0 -1
  225. package/dist/watch-DkDGmGAx.cjs +0 -119
  226. package/dist/watch-DkDGmGAx.cjs.map +0 -1
  227. package/dist/watch-DztcJuUy.cjs +0 -119
  228. package/dist/watch-DztcJuUy.cjs.map +0 -1
  229. package/dist/watch-IrR8G28N.js +0 -108
  230. package/dist/watch-IrR8G28N.js.map +0 -1
  231. package/dist/watch-entry.cjs +0 -4
  232. package/dist/watch-entry.d.cts +0 -24
  233. package/dist/watch-entry.d.ts +0 -24
  234. package/dist/watch-entry.js +0 -2
  235. package/dist/watch-hx0r92Zc.js +0 -108
  236. package/dist/watch-hx0r92Zc.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,11 +1,6 @@
1
- import { a as INIT_CONFIG, c as isExcludedFromDevTools, d as PluginManager, f as configureBlac, h as shallowEqualState, i as APPLY_DEPS, l as isKeepAliveClass, m as resetBlacConfig, n as getPluginManager, o as REMOVE_DEPS_OWNER, p as getBlacConfig, r as globalRegistry, t as StateContainerRegistry, u as BLAC_STATIC_PROPS } from "./StateContainerRegistry-Dj77cok9.js";
2
- import { i as StateContainer, n as Cubit, r as DEP_BRAND, t as ensure } from "./ensure-Bm91o37h.js";
3
- import { n as getStats, r as setRegistry, t as getRegistry } from "./config-CzcoAvBo.js";
4
- import { n as resolveInstanceKey, t as acquire } from "./acquire-BRIJVJaA.js";
5
- import { a as getAll, c as hasInstance, i as forEach, n as clearAll, o as getRefCount, r as register, s as getRefIds, t as clear } from "./management-AFuqQEwz.js";
6
- import { n as watch, t as instance } from "./watch-hx0r92Zc.js";
7
- import { t as instanceId } from "./branded-DkbUzncc.js";
8
- import { ALL_PATHS } from "@dirtytalk/structural";
1
+ import { _ as resetBlacConfig, a as ON_DISPOSE, c as WITH_TRACKED_STATE, d as isExcludedFromDevTools, f as isKeepAliveClass, g as getBlacConfig, h as configureBlac, i as INIT_CONFIG, l as getBlacName, n as globalRegistry, o as REMOVE_DEPS_OWNER, p as BLAC_STATIC_PROPS, r as APPLY_DEPS, t as StateContainerRegistry, v as shallowEqualState } from "./StateContainerRegistry-vWgsD-RP.js";
2
+ import { a as DEP_BRAND, c as getStats, i as Cubit, l as setRegistry, n as acquire, o as StateContainer, r as resolveInstanceKey, s as getRegistry, t as ensure } from "./ensure-k-6q7O25.js";
3
+ import { ALL_PATHS, ALL_PATHS as ALL_PATHS$1 } from "@dirtytalk/structural";
9
4
  //#region src/registry/borrow.ts
10
5
  function resolveBorrowKey(BlocClass, target) {
11
6
  return getRegistry().resolveKey(BlocClass, void 0, target?.args);
@@ -22,9 +17,9 @@ function borrowSafe(BlocClass, target) {
22
17
  * Release a reference to an instance. Instance identity is derived purely from
23
18
  * `args` (must match the `args` it was acquired with).
24
19
  *
25
- * @param opts.args - Construction/identity args; derives the instance key
26
- * @param opts.refId - The specific ref to drop; drops one arbitrary ref if omitted
27
- * @param opts.forceDispose - Force immediate disposal regardless of refs
20
+ * @param opts - `args` derives the instance key (must match acquire);
21
+ * `refId` picks the ref to drop, otherwise one arbitrary ref goes;
22
+ * `forceDispose` disposes immediately regardless of remaining refs.
28
23
  */
29
24
  function release(BlocClass, opts) {
30
25
  const registry = getRegistry();
@@ -32,6 +27,58 @@ function release(BlocClass, opts) {
32
27
  registry.release(BlocClass, key, opts?.forceDispose ?? false, opts?.refId);
33
28
  }
34
29
  //#endregion
30
+ //#region src/registry/queries.ts
31
+ /**
32
+ * @public
33
+ */
34
+ function hasInstance(BlocClass, opts) {
35
+ const registry = getRegistry();
36
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
37
+ return registry.hasInstance(BlocClass, key);
38
+ }
39
+ /**
40
+ * @public
41
+ */
42
+ function getRefCount(BlocClass, opts) {
43
+ const registry = getRegistry();
44
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
45
+ return registry.getRefCount(BlocClass, key);
46
+ }
47
+ /**
48
+ * @public
49
+ */
50
+ function getRefIds(BlocClass, opts) {
51
+ const registry = getRegistry();
52
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
53
+ return registry.getRefIds(BlocClass, key);
54
+ }
55
+ /**
56
+ * @public
57
+ */
58
+ function getAll(BlocClass) {
59
+ return getRegistry().getAll(BlocClass);
60
+ }
61
+ /**
62
+ * @public
63
+ */
64
+ function forEach(BlocClass, callback) {
65
+ getRegistry().forEach(BlocClass, callback);
66
+ }
67
+ //#endregion
68
+ //#region src/registry/management.ts
69
+ function clear(BlocClass) {
70
+ getRegistry().clear(BlocClass);
71
+ }
72
+ function clearAll() {
73
+ getRegistry().clearAll();
74
+ }
75
+ /**
76
+ * @public
77
+ */
78
+ function register(BlocClass) {
79
+ getRegistry().register(BlocClass);
80
+ }
81
+ //#endregion
35
82
  //#region src/decorators/blac.ts
36
83
  /**
37
84
  * Decorator to configure StateContainer classes.
@@ -43,6 +90,9 @@ function release(BlocClass, opts) {
43
90
  *
44
91
  * @blac({ excludeFromDevTools: true })
45
92
  * class InternalBloc extends Cubit<InternalState> {}
93
+ *
94
+ * @blac({ keepAlive: true, key: (args) => args.userId })
95
+ * class UserBloc extends Cubit<UserState> {}
46
96
  * ```
47
97
  *
48
98
  * @example Function syntax (no decorator support needed)
@@ -58,10 +108,140 @@ function blac(options) {
58
108
  if ("excludeFromDevTools" in options && options.excludeFromDevTools) target[BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS] = true;
59
109
  if ("equality" in options && typeof options.equality === "function") target[BLAC_STATIC_PROPS.EQUALITY] = options.equality;
60
110
  if ("key" in options && typeof options.key === "function") target[BLAC_STATIC_PROPS.KEY] = options.key;
111
+ if ("name" in options && typeof options.name === "string") target[BLAC_STATIC_PROPS.BLAC_NAME] = options.name;
61
112
  return target;
62
113
  };
63
114
  }
64
115
  //#endregion
65
- export { ALL_PATHS, APPLY_DEPS, Cubit, DEP_BRAND, INIT_CONFIG, PluginManager, REMOVE_DEPS_OWNER, StateContainer, StateContainerRegistry, acquire, blac, borrow, borrowSafe, clear, clearAll, configureBlac, ensure, forEach, getAll, getBlacConfig, getPluginManager, getRefCount, getRefIds, getRegistry, getStats, globalRegistry, hasInstance, instance, instanceId, isExcludedFromDevTools, isKeepAliveClass, register, release, resetBlacConfig, resolveInstanceKey, setRegistry, shallowEqualState, watch };
116
+ //#region src/watch/watch.ts
117
+ const STOP = Symbol("watch.STOP");
118
+ const BLOC_REF_MARKER = Symbol("BlocRef");
119
+ /**
120
+ * Create a reference to a specific bloc instance, identified by its `args`.
121
+ * The key is derived the same way `useBloc`/`acquire` derive it.
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {
126
+ * console.log(userBloc.state.name);
127
+ * });
128
+ * ```
129
+ */
130
+ function instance(BlocClass, args) {
131
+ return {
132
+ [BLOC_REF_MARKER]: true,
133
+ blocClass: BlocClass,
134
+ instanceId: resolveInstanceKey(BlocClass, args),
135
+ args
136
+ };
137
+ }
138
+ function isBlocRef(input) {
139
+ return typeof input === "object" && input !== null && BLOC_REF_MARKER in input;
140
+ }
141
+ function toWatchTarget(input) {
142
+ const registry = getRegistry();
143
+ if (isBlocRef(input)) return {
144
+ blocClass: input.blocClass,
145
+ key: input.instanceId,
146
+ args: input.args
147
+ };
148
+ return {
149
+ blocClass: input,
150
+ key: registry.resolveKey(input, void 0, void 0),
151
+ args: void 0
152
+ };
153
+ }
154
+ let watchRefSeq = 0;
155
+ /**
156
+ * Acquire a real ref (countRef: true) for the target, carrying its `args`
157
+ * through so a not-yet-created instance is initialized correctly. The
158
+ * caller is responsible for releasing `refId` in cleanup.
159
+ */
160
+ function resolveBloc(target, refId) {
161
+ return getRegistry().acquire(target.blocClass, target.key, {
162
+ countRef: true,
163
+ refId,
164
+ args: target.args
165
+ });
166
+ }
167
+ /**
168
+ * Passive lookup for `{ create: false }`: never creates the instance and
169
+ * never takes a ref. Returns `undefined` when no instance currently exists.
170
+ */
171
+ function resolveBlocPassive(target) {
172
+ const registry = getRegistry();
173
+ try {
174
+ return registry.acquire(target.blocClass, target.key, {
175
+ canCreate: false,
176
+ countRef: false,
177
+ args: target.args
178
+ });
179
+ } catch {
180
+ return;
181
+ }
182
+ }
183
+ function isArray(input) {
184
+ return Array.isArray(input);
185
+ }
186
+ function watchImpl(blocsOrBloc, callback, options) {
187
+ const isSingle = !isArray(blocsOrBloc);
188
+ const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;
189
+ const registry = getRegistry();
190
+ const create = options?.create ?? true;
191
+ const targets = inputs.map(toWatchTarget);
192
+ const refIds = targets.map(() => `_watch_${watchRefSeq++}`);
193
+ let disposed = false;
194
+ const instances = targets.map((target, i) => create ? resolveBloc(target, refIds[i]) : resolveBlocPassive(target));
195
+ const channelUnsubs = [];
196
+ const disposedUnsubs = [];
197
+ const cleanup = () => {
198
+ if (disposed) return;
199
+ disposed = true;
200
+ for (const unsub of channelUnsubs) unsub?.();
201
+ for (const unsub of disposedUnsubs) unsub?.();
202
+ channelUnsubs.length = 0;
203
+ disposedUnsubs.length = 0;
204
+ if (create) for (let i = 0; i < targets.length; i++) registry.release(targets[i].blocClass, targets[i].key, false, refIds[i]);
205
+ };
206
+ const runCallback = () => {
207
+ if (disposed) return;
208
+ if (instances.some((i) => i === void 0)) return;
209
+ if (callback(isSingle ? instances[0] : instances) === STOP) cleanup();
210
+ };
211
+ const subscribeAt = (index) => {
212
+ channelUnsubs[index] = instances[index]?.channel.subscribe(() => ALL_PATHS$1, runCallback);
213
+ };
214
+ const resubscribeAt = (index) => {
215
+ if (disposed) return;
216
+ instances[index] = create ? resolveBloc(targets[index], refIds[index]) : resolveBlocPassive(targets[index]);
217
+ subscribeAt(index);
218
+ subscribeDisposeAt(index);
219
+ runCallback();
220
+ };
221
+ const subscribeDisposeAt = (index) => {
222
+ disposedUnsubs[index] = instances[index]?.[ON_DISPOSE](() => {
223
+ channelUnsubs[index]?.();
224
+ channelUnsubs[index] = void 0;
225
+ queueMicrotask(() => resubscribeAt(index));
226
+ });
227
+ };
228
+ for (let i = 0; i < instances.length; i++) subscribeAt(i);
229
+ for (let i = 0; i < instances.length; i++) subscribeDisposeAt(i);
230
+ runCallback();
231
+ return cleanup;
232
+ }
233
+ const watch = Object.assign(watchImpl, { STOP });
234
+ //#endregion
235
+ //#region src/types/branded.ts
236
+ /**
237
+ * Create a branded InstanceId from a string
238
+ * @param id - The string ID to brand
239
+ * @returns Branded InstanceId
240
+ */
241
+ function instanceId(id) {
242
+ return id;
243
+ }
244
+ //#endregion
245
+ export { ALL_PATHS, APPLY_DEPS, Cubit, DEP_BRAND, INIT_CONFIG, ON_DISPOSE, REMOVE_DEPS_OWNER, StateContainer, StateContainerRegistry, WITH_TRACKED_STATE, acquire, blac, borrow, borrowSafe, clear, clearAll, configureBlac, ensure, forEach, getAll, getBlacConfig, getBlacName, getRefCount, getRefIds, getRegistry, getStats, globalRegistry, hasInstance, instance, instanceId, isExcludedFromDevTools, isKeepAliveClass, register, release, resetBlacConfig, resolveInstanceKey, setRegistry, shallowEqualState, watch };
66
246
 
67
247
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/registry/borrow.ts","../src/registry/release.ts","../src/decorators/blac.ts"],"sourcesContent":["import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * How to identify the instance to borrow: the same `args` shape `useBloc`\n * accepts, resolved through the class's `static key(args)` so call sites use\n * the *same* shape they pass to `useBloc` instead of hand-deriving the key.\n *\n * `borrowSafe(ChannelBloc, { args: { channelId } })` and\n * `useBloc(ChannelBloc, { args: { channelId } })` therefore always agree.\n */\nexport type BorrowTarget<T extends StateContainerConstructor> = {\n args?: ExtractArgs<T>;\n};\n\nfunction resolveBorrowKey<T extends StateContainerConstructor>(\n BlocClass: T,\n target: BorrowTarget<T> | undefined,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, target?.args);\n}\n\nexport function borrow<T extends StateContainerConstructor>(\n BlocClass: T,\n target?: BorrowTarget<T>,\n): InstanceType<T> {\n return getRegistry().borrow(BlocClass, resolveBorrowKey(BlocClass, target));\n}\n\nexport function borrowSafe<T extends StateContainerConstructor>(\n BlocClass: T,\n target?: BorrowTarget<T>,\n):\n | { error: Error; instance: null }\n | { error: null; instance: InstanceType<T> } {\n return getRegistry().borrowSafe(\n BlocClass,\n resolveBorrowKey(BlocClass, target),\n );\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Release a reference to an instance. Instance identity is derived purely from\n * `args` (must match the `args` it was acquired with).\n *\n * @param opts.args - Construction/identity args; derives the instance key\n * @param opts.refId - The specific ref to drop; drops one arbitrary ref if omitted\n * @param opts.forceDispose - Force immediate disposal regardless of refs\n */\nexport function release<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string; forceDispose?: boolean },\n): void {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n registry.release(BlocClass, key, opts?.forceDispose ?? false, opts?.refId);\n}\n","import { BLAC_STATIC_PROPS } from '../constants';\nimport type { EqualityFn } from '../config';\n\n/**\n * Configuration options for the @blac decorator.\n * Only one option can be specified at a time (union type).\n */\nexport type BlacOptions =\n /** Mark bloc to never be auto-disposed when ref count reaches 0 */\n | { keepAlive: true }\n /** Exclude bloc from DevTools tracking (prevents infinite loops) */\n | { excludeFromDevTools: true }\n /**\n * Override the global equality check for this bloc.\n * Return `true` to skip the emit (states considered equal).\n */\n | { equality: EqualityFn }\n /**\n * Override the default structural-hash identity key.\n * The function receives `args` and returns the instance key string.\n * Distinct return values → distinct instances; identical values → shared instance.\n * Non-identity fields can be excluded so they don't fork new instances.\n */\n | { key: (args: any) => string };\n\n/**\n * Decorator to configure StateContainer classes.\n *\n * @example Decorator syntax (requires experimentalDecorators or TC39 decorators)\n * ```ts\n * @blac({ keepAlive: true })\n * class AuthBloc extends Cubit<AuthState> {}\n *\n * @blac({ excludeFromDevTools: true })\n * class InternalBloc extends Cubit<InternalState> {}\n * ```\n *\n * @example Function syntax (no decorator support needed)\n * ```ts\n * const AuthBloc = blac({ keepAlive: true })(\n * class extends Cubit<AuthState> {}\n * );\n * ```\n */\nexport function blac(options: BlacOptions) {\n return function <T extends new (...args: any[]) => any>(\n target: T,\n _context?: ClassDecoratorContext,\n ): T {\n if ('keepAlive' in options && options.keepAlive) {\n (target as any)[BLAC_STATIC_PROPS.KEEP_ALIVE] = true;\n }\n if ('excludeFromDevTools' in options && options.excludeFromDevTools) {\n (target as any)[BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS] = true;\n }\n if ('equality' in options && typeof options.equality === 'function') {\n (target as any)[BLAC_STATIC_PROPS.EQUALITY] = options.equality;\n }\n if ('key' in options && typeof options.key === 'function') {\n (target as any)[BLAC_STATIC_PROPS.KEY] = options.key;\n }\n return target;\n };\n}\n"],"mappings":";;;;;;;;;AAkBA,SAAS,iBACP,WACA,QACQ;CACR,OAAO,YAAY,EAAE,WAAW,WAAW,KAAA,GAAW,QAAQ,IAAI;AACpE;AAEA,SAAgB,OACd,WACA,QACiB;CACjB,OAAO,YAAY,EAAE,OAAO,WAAW,iBAAiB,WAAW,MAAM,CAAC;AAC5E;AAEA,SAAgB,WACd,WACA,QAG6C;CAC7C,OAAO,YAAY,EAAE,WACnB,WACA,iBAAiB,WAAW,MAAM,CACpC;AACF;;;;;;;;;;;AC5BA,SAAgB,QACd,WACA,MACM;CACN,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,SAAS,QAAQ,WAAW,KAAK,MAAM,gBAAgB,OAAO,MAAM,KAAK;AAC3E;;;;;;;;;;;;;;;;;;;;;;ACuBA,SAAgB,KAAK,SAAsB;CACzC,OAAO,SACL,QACA,UACG;EACH,IAAI,eAAe,WAAW,QAAQ,WACpC,OAAgB,kBAAkB,cAAc;EAElD,IAAI,yBAAyB,WAAW,QAAQ,qBAC9C,OAAgB,kBAAkB,yBAAyB;EAE7D,IAAI,cAAc,WAAW,OAAO,QAAQ,aAAa,YACvD,OAAgB,kBAAkB,YAAY,QAAQ;EAExD,IAAI,SAAS,WAAW,OAAO,QAAQ,QAAQ,YAC7C,OAAgB,kBAAkB,OAAO,QAAQ;EAEnD,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"index.js","names":["ALL_PATHS"],"sources":["../src/registry/borrow.ts","../src/registry/release.ts","../src/registry/queries.ts","../src/registry/management.ts","../src/decorators/blac.ts","../src/watch/watch.ts","../src/types/branded.ts"],"sourcesContent":["import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * How to identify the instance to borrow: the same `args` shape `useBloc`\n * accepts, resolved through the class's `static key(args)` so call sites use\n * the *same* shape they pass to `useBloc` instead of hand-deriving the key.\n *\n * `borrowSafe(ChannelBloc, { args: { channelId } })` and\n * `useBloc(ChannelBloc, { args: { channelId } })` therefore always agree.\n */\nexport type BorrowTarget<T extends StateContainerConstructor> = {\n args?: ExtractArgs<T>;\n};\n\nfunction resolveBorrowKey<T extends StateContainerConstructor>(\n BlocClass: T,\n target: BorrowTarget<T> | undefined,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, target?.args);\n}\n\nexport function borrow<T extends StateContainerConstructor>(\n BlocClass: T,\n target?: BorrowTarget<T>,\n): InstanceType<T> {\n return getRegistry().borrow(BlocClass, resolveBorrowKey(BlocClass, target));\n}\n\nexport function borrowSafe<T extends StateContainerConstructor>(\n BlocClass: T,\n target?: BorrowTarget<T>,\n):\n | { error: Error; instance: null }\n | { error: null; instance: InstanceType<T> } {\n return getRegistry().borrowSafe(\n BlocClass,\n resolveBorrowKey(BlocClass, target),\n );\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Release a reference to an instance. Instance identity is derived purely from\n * `args` (must match the `args` it was acquired with).\n *\n * @param opts - `args` derives the instance key (must match acquire);\n * `refId` picks the ref to drop, otherwise one arbitrary ref goes;\n * `forceDispose` disposes immediately regardless of remaining refs.\n */\nexport function release<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string; forceDispose?: boolean },\n): void {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n registry.release(BlocClass, key, opts?.forceDispose ?? false, opts?.refId);\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n InstanceReadonlyState,\n} from '../types/utilities';\n\n/**\n * @public\n */\nexport function hasInstance<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): boolean {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.hasInstance(BlocClass, key);\n}\n\n/**\n * @public\n */\nexport function getRefCount<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): number {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.getRefCount(BlocClass, key);\n}\n\n/**\n * @public\n */\nexport function getRefIds<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): string[] {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.getRefIds(BlocClass, key);\n}\n\n/**\n * @public\n */\nexport function getAll<T extends StateContainerConstructor>(\n BlocClass: T,\n): InstanceReadonlyState<T>[] {\n return getRegistry().getAll(BlocClass);\n}\n\n/**\n * @public\n */\nexport function forEach<T extends StateContainerConstructor>(\n BlocClass: T,\n callback: (instance: InstanceReadonlyState<T>) => void,\n): void {\n getRegistry().forEach(BlocClass, callback);\n}\n","import { getRegistry } from './config';\nimport type { StateContainerConstructor } from '../types/utilities';\n\nexport function clear<T extends StateContainerConstructor>(BlocClass: T): void {\n getRegistry().clear(BlocClass);\n}\n\nexport function clearAll(): void {\n getRegistry().clearAll();\n}\n\n/**\n * @public\n */\nexport function register<T extends StateContainerConstructor>(\n BlocClass: T,\n): void {\n getRegistry().register(BlocClass);\n}\n","import { BLAC_STATIC_PROPS } from '../constants';\nimport type { EqualityFn } from '../config';\n\n/**\n * Configuration options for the `@blac` decorator. Any combination may be\n * given at once.\n */\nexport interface BlacOptions {\n /** Mark bloc to never be auto-disposed when ref count reaches 0 */\n keepAlive?: true;\n /** Exclude bloc from DevTools tracking (prevents infinite loops) */\n excludeFromDevTools?: true;\n /**\n * Override the global equality check for this bloc.\n * Return `true` to skip the emit (states considered equal).\n */\n equality?: EqualityFn;\n /**\n * Override the default structural-hash identity key.\n * The function receives `args` and returns the instance key string.\n * Distinct return values → distinct instances; identical values → shared instance.\n * Non-identity fields can be excluded so they don't fork new instances.\n */\n key?: (args: any) => string;\n /**\n * Explicit, minification-safe identity for this bloc class. Falls back to\n * `constructor.name` when unset, which collides across classes once a\n * minifier shortens class names.\n */\n name?: string;\n}\n\n/**\n * Decorator to configure StateContainer classes.\n *\n * @example Decorator syntax (requires experimentalDecorators or TC39 decorators)\n * ```ts\n * @blac({ keepAlive: true })\n * class AuthBloc extends Cubit<AuthState> {}\n *\n * @blac({ excludeFromDevTools: true })\n * class InternalBloc extends Cubit<InternalState> {}\n *\n * @blac({ keepAlive: true, key: (args) => args.userId })\n * class UserBloc extends Cubit<UserState> {}\n * ```\n *\n * @example Function syntax (no decorator support needed)\n * ```ts\n * const AuthBloc = blac({ keepAlive: true })(\n * class extends Cubit<AuthState> {}\n * );\n * ```\n */\nexport function blac(options: BlacOptions) {\n return function <T extends new (...args: any[]) => any>(\n target: T,\n _context?: ClassDecoratorContext,\n ): T {\n if ('keepAlive' in options && options.keepAlive) {\n (target as any)[BLAC_STATIC_PROPS.KEEP_ALIVE] = true;\n }\n if ('excludeFromDevTools' in options && options.excludeFromDevTools) {\n (target as any)[BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS] = true;\n }\n if ('equality' in options && typeof options.equality === 'function') {\n (target as any)[BLAC_STATIC_PROPS.EQUALITY] = options.equality;\n }\n if ('key' in options && typeof options.key === 'function') {\n (target as any)[BLAC_STATIC_PROPS.KEY] = options.key;\n }\n if ('name' in options && typeof options.name === 'string') {\n (target as any)[BLAC_STATIC_PROPS.BLAC_NAME] = options.name;\n }\n return target;\n };\n}\n","import { ALL_PATHS } from '@dirtytalk/structural';\nimport { ON_DISPOSE } from '../core/symbols';\nimport { getRegistry } from '../registry';\nimport { resolveInstanceKey } from '../registry/acquire';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\n\nconst STOP: unique symbol = Symbol('watch.STOP');\ntype StopSymbol = typeof STOP;\n\nconst BLOC_REF_MARKER = Symbol('BlocRef');\n\n/**\n * Reference to a specific bloc instance, identified by class + the resolved\n * key derived from its `args`.\n */\nexport interface BlocRef<T extends StateContainerConstructor> {\n [BLOC_REF_MARKER]: true;\n blocClass: T;\n /** @internal The resolved instance key (derived from `args`). */\n instanceId: string;\n /**\n * @internal The `args` used to derive `instanceId`. Forwarded to\n * `registry.acquire` so a not-yet-created instance is initialized with\n * these args instead of `undefined`.\n */\n args?: unknown;\n}\n\n/**\n * Create a reference to a specific bloc instance, identified by its `args`.\n * The key is derived the same way `useBloc`/`acquire` derive it.\n *\n * @example\n * ```ts\n * watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n */\nexport function instance<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): BlocRef<T> {\n return {\n [BLOC_REF_MARKER]: true,\n blocClass: BlocClass,\n instanceId: resolveInstanceKey(BlocClass, args),\n args,\n };\n}\n\nfunction isBlocRef(\n input: unknown,\n): input is BlocRef<StateContainerConstructor> {\n return (\n typeof input === 'object' && input !== null && BLOC_REF_MARKER in input\n );\n}\n\ntype BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;\n\n/**\n * Options for `watch`.\n */\nexport interface WatchOptions {\n /**\n * When `false`, `watch` observes passively instead of owning the instance:\n * it does not create a missing instance, and it does not take a real\n * ownership ref on an existing one (so it never keeps an otherwise-\n * unreferenced instance alive).\n *\n * If the instance does not exist yet when `watch` is called, the callback\n * simply never fires for it — `watch` does not poll or wait for a later\n * creation. Call `watch` again once the instance is known to exist (e.g.\n * after some other owner has acquired it).\n *\n * Defaults to `true`.\n */\n create?: boolean;\n}\n\ntype ExtractInstance<T> =\n T extends BlocRef<infer C>\n ? InstanceType<C>\n : T extends StateContainerConstructor\n ? InstanceType<T>\n : never;\n\ntype ExtractInstances<T extends readonly BlocInput[]> = {\n [K in keyof T]: ExtractInstance<T[K]>;\n};\n\n/**\n * Watch function signature for single bloc.\n */\nexport interface WatchSingleFn {\n <T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n options?: WatchOptions,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Watch function signature for multiple blocs.\n */\nexport interface WatchMultipleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n options?: WatchOptions,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Combined watch function type.\n */\nexport interface WatchFn extends WatchSingleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n options?: WatchOptions,\n ): () => void;\n}\n\n/**\n * Class + resolved key + args needed to (re-)acquire a specific instance.\n * `watch` keeps this around per input so it can re-acquire the same logical\n * instance if the underlying container is disposed elsewhere.\n */\ninterface WatchTarget {\n blocClass: StateContainerConstructor;\n key: string;\n args: unknown;\n}\n\nfunction toWatchTarget(input: BlocInput): WatchTarget {\n const registry = getRegistry();\n if (isBlocRef(input)) {\n return {\n blocClass: input.blocClass,\n key: input.instanceId,\n args: input.args,\n };\n }\n return {\n blocClass: input,\n key: registry.resolveKey(input, undefined, undefined),\n args: undefined,\n };\n}\n\nlet watchRefSeq = 0;\n\n/**\n * Acquire a real ref (countRef: true) for the target, carrying its `args`\n * through so a not-yet-created instance is initialized correctly. The\n * caller is responsible for releasing `refId` in cleanup.\n */\nfunction resolveBloc(\n target: WatchTarget,\n refId: string,\n): StateContainerInstance {\n const registry = getRegistry();\n return registry.acquire(target.blocClass, target.key, {\n countRef: true,\n refId,\n args: target.args,\n });\n}\n\n/**\n * Passive lookup for `{ create: false }`: never creates the instance and\n * never takes a ref. Returns `undefined` when no instance currently exists.\n */\nfunction resolveBlocPassive(\n target: WatchTarget,\n): StateContainerInstance | undefined {\n const registry = getRegistry();\n try {\n return registry.acquire(target.blocClass, target.key, {\n canCreate: false,\n countRef: false,\n args: target.args,\n });\n } catch {\n return undefined;\n }\n}\n\nfunction isArray(input: unknown): input is readonly BlocInput[] {\n return Array.isArray(input);\n}\n\n/**\n * Watch one or more blocs for state changes.\n *\n * Thin wrapper around `container.channel.subscribe(ALL_PATHS, ...)`. The\n * callback fires once immediately, then on every state change of any of the\n * passed blocs. Returning `watch.STOP` from the callback tears down all\n * subscriptions.\n *\n * Note: subscriptions are microtask-deferred (per the DirtyChannel default\n * scheduler), so callbacks land asynchronously after `emit()`.\n *\n * By default `watch` creates the instance if it does not exist and holds a\n * real ownership ref until `unwatch`, matching `acquire`. Pass\n * `{ create: false }` to observe passively instead — see `WatchOptions`.\n *\n * @example Single bloc\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n *\n * @example Multiple blocs\n * ```ts\n * const unwatch = watch(\n * [UserBloc, SettingsBloc] as const,\n * ([userBloc, settingsBloc]) => {\n * console.log(userBloc.state.name, settingsBloc.state.theme);\n * }\n * );\n * ```\n *\n * @example With specific instance\n * ```ts\n * const unwatch = watch(\n * instance(UserBloc, { userId: 'user-123' }),\n * (userBloc) => {\n * console.log(userBloc.state.name);\n * }\n * );\n * ```\n *\n * @example Stop watching from callback\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * if (userBloc.state.done) {\n * return watch.STOP;\n * }\n * });\n * ```\n */\nfunction watchImpl<T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n options?: WatchOptions,\n): () => void;\n\nfunction watchImpl<T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n options?: WatchOptions,\n): () => void;\n\nfunction watchImpl(\n blocsOrBloc: BlocInput | readonly BlocInput[],\n callback: (blocsOrBloc: any) => void | StopSymbol,\n options?: WatchOptions,\n): () => void {\n const isSingle = !isArray(blocsOrBloc);\n const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;\n const registry = getRegistry();\n const create = options?.create ?? true;\n\n const targets = inputs.map(toWatchTarget);\n const refIds = targets.map(() => `_watch_${watchRefSeq++}`);\n\n let disposed = false;\n const instances: Array<StateContainerInstance | undefined> = targets.map(\n (target, i) =>\n create ? resolveBloc(target, refIds[i]) : resolveBlocPassive(target),\n );\n const channelUnsubs: Array<(() => void) | undefined> = [];\n const disposedUnsubs: Array<(() => void) | undefined> = [];\n\n const cleanup = () => {\n if (disposed) return;\n disposed = true;\n for (const unsub of channelUnsubs) unsub?.();\n for (const unsub of disposedUnsubs) unsub?.();\n channelUnsubs.length = 0;\n disposedUnsubs.length = 0;\n if (create) {\n for (let i = 0; i < targets.length; i++) {\n registry.release(\n targets[i].blocClass,\n targets[i].key,\n false,\n refIds[i],\n );\n }\n }\n };\n\n const runCallback = () => {\n if (disposed) return;\n if (instances.some((i) => i === undefined)) return;\n const arg = isSingle ? instances[0] : instances;\n const result = callback(arg);\n if (result === STOP) cleanup();\n };\n\n const subscribeAt = (index: number) => {\n channelUnsubs[index] = instances[index]?.channel.subscribe(\n () => ALL_PATHS,\n runCallback,\n );\n };\n\n // On external dispose, tear down the stale subscription and re-acquire +\n // resubscribe (microtask-deferred, so it never runs mid-mutation of the\n // registry that triggered the dispose, e.g. `clearAll()`), then notify.\n const resubscribeAt = (index: number) => {\n if (disposed) return;\n instances[index] = create\n ? resolveBloc(targets[index], refIds[index])\n : resolveBlocPassive(targets[index]);\n subscribeAt(index);\n subscribeDisposeAt(index);\n runCallback();\n };\n\n const subscribeDisposeAt = (index: number) => {\n disposedUnsubs[index] = instances[index]?.[ON_DISPOSE](() => {\n channelUnsubs[index]?.();\n channelUnsubs[index] = undefined;\n queueMicrotask(() => resubscribeAt(index));\n });\n };\n\n for (let i = 0; i < instances.length; i++) {\n subscribeAt(i);\n }\n\n for (let i = 0; i < instances.length; i++) {\n subscribeDisposeAt(i);\n }\n\n // Fire once immediately so the consumer sees the current state.\n runCallback();\n\n return cleanup;\n}\n\nexport const watch: WatchFn = Object.assign(watchImpl, { STOP }) as WatchFn;\n","declare const brand: unique symbol;\n\n/**\n * Utility type for creating branded/nominal types.\n * Prevents accidental type confusion between similar primitive types.\n * @typeParam T - The base type\n * @typeParam B - The brand identifier\n */\nexport type Brand<T, B> = T & { [brand]: B };\n\n/**\n * Branded string type for type-safe IDs.\n * @typeParam B - The brand identifier\n */\nexport type BrandedId<B> = Brand<string, B>;\n\n/**\n * Branded string type for state container instance IDs\n */\nexport type InstanceId = Brand<string, 'InstanceId'>;\n\n/**\n * Create a branded InstanceId from a string\n * @param id - The string ID to brand\n * @returns Branded InstanceId\n */\nexport function instanceId(id: string): InstanceId {\n return id as InstanceId;\n}\n"],"mappings":";;;;AAkBA,SAAS,iBACP,WACA,QACQ;CACR,OAAO,YAAY,EAAE,WAAW,WAAW,KAAA,GAAW,QAAQ,IAAI;AACpE;AAEA,SAAgB,OACd,WACA,QACiB;CACjB,OAAO,YAAY,EAAE,OAAO,WAAW,iBAAiB,WAAW,MAAM,CAAC;AAC5E;AAEA,SAAgB,WACd,WACA,QAG6C;CAC7C,OAAO,YAAY,EAAE,WACnB,WACA,iBAAiB,WAAW,MAAM,CACpC;AACF;;;;;;;;;;;AC5BA,SAAgB,QACd,WACA,MACM;CACN,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,SAAS,QAAQ,WAAW,KAAK,MAAM,gBAAgB,OAAO,MAAM,KAAK;AAC3E;;;;;;ACXA,SAAgB,YACd,WACA,MACS;CACT,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,YAAY,WAAW,GAAG;AAC5C;;;;AAKA,SAAgB,YACd,WACA,MACQ;CACR,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,YAAY,WAAW,GAAG;AAC5C;;;;AAKA,SAAgB,UACd,WACA,MACU;CACV,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,UAAU,WAAW,GAAG;AAC1C;;;;AAKA,SAAgB,OACd,WAC4B;CAC5B,OAAO,YAAY,EAAE,OAAO,SAAS;AACvC;;;;AAKA,SAAgB,QACd,WACA,UACM;CACN,YAAY,EAAE,QAAQ,WAAW,QAAQ;AAC3C;;;ACzDA,SAAgB,MAA2C,WAAoB;CAC7E,YAAY,EAAE,MAAM,SAAS;AAC/B;AAEA,SAAgB,WAAiB;CAC/B,YAAY,EAAE,SAAS;AACzB;;;;AAKA,SAAgB,SACd,WACM;CACN,YAAY,EAAE,SAAS,SAAS;AAClC;;;;;;;;;;;;;;;;;;;;;;;;;ACoCA,SAAgB,KAAK,SAAsB;CACzC,OAAO,SACL,QACA,UACG;EACH,IAAI,eAAe,WAAW,QAAQ,WACpC,OAAgB,kBAAkB,cAAc;EAElD,IAAI,yBAAyB,WAAW,QAAQ,qBAC9C,OAAgB,kBAAkB,yBAAyB;EAE7D,IAAI,cAAc,WAAW,OAAO,QAAQ,aAAa,YACvD,OAAgB,kBAAkB,YAAY,QAAQ;EAExD,IAAI,SAAS,WAAW,OAAO,QAAQ,QAAQ,YAC7C,OAAgB,kBAAkB,OAAO,QAAQ;EAEnD,IAAI,UAAU,WAAW,OAAO,QAAQ,SAAS,UAC/C,OAAgB,kBAAkB,aAAa,QAAQ;EAEzD,OAAO;CACT;AACF;;;AClEA,MAAM,OAAsB,OAAO,YAAY;AAG/C,MAAM,kBAAkB,OAAO,SAAS;;;;;;;;;;;;AA8BxC,SAAgB,SACd,WACA,MACY;CACZ,OAAO;GACJ,kBAAkB;EACnB,WAAW;EACX,YAAY,mBAAmB,WAAW,IAAI;EAC9C;CACF;AACF;AAEA,SAAS,UACP,OAC6C;CAC7C,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,mBAAmB;AAEtE;AAmFA,SAAS,cAAc,OAA+B;CACpD,MAAM,WAAW,YAAY;CAC7B,IAAI,UAAU,KAAK,GACjB,OAAO;EACL,WAAW,MAAM;EACjB,KAAK,MAAM;EACX,MAAM,MAAM;CACd;CAEF,OAAO;EACL,WAAW;EACX,KAAK,SAAS,WAAW,OAAO,KAAA,GAAW,KAAA,CAAS;EACpD,MAAM,KAAA;CACR;AACF;AAEA,IAAI,cAAc;;;;;;AAOlB,SAAS,YACP,QACA,OACwB;CAExB,OADiB,YACH,EAAE,QAAQ,OAAO,WAAW,OAAO,KAAK;EACpD,UAAU;EACV;EACA,MAAM,OAAO;CACf,CAAC;AACH;;;;;AAMA,SAAS,mBACP,QACoC;CACpC,MAAM,WAAW,YAAY;CAC7B,IAAI;EACF,OAAO,SAAS,QAAQ,OAAO,WAAW,OAAO,KAAK;GACpD,WAAW;GACX,UAAU;GACV,MAAM,OAAO;EACf,CAAC;CACH,QAAQ;EACN;CACF;AACF;AAEA,SAAS,QAAQ,OAA+C;CAC9D,OAAO,MAAM,QAAQ,KAAK;AAC5B;AAiEA,SAAS,UACP,aACA,UACA,SACY;CACZ,MAAM,WAAW,CAAC,QAAQ,WAAW;CACrC,MAAM,SAAS,WAAW,CAAC,WAAW,IAAI;CAC1C,MAAM,WAAW,YAAY;CAC7B,MAAM,SAAS,SAAS,UAAU;CAElC,MAAM,UAAU,OAAO,IAAI,aAAa;CACxC,MAAM,SAAS,QAAQ,UAAU,UAAU,eAAe;CAE1D,IAAI,WAAW;CACf,MAAM,YAAuD,QAAQ,KAClE,QAAQ,MACP,SAAS,YAAY,QAAQ,OAAO,EAAE,IAAI,mBAAmB,MAAM,CACvE;CACA,MAAM,gBAAiD,CAAC;CACxD,MAAM,iBAAkD,CAAC;CAEzD,MAAM,gBAAgB;EACpB,IAAI,UAAU;EACd,WAAW;EACX,KAAK,MAAM,SAAS,eAAe,QAAQ;EAC3C,KAAK,MAAM,SAAS,gBAAgB,QAAQ;EAC5C,cAAc,SAAS;EACvB,eAAe,SAAS;EACxB,IAAI,QACF,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAClC,SAAS,QACP,QAAQ,GAAG,WACX,QAAQ,GAAG,KACX,OACA,OAAO,EACT;CAGN;CAEA,MAAM,oBAAoB;EACxB,IAAI,UAAU;EACd,IAAI,UAAU,MAAM,MAAM,MAAM,KAAA,CAAS,GAAG;EAG5C,IADe,SADH,WAAW,UAAU,KAAK,SAE7B,MAAM,MAAM,QAAQ;CAC/B;CAEA,MAAM,eAAe,UAAkB;EACrC,cAAc,SAAS,UAAU,QAAQ,QAAQ,gBACzCA,aACN,WACF;CACF;CAKA,MAAM,iBAAiB,UAAkB;EACvC,IAAI,UAAU;EACd,UAAU,SAAS,SACf,YAAY,QAAQ,QAAQ,OAAO,MAAM,IACzC,mBAAmB,QAAQ,MAAM;EACrC,YAAY,KAAK;EACjB,mBAAmB,KAAK;EACxB,YAAY;CACd;CAEA,MAAM,sBAAsB,UAAkB;EAC5C,eAAe,SAAS,UAAU,SAAS,kBAAkB;GAC3D,cAAc,SAAS;GACvB,cAAc,SAAS,KAAA;GACvB,qBAAqB,cAAc,KAAK,CAAC;EAC3C,CAAC;CACH;CAEA,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACpC,YAAY,CAAC;CAGf,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACpC,mBAAmB,CAAC;CAItB,YAAY;CAEZ,OAAO;AACT;AAEA,MAAa,QAAiB,OAAO,OAAO,WAAW,EAAE,KAAK,CAAC;;;;;;;;ACzU/D,SAAgB,WAAW,IAAwB;CACjD,OAAO;AACT"}
@@ -99,6 +99,20 @@ export interface BlacPlugin {
99
99
  * Fires when a container's hydration status transitions.
100
100
  */
101
101
  onHydrationChange?(ctx: PluginContext, status: HydrationStatus, previousStatus: HydrationStatus): void;
102
+ /**
103
+ * Fires on the same 0↔1 ownership transition that drives the container's
104
+ * own `onActivate`, after that hook has already run. `signal` aborts on the
105
+ * matching `onDeactivate` and on dispose — dispose does NOT fire
106
+ * `onDeactivate` (or this hook), matching `StateContainer`'s single
107
+ * teardown path.
108
+ */
109
+ onActivate?(ctx: PluginContext, signal: AbortSignal): void;
110
+ /**
111
+ * Fires when an active container goes back to unowned while surviving in
112
+ * the registry (i.e. `keepAlive`), after the container's own `onDeactivate`
113
+ * has already run. Not fired on dispose.
114
+ */
115
+ onDeactivate?(ctx: PluginContext): void;
102
116
  /**
103
117
  * @internal Devtools-only — fires when a named ref is acquired.
104
118
  * Not part of the state-change event payload.
@@ -6,7 +6,8 @@ import type { BlacPlugin, PluginConfig } from './BlacPlugin';
6
6
  * The manager hooks into two surfaces:
7
7
  *
8
8
  * 1. **Registry lifecycle events** (`created`, `disposed`, `refAcquired`,
9
- * `refReleased`, `depsChanged`) — synchronous, fired by the registry.
9
+ * `refReleased`, `depsChanged`, `activated`, `deactivated`) — synchronous,
10
+ * fired by the registry.
10
11
  *
11
12
  * 2. **Per-container channel flushes** — microtask-coalesced. For each
12
13
  * container, the manager subscribes once at create-time with
@@ -38,6 +39,12 @@ export declare class PluginManager {
38
39
  * manager hands plugins on each flush.
39
40
  */
40
41
  private containerBridges;
42
+ /**
43
+ * One `PluginContext` per container. The context closes over `registry` and
44
+ * `container` only — both stable for the container's lifetime — so it is
45
+ * safe to reuse instead of rebuilding its method table on every dispatch.
46
+ */
47
+ private contextCache;
41
48
  /**
42
49
  * Create a new PluginManager
43
50
  * @param registry - The StateContainerRegistry to monitor for lifecycle events
@@ -98,6 +105,17 @@ export declare class PluginManager {
98
105
  */
99
106
  private attachStateBridge;
100
107
  private detachStateBridge;
108
+ /**
109
+ * Backfill a newly-installed plugin with the app's existing instances.
110
+ *
111
+ * Iterates every registered `Type` and its live instances (`getAll`
112
+ * already skips disposed), attaching the state bridge (idempotent — see
113
+ * `attachStateBridge`) and, if the plugin implements `onCreated`, invoking
114
+ * it directly for each instance. Scoped to this single plugin only — the
115
+ * broadcast `notifyPlugins` would re-notify *every* plugin of *every*
116
+ * instance, which is wrong here.
117
+ */
118
+ private backfillPlugin;
101
119
  /**
102
120
  * Channel-flush callback. Snapshots `next`, hands `(prev, next, paths)`
103
121
  * to every enabled plugin's `onStateChange`, then updates `prevState`
@@ -119,14 +137,12 @@ export declare class PluginManager {
119
137
  */
120
138
  private notifyPlugins;
121
139
  /**
122
- * Build a `PluginContext` for a given focal container. The context is
123
- * cheap to build — its methods close over `this.registry` directly —
124
- * so we create one per dispatch rather than caching per container.
125
- * This sidesteps the lifetime question of "when do we evict a cached
126
- * context?" and keeps `paths`-vs-`container` lifetimes cleanly
127
- * separated.
140
+ * Get the `PluginContext` for a focal container, building it once and
141
+ * reusing it thereafter. Eviction is handled by the `WeakMap`: the context
142
+ * dies with the container. `undefined` (install-time) is never cached.
128
143
  */
129
144
  private buildContext;
145
+ private createContext;
130
146
  /**
131
147
  * Check if plugin should be enabled based on environment
132
148
  */