@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.
- package/README.md +19 -29
- package/dist/{StateContainerRegistry-CSNm2Ws5.cjs → StateContainerRegistry-141uHhtF.cjs} +300 -397
- package/dist/StateContainerRegistry-141uHhtF.cjs.map +1 -0
- package/dist/{StateContainerRegistry-DVIBTxGZ.js → StateContainerRegistry-BH7aOMWV.js} +299 -406
- package/dist/StateContainerRegistry-BH7aOMWV.js.map +1 -0
- package/dist/{StateContainerRegistry-Dj77cok9.js → StateContainerRegistry-BsH_s0pJ.js} +303 -413
- package/dist/StateContainerRegistry-BsH_s0pJ.js.map +1 -0
- package/dist/{StateContainerRegistry-lIwo-0m3.cjs → StateContainerRegistry-CBLeHObO.cjs} +326 -418
- package/dist/StateContainerRegistry-CBLeHObO.cjs.map +1 -0
- package/dist/{StateContainerRegistry-D9BIRjwv.cjs → StateContainerRegistry-MkT0W4C2.cjs} +322 -411
- package/dist/StateContainerRegistry-MkT0W4C2.cjs.map +1 -0
- package/dist/{StateContainerRegistry-CvBOhAT2.js → StateContainerRegistry-vWgsD-RP.js} +277 -392
- package/dist/StateContainerRegistry-vWgsD-RP.js.map +1 -0
- package/dist/config.d.cts +2 -2
- package/dist/config.d.ts +2 -2
- package/dist/constants.d.cts +4 -20
- package/dist/constants.d.ts +4 -20
- package/dist/core/Cubit.d.ts +14 -10
- package/dist/core/StateContainer.d.ts +68 -8
- package/dist/core/StateContainerRegistry.d.ts +100 -19
- package/dist/core/meta.d.ts +34 -47
- package/dist/core/symbols.d.ts +18 -1
- package/dist/decorators/blac.d.ts +28 -26
- package/dist/{ensure-BKdq5xsY.cjs → ensure-BjhbDW8Z.cjs} +223 -40
- package/dist/ensure-BjhbDW8Z.cjs.map +1 -0
- package/dist/ensure-BnVyd6s4.js +730 -0
- package/dist/ensure-BnVyd6s4.js.map +1 -0
- package/dist/ensure-CneMkpbI.js +731 -0
- package/dist/ensure-CneMkpbI.js.map +1 -0
- package/dist/{ensure-CQimeD0I.cjs → ensure-D15vGnk5.cjs} +348 -124
- package/dist/ensure-D15vGnk5.cjs.map +1 -0
- package/dist/{ensure-B1dEDsZV.cjs → ensure-D3w6YGp9.cjs} +349 -124
- package/dist/ensure-D3w6YGp9.cjs.map +1 -0
- package/dist/{ensure-B2DYCbbI.cjs → ensure-ORVw-WRE.cjs} +214 -39
- package/dist/ensure-ORVw-WRE.cjs.map +1 -0
- package/dist/{ensure-B59ri8oo.js → ensure-dsqWhIuO.js} +192 -39
- package/dist/ensure-dsqWhIuO.js.map +1 -0
- package/dist/{ensure-BSJHkUNX.js → ensure-k-6q7O25.js} +183 -38
- package/dist/ensure-k-6q7O25.js.map +1 -0
- package/dist/index.cjs +212 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -6
- package/dist/index.d.ts +4 -6
- package/dist/index.js +192 -12
- package/dist/index.js.map +1 -1
- package/dist/plugin/BlacPlugin.d.ts +14 -0
- package/dist/plugin/PluginManager.d.ts +21 -11
- package/dist/plugins.cjs +403 -3
- package/dist/plugins.cjs.map +1 -0
- package/dist/plugins.d.cts +6 -2
- package/dist/plugins.d.ts +6 -2
- package/dist/plugins.js +401 -1
- package/dist/plugins.js.map +1 -0
- package/dist/registry/acquire.d.ts +2 -2
- package/dist/registry/config.d.ts +9 -0
- package/dist/registry/management.d.ts +3 -0
- package/dist/registry/queries.d.ts +15 -0
- package/dist/registry/release.d.ts +3 -3
- package/dist/testing.cjs +13 -15
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +2 -4
- package/dist/testing.js.map +1 -1
- package/dist/types/branded.d.ts +3 -3
- package/dist/types/utilities.d.ts +45 -18
- package/dist/utils/static-props.d.ts +25 -1
- package/dist/utils/structural-key.d.ts +0 -7
- package/dist/watch/index.d.ts +1 -1
- package/dist/watch/watch.d.ts +22 -3
- package/package.json +16 -55
- package/dist/StateContainerRegistry-4Ljd9EJx.js +0 -1018
- package/dist/StateContainerRegistry-4Ljd9EJx.js.map +0 -1
- package/dist/StateContainerRegistry-8zNFMAf7.js +0 -1067
- package/dist/StateContainerRegistry-8zNFMAf7.js.map +0 -1
- package/dist/StateContainerRegistry-B1GYx9Xo.js +0 -975
- package/dist/StateContainerRegistry-B1GYx9Xo.js.map +0 -1
- package/dist/StateContainerRegistry-B_ViBLvJ.js +0 -975
- package/dist/StateContainerRegistry-B_ViBLvJ.js.map +0 -1
- package/dist/StateContainerRegistry-Bx2ly-ba.cjs +0 -1162
- package/dist/StateContainerRegistry-Bx2ly-ba.cjs.map +0 -1
- package/dist/StateContainerRegistry-C0dCNlTF.js +0 -1005
- package/dist/StateContainerRegistry-C0dCNlTF.js.map +0 -1
- package/dist/StateContainerRegistry-CEWpc1bj.cjs +0 -1113
- package/dist/StateContainerRegistry-CEWpc1bj.cjs.map +0 -1
- package/dist/StateContainerRegistry-CS18y4au.cjs +0 -1163
- package/dist/StateContainerRegistry-CS18y4au.cjs.map +0 -1
- package/dist/StateContainerRegistry-CSNm2Ws5.cjs.map +0 -1
- package/dist/StateContainerRegistry-CchRjnjX.cjs +0 -1094
- package/dist/StateContainerRegistry-CchRjnjX.cjs.map +0 -1
- package/dist/StateContainerRegistry-CvBOhAT2.js.map +0 -1
- package/dist/StateContainerRegistry-D8nu7Z0T.js +0 -1068
- package/dist/StateContainerRegistry-D8nu7Z0T.js.map +0 -1
- package/dist/StateContainerRegistry-D9BIRjwv.cjs.map +0 -1
- package/dist/StateContainerRegistry-DJQqLrli.cjs +0 -1046
- package/dist/StateContainerRegistry-DJQqLrli.cjs.map +0 -1
- package/dist/StateContainerRegistry-DVIBTxGZ.js.map +0 -1
- package/dist/StateContainerRegistry-Dj77cok9.js.map +0 -1
- package/dist/StateContainerRegistry-FWKzPfS-.cjs +0 -1046
- package/dist/StateContainerRegistry-FWKzPfS-.cjs.map +0 -1
- package/dist/StateContainerRegistry-lIwo-0m3.cjs.map +0 -1
- package/dist/acquire-B1LYXSGj.js +0 -35
- package/dist/acquire-B1LYXSGj.js.map +0 -1
- package/dist/acquire-B1Wuqla6.cjs +0 -46
- package/dist/acquire-B1Wuqla6.cjs.map +0 -1
- package/dist/acquire-BJ3xUEmh.cjs +0 -46
- package/dist/acquire-BJ3xUEmh.cjs.map +0 -1
- package/dist/acquire-BP-ZfUH2.js +0 -35
- package/dist/acquire-BP-ZfUH2.js.map +0 -1
- package/dist/acquire-BRIJVJaA.js +0 -35
- package/dist/acquire-BRIJVJaA.js.map +0 -1
- package/dist/acquire-BZIs6tpN.cjs +0 -46
- package/dist/acquire-BZIs6tpN.cjs.map +0 -1
- package/dist/acquire-B_p1fNEh.cjs +0 -46
- package/dist/acquire-B_p1fNEh.cjs.map +0 -1
- package/dist/acquire-BdsVZBSe.js +0 -35
- package/dist/acquire-BdsVZBSe.js.map +0 -1
- package/dist/acquire-C3nOb3XR.cjs +0 -46
- package/dist/acquire-C3nOb3XR.cjs.map +0 -1
- package/dist/acquire-C4WAS13G.cjs +0 -46
- package/dist/acquire-C4WAS13G.cjs.map +0 -1
- package/dist/acquire-C7beGI55.cjs +0 -46
- package/dist/acquire-C7beGI55.cjs.map +0 -1
- package/dist/acquire-CbMz7gWs.cjs +0 -46
- package/dist/acquire-CbMz7gWs.cjs.map +0 -1
- package/dist/acquire-CwB083au.js +0 -35
- package/dist/acquire-CwB083au.js.map +0 -1
- package/dist/acquire-DHEOEVcj.cjs +0 -46
- package/dist/acquire-DHEOEVcj.cjs.map +0 -1
- package/dist/acquire-DXEQDZGr.js +0 -35
- package/dist/acquire-DXEQDZGr.js.map +0 -1
- package/dist/acquire-Dg-uXwjF.js +0 -35
- package/dist/acquire-Dg-uXwjF.js.map +0 -1
- package/dist/acquire-Don7499S.js +0 -35
- package/dist/acquire-Don7499S.js.map +0 -1
- package/dist/acquire-G8aB3GAx.js +0 -35
- package/dist/acquire-G8aB3GAx.js.map +0 -1
- package/dist/branded-BybA0_xw.cjs +0 -18
- package/dist/branded-BybA0_xw.cjs.map +0 -1
- package/dist/branded-DkbUzncc.js +0 -13
- package/dist/branded-DkbUzncc.js.map +0 -1
- package/dist/config-8pyOC5gv.js +0 -16
- package/dist/config-8pyOC5gv.js.map +0 -1
- package/dist/config-B1l8ZGlU.cjs +0 -32
- package/dist/config-B1l8ZGlU.cjs.map +0 -1
- package/dist/config-C7Ktkjh2.cjs +0 -32
- package/dist/config-C7Ktkjh2.cjs.map +0 -1
- package/dist/config-COT4Xkbc.js +0 -16
- package/dist/config-COT4Xkbc.js.map +0 -1
- package/dist/config-CzcoAvBo.js +0 -16
- package/dist/config-CzcoAvBo.js.map +0 -1
- package/dist/config-D6BoWWPv.js +0 -16
- package/dist/config-D6BoWWPv.js.map +0 -1
- package/dist/config-DOO82lbZ.js +0 -16
- package/dist/config-DOO82lbZ.js.map +0 -1
- package/dist/config-DVM_ESQt.js +0 -16
- package/dist/config-DVM_ESQt.js.map +0 -1
- package/dist/config-DVMnlHLv.cjs +0 -32
- package/dist/config-DVMnlHLv.cjs.map +0 -1
- package/dist/config-DWUq7zEQ.cjs +0 -32
- package/dist/config-DWUq7zEQ.cjs.map +0 -1
- package/dist/config-DXI3kzmA.js +0 -16
- package/dist/config-DXI3kzmA.js.map +0 -1
- package/dist/config-Dk1FxfXj.js +0 -16
- package/dist/config-Dk1FxfXj.js.map +0 -1
- package/dist/config-b2z51Y_C.cjs +0 -32
- package/dist/config-b2z51Y_C.cjs.map +0 -1
- package/dist/config-buwpT7l3.js +0 -16
- package/dist/config-buwpT7l3.js.map +0 -1
- package/dist/config-cwaTn5oy.cjs +0 -32
- package/dist/config-cwaTn5oy.cjs.map +0 -1
- package/dist/config-d9_U58ef.cjs +0 -32
- package/dist/config-d9_U58ef.cjs.map +0 -1
- package/dist/config-hWTayX76.cjs +0 -32
- package/dist/config-hWTayX76.cjs.map +0 -1
- package/dist/config-sCPKPYxZ.cjs +0 -32
- package/dist/config-sCPKPYxZ.cjs.map +0 -1
- package/dist/debug.cjs +0 -14
- package/dist/debug.d.cts +0 -34
- package/dist/debug.d.ts +0 -34
- package/dist/debug.js +0 -4
- package/dist/ensure-B1dEDsZV.cjs.map +0 -1
- package/dist/ensure-B2DYCbbI.cjs.map +0 -1
- package/dist/ensure-B59ri8oo.js.map +0 -1
- package/dist/ensure-B9oOqpOB.cjs +0 -558
- package/dist/ensure-B9oOqpOB.cjs.map +0 -1
- package/dist/ensure-BKdq5xsY.cjs.map +0 -1
- package/dist/ensure-BSJHkUNX.js.map +0 -1
- package/dist/ensure-BfYnvAsI.js +0 -709
- package/dist/ensure-BfYnvAsI.js.map +0 -1
- package/dist/ensure-Bm91o37h.js +0 -536
- package/dist/ensure-Bm91o37h.js.map +0 -1
- package/dist/ensure-C1a8IFWy.js +0 -535
- package/dist/ensure-C1a8IFWy.js.map +0 -1
- package/dist/ensure-CLQEx0Nn.cjs +0 -528
- package/dist/ensure-CLQEx0Nn.cjs.map +0 -1
- package/dist/ensure-CPMiGvov.js +0 -493
- package/dist/ensure-CPMiGvov.js.map +0 -1
- package/dist/ensure-CQimeD0I.cjs.map +0 -1
- package/dist/ensure-DEXSmA-N.js +0 -526
- package/dist/ensure-DEXSmA-N.js.map +0 -1
- package/dist/ensure-DTTTd2h8.js +0 -536
- package/dist/ensure-DTTTd2h8.js.map +0 -1
- package/dist/ensure-Dx86f80B.cjs +0 -567
- package/dist/ensure-Dx86f80B.cjs.map +0 -1
- package/dist/ensure-DzqGej43.js +0 -526
- package/dist/ensure-DzqGej43.js.map +0 -1
- package/dist/ensure-VuiNPccZ.cjs +0 -559
- package/dist/ensure-VuiNPccZ.cjs.map +0 -1
- package/dist/ensure-_Oh8XPm4.cjs +0 -732
- package/dist/ensure-_Oh8XPm4.cjs.map +0 -1
- package/dist/ensure-fsQMjaQL.cjs +0 -567
- package/dist/ensure-fsQMjaQL.cjs.map +0 -1
- package/dist/ensure-vxAGa2v3.js +0 -536
- package/dist/ensure-vxAGa2v3.js.map +0 -1
- package/dist/management-14vsHr4t.cjs +0 -85
- package/dist/management-14vsHr4t.cjs.map +0 -1
- package/dist/management-444tdCBG.js +0 -38
- package/dist/management-444tdCBG.js.map +0 -1
- package/dist/management-7jLjVHJd.js +0 -38
- package/dist/management-7jLjVHJd.js.map +0 -1
- package/dist/management-AFuqQEwz.js +0 -38
- package/dist/management-AFuqQEwz.js.map +0 -1
- package/dist/management-BodVLAfJ.cjs +0 -85
- package/dist/management-BodVLAfJ.cjs.map +0 -1
- package/dist/management-BqGBdL01.js +0 -38
- package/dist/management-BqGBdL01.js.map +0 -1
- package/dist/management-BvUAjril.js +0 -38
- package/dist/management-BvUAjril.js.map +0 -1
- package/dist/management-C-WGcwPD.js +0 -38
- package/dist/management-C-WGcwPD.js.map +0 -1
- package/dist/management-C2wv4vGS.cjs +0 -85
- package/dist/management-C2wv4vGS.cjs.map +0 -1
- package/dist/management-D2pjr38g.js +0 -38
- package/dist/management-D2pjr38g.js.map +0 -1
- package/dist/management-D5WsZoTV.js +0 -38
- package/dist/management-D5WsZoTV.js.map +0 -1
- package/dist/management-DAV9sN-k.cjs +0 -85
- package/dist/management-DAV9sN-k.cjs.map +0 -1
- package/dist/management-Df7Y2sF1.cjs +0 -85
- package/dist/management-Df7Y2sF1.cjs.map +0 -1
- package/dist/management-DwO0nBzL.cjs +0 -85
- package/dist/management-DwO0nBzL.cjs.map +0 -1
- package/dist/management-GcnNJjnm.cjs +0 -85
- package/dist/management-GcnNJjnm.cjs.map +0 -1
- package/dist/management-P_Vi_cvw.js +0 -38
- package/dist/management-P_Vi_cvw.js.map +0 -1
- package/dist/management-QWLpbXlW.cjs +0 -85
- package/dist/management-QWLpbXlW.cjs.map +0 -1
- package/dist/management-iE4x6IQY.cjs +0 -85
- package/dist/management-iE4x6IQY.cjs.map +0 -1
- package/dist/types.cjs +0 -3
- package/dist/types.d.cts +0 -8
- package/dist/types.d.ts +0 -8
- package/dist/types.js +0 -2
- package/dist/watch-B0pUfh-v.cjs +0 -119
- package/dist/watch-B0pUfh-v.cjs.map +0 -1
- package/dist/watch-B91opmva.cjs +0 -70
- package/dist/watch-B91opmva.cjs.map +0 -1
- package/dist/watch-BHfCtbn1.cjs +0 -119
- package/dist/watch-BHfCtbn1.cjs.map +0 -1
- package/dist/watch-BmC-Tyqg.js +0 -59
- package/dist/watch-BmC-Tyqg.js.map +0 -1
- package/dist/watch-Bx0y-Kcc.js +0 -108
- package/dist/watch-Bx0y-Kcc.js.map +0 -1
- package/dist/watch-CKWt788i.cjs +0 -70
- package/dist/watch-CKWt788i.cjs.map +0 -1
- package/dist/watch-CfrSSrRY.js +0 -59
- package/dist/watch-CfrSSrRY.js.map +0 -1
- package/dist/watch-Cnh3PtQA.cjs +0 -70
- package/dist/watch-Cnh3PtQA.cjs.map +0 -1
- package/dist/watch-D01MdwKy.js +0 -108
- package/dist/watch-D01MdwKy.js.map +0 -1
- package/dist/watch-D8hwbFU1.js +0 -59
- package/dist/watch-D8hwbFU1.js.map +0 -1
- package/dist/watch-DPVUwPUY.js +0 -59
- package/dist/watch-DPVUwPUY.js.map +0 -1
- package/dist/watch-DVmvZBMD.cjs +0 -70
- package/dist/watch-DVmvZBMD.cjs.map +0 -1
- package/dist/watch-DkDGmGAx.cjs +0 -119
- package/dist/watch-DkDGmGAx.cjs.map +0 -1
- package/dist/watch-DttHqefn.js +0 -108
- package/dist/watch-DttHqefn.js.map +0 -1
- package/dist/watch-DxdIZjpt.cjs +0 -119
- package/dist/watch-DxdIZjpt.cjs.map +0 -1
- package/dist/watch-DztcJuUy.cjs +0 -119
- package/dist/watch-DztcJuUy.cjs.map +0 -1
- package/dist/watch-IrR8G28N.js +0 -108
- package/dist/watch-IrR8G28N.js.map +0 -1
- package/dist/watch-entry.cjs +0 -4
- package/dist/watch-entry.d.cts +0 -24
- package/dist/watch-entry.d.ts +0 -24
- package/dist/watch-entry.js +0 -2
- package/dist/watch-hx0r92Zc.js +0 -108
- package/dist/watch-hx0r92Zc.js.map +0 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
let _dirtytalk_structural = require("@dirtytalk/structural");
|
|
2
1
|
//#region src/config.ts
|
|
3
2
|
/**
|
|
4
3
|
* Default equality: shallow per-key `Object.is` comparison.
|
|
@@ -19,13 +18,13 @@ const shallowEqualState = (prev, next) => {
|
|
|
19
18
|
};
|
|
20
19
|
const defaultConfig = {
|
|
21
20
|
equality: shallowEqualState,
|
|
22
|
-
maxInstancesPerType:
|
|
23
|
-
maxRefsPerInstance:
|
|
24
|
-
maxEmitsPerSecond:
|
|
21
|
+
maxInstancesPerType: 1e5,
|
|
22
|
+
maxRefsPerInstance: 1e5,
|
|
23
|
+
maxEmitsPerSecond: 1e3
|
|
25
24
|
};
|
|
26
25
|
let globalConfig = { ...defaultConfig };
|
|
27
26
|
/**
|
|
28
|
-
* Configure global defaults for
|
|
27
|
+
* Configure global defaults for `@blac/core`.
|
|
29
28
|
*
|
|
30
29
|
* @example
|
|
31
30
|
* ```ts
|
|
@@ -56,322 +55,6 @@ function resetBlacConfig() {
|
|
|
56
55
|
globalConfig = { ...defaultConfig };
|
|
57
56
|
}
|
|
58
57
|
//#endregion
|
|
59
|
-
//#region src/plugin/PluginManager.ts
|
|
60
|
-
/**
|
|
61
|
-
* Manages plugin lifecycle for the BlaC state management system.
|
|
62
|
-
*
|
|
63
|
-
* The manager hooks into two surfaces:
|
|
64
|
-
*
|
|
65
|
-
* 1. **Registry lifecycle events** (`created`, `disposed`, `refAcquired`,
|
|
66
|
-
* `refReleased`, `depsChanged`) — synchronous, fired by the registry.
|
|
67
|
-
*
|
|
68
|
-
* 2. **Per-container channel flushes** — microtask-coalesced. For each
|
|
69
|
-
* container, the manager subscribes once at create-time with
|
|
70
|
-
* `ALL_PATHS` interest and stashes `prevState`. On every flush it
|
|
71
|
-
* captures the new state + the changed `PathSet` and dispatches
|
|
72
|
-
* `onStateChange(ctx, prev, next, paths)` to every enabled plugin.
|
|
73
|
-
*
|
|
74
|
-
* The `ALL_PATHS` subscription cost: plugins counted as a consumer with
|
|
75
|
-
* `ALL_PATHS` interest will defeat the single-consumer-skip optimization
|
|
76
|
-
* in `StructuralContainer`. This is the intended trade-off — devtools /
|
|
77
|
-
* persist plugins genuinely want every change, and stateful plugins
|
|
78
|
-
* (logging) can decode `paths` via `container.interner.lookup(id)` to log
|
|
79
|
-
* only relevant fields. Plugins that want low overhead should remain
|
|
80
|
-
* uninstalled or environment-gated.
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* ```ts
|
|
84
|
-
* const manager = createPluginManager(registry);
|
|
85
|
-
* manager.install(myPlugin, { environment: 'development' });
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
|
-
var PluginManager = class {
|
|
89
|
-
/**
|
|
90
|
-
* Create a new PluginManager
|
|
91
|
-
* @param registry - The StateContainerRegistry to monitor for lifecycle events
|
|
92
|
-
*/
|
|
93
|
-
constructor(registry) {
|
|
94
|
-
this.plugins = /* @__PURE__ */ new Map();
|
|
95
|
-
this.lifecycleUnsubscribers = [];
|
|
96
|
-
this.containerBridges = /* @__PURE__ */ new WeakMap();
|
|
97
|
-
this.registry = registry;
|
|
98
|
-
this.setupLifecycleHooks();
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Install a plugin with optional configuration
|
|
102
|
-
* @param plugin - The plugin to install
|
|
103
|
-
* @param config - Optional plugin configuration
|
|
104
|
-
* @throws Error if plugin is already installed
|
|
105
|
-
*/
|
|
106
|
-
install(plugin, config = {}) {
|
|
107
|
-
const effectiveConfig = {
|
|
108
|
-
enabled: true,
|
|
109
|
-
environment: "all",
|
|
110
|
-
...config
|
|
111
|
-
};
|
|
112
|
-
if (!this.shouldEnablePlugin(effectiveConfig)) {
|
|
113
|
-
console.log(`[BlaC] Plugin "${plugin.name}" skipped (environment mismatch)`);
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
if (this.plugins.has(plugin.name)) throw new Error(`Plugin "${plugin.name}" is already installed`);
|
|
117
|
-
const installContext = this.buildContext(void 0);
|
|
118
|
-
this.plugins.set(plugin.name, {
|
|
119
|
-
plugin,
|
|
120
|
-
config: effectiveConfig,
|
|
121
|
-
installContext
|
|
122
|
-
});
|
|
123
|
-
if (plugin.onInstall) try {
|
|
124
|
-
plugin.onInstall(installContext);
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.error(`[BlaC] Error installing plugin "${plugin.name}":`, error);
|
|
127
|
-
this.plugins.delete(plugin.name);
|
|
128
|
-
throw error;
|
|
129
|
-
}
|
|
130
|
-
console.log(`[BlaC] Plugin "${plugin.name}" v${plugin.version} installed`);
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Uninstall a plugin by name
|
|
134
|
-
* @param pluginName - The name of the plugin to uninstall
|
|
135
|
-
* @throws Error if plugin is not installed
|
|
136
|
-
*/
|
|
137
|
-
uninstall(pluginName) {
|
|
138
|
-
const installed = this.plugins.get(pluginName);
|
|
139
|
-
if (!installed) throw new Error(`Plugin "${pluginName}" is not installed`);
|
|
140
|
-
if (installed.plugin.onUninstall) try {
|
|
141
|
-
installed.plugin.onUninstall();
|
|
142
|
-
} catch (error) {
|
|
143
|
-
console.error(`[BlaC] Error uninstalling plugin "${pluginName}":`, error);
|
|
144
|
-
}
|
|
145
|
-
this.plugins.delete(pluginName);
|
|
146
|
-
console.log(`[BlaC] Plugin "${pluginName}" uninstalled`);
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Get an installed plugin by name
|
|
150
|
-
* @param pluginName - The name of the plugin to retrieve
|
|
151
|
-
* @returns The plugin instance or undefined if not found
|
|
152
|
-
*/
|
|
153
|
-
getPlugin(pluginName) {
|
|
154
|
-
return this.plugins.get(pluginName)?.plugin;
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Get all installed plugins
|
|
158
|
-
* @returns Array of all installed plugins
|
|
159
|
-
*/
|
|
160
|
-
getAllPlugins() {
|
|
161
|
-
return Array.from(this.plugins.values()).map((p) => p.plugin);
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Check if a plugin is installed
|
|
165
|
-
* @param pluginName - The name of the plugin to check
|
|
166
|
-
* @returns true if the plugin is installed
|
|
167
|
-
*/
|
|
168
|
-
hasPlugin(pluginName) {
|
|
169
|
-
return this.plugins.has(pluginName);
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Uninstall all plugins
|
|
173
|
-
*/
|
|
174
|
-
clear() {
|
|
175
|
-
for (const name of this.plugins.keys()) this.uninstall(name);
|
|
176
|
-
}
|
|
177
|
-
destroy() {
|
|
178
|
-
this.clear();
|
|
179
|
-
for (const unsub of this.lifecycleUnsubscribers) unsub();
|
|
180
|
-
this.lifecycleUnsubscribers = [];
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Wire registry lifecycle events into plugin dispatch.
|
|
184
|
-
*
|
|
185
|
-
* `onStateChange` is NOT wired through `registry.on('stateChanged', …)` —
|
|
186
|
-
* that event lacks the `PathSet` payload. Instead, on each `created` we
|
|
187
|
-
* subscribe to the container's channel directly so we get
|
|
188
|
-
* `(paths)` and capture `(prev, next)` via the per-container snapshot.
|
|
189
|
-
*/
|
|
190
|
-
setupLifecycleHooks() {
|
|
191
|
-
this.lifecycleUnsubscribers = [
|
|
192
|
-
this.registry.on("created", (instance) => {
|
|
193
|
-
this.attachStateBridge(instance);
|
|
194
|
-
this.notifyPlugins("onCreated", instance);
|
|
195
|
-
}),
|
|
196
|
-
this.registry.on("disposed", (instance) => {
|
|
197
|
-
this.notifyPlugins("onDestroyed", instance);
|
|
198
|
-
this.detachStateBridge(instance);
|
|
199
|
-
}),
|
|
200
|
-
this.registry.on("refAcquired", (instance, refId) => {
|
|
201
|
-
this.notifyPlugins("onRefAcquired", instance, refId);
|
|
202
|
-
}),
|
|
203
|
-
this.registry.on("refReleased", (instance, refId) => {
|
|
204
|
-
this.notifyPlugins("onRefReleased", instance, refId);
|
|
205
|
-
}),
|
|
206
|
-
this.registry.on("depsChanged", (instance, previousDeps, currentDeps) => {
|
|
207
|
-
this.notifyPlugins("onDepsChanged", instance, previousDeps, currentDeps);
|
|
208
|
-
})
|
|
209
|
-
];
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Subscribe to the container's channel with `ALL_PATHS` interest, so we
|
|
213
|
-
* fire on every flush. Capture `prev` from the snapshot taken on the
|
|
214
|
-
* previous flush (or at create-time for the first flush) and pass the
|
|
215
|
-
* channel's `paths` argument straight through to plugins.
|
|
216
|
-
*
|
|
217
|
-
* Per-container bookkeeping is stored in a `WeakMap` keyed by the
|
|
218
|
-
* container itself, so a disposed/GC'd container drops cleanly.
|
|
219
|
-
*/
|
|
220
|
-
attachStateBridge(container) {
|
|
221
|
-
if (this.containerBridges.has(container)) return;
|
|
222
|
-
const bridge = {
|
|
223
|
-
unsub: () => {},
|
|
224
|
-
prevState: container.state
|
|
225
|
-
};
|
|
226
|
-
this.containerBridges.set(container, bridge);
|
|
227
|
-
bridge.unsub = container.channel.subscribe(() => _dirtytalk_structural.ALL_PATHS, (paths) => this.dispatchStateChange(container, paths));
|
|
228
|
-
}
|
|
229
|
-
detachStateBridge(container) {
|
|
230
|
-
const bridge = this.containerBridges.get(container);
|
|
231
|
-
if (!bridge) return;
|
|
232
|
-
bridge.unsub();
|
|
233
|
-
this.containerBridges.delete(container);
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Channel-flush callback. Snapshots `next`, hands `(prev, next, paths)`
|
|
237
|
-
* to every enabled plugin's `onStateChange`, then updates `prevState`
|
|
238
|
-
* for the next flush.
|
|
239
|
-
*
|
|
240
|
-
* Note: `prev` is captured once and reused across plugins — every
|
|
241
|
-
* plugin sees the same `prev`/`next`/`paths` regardless of dispatch
|
|
242
|
-
* order, matching the "snapshot prev once per flush" invariant.
|
|
243
|
-
*/
|
|
244
|
-
dispatchStateChange(container, paths) {
|
|
245
|
-
const bridge = this.containerBridges.get(container);
|
|
246
|
-
if (!bridge) return;
|
|
247
|
-
const prev = bridge.prevState;
|
|
248
|
-
const next = container.state;
|
|
249
|
-
bridge.prevState = next;
|
|
250
|
-
for (const { plugin, config } of this.plugins.values()) {
|
|
251
|
-
if (!config.enabled) continue;
|
|
252
|
-
const hook = plugin.onStateChange;
|
|
253
|
-
if (typeof hook !== "function") continue;
|
|
254
|
-
try {
|
|
255
|
-
hook.call(plugin, this.buildContext(container), prev, next, paths);
|
|
256
|
-
} catch (error) {
|
|
257
|
-
console.error(`[BlaC] Error in plugin "${plugin.name}" onStateChange:`, error);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Notify all plugins of a lifecycle event.
|
|
263
|
-
*
|
|
264
|
-
* Builds a fresh `PluginContext` per dispatch (instance becomes
|
|
265
|
-
* `ctx.container`), so plugins can reach the focal bloc through
|
|
266
|
-
* `ctx.container`.
|
|
267
|
-
*/
|
|
268
|
-
notifyPlugins(hookName, instance, ...extraArgs) {
|
|
269
|
-
for (const { plugin, config } of this.plugins.values()) {
|
|
270
|
-
if (!config.enabled) continue;
|
|
271
|
-
const hook = plugin[hookName];
|
|
272
|
-
if (typeof hook !== "function") continue;
|
|
273
|
-
try {
|
|
274
|
-
hook.call(plugin, this.buildContext(instance), ...extraArgs);
|
|
275
|
-
} catch (error) {
|
|
276
|
-
console.error(`[BlaC] Error in plugin "${plugin.name}" ${hookName}:`, error);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Build a `PluginContext` for a given focal container. The context is
|
|
282
|
-
* cheap to build — its methods close over `this.registry` directly —
|
|
283
|
-
* so we create one per dispatch rather than caching per container.
|
|
284
|
-
* This sidesteps the lifetime question of "when do we evict a cached
|
|
285
|
-
* context?" and keeps `paths`-vs-`container` lifetimes cleanly
|
|
286
|
-
* separated.
|
|
287
|
-
*/
|
|
288
|
-
buildContext(container) {
|
|
289
|
-
const registry = this.registry;
|
|
290
|
-
return {
|
|
291
|
-
container,
|
|
292
|
-
getInstanceMetadata: (instance) => {
|
|
293
|
-
return {
|
|
294
|
-
id: instance.$blac.id,
|
|
295
|
-
className: instance.constructor.name,
|
|
296
|
-
isDisposed: instance.$blac.disposed,
|
|
297
|
-
name: instance.$blac.name,
|
|
298
|
-
createdAt: instance.$blac.createdAt,
|
|
299
|
-
state: instance.state,
|
|
300
|
-
hydrationStatus: instance.$blac.hydration.status,
|
|
301
|
-
isHydrated: instance.$blac.hydration.isHydrated,
|
|
302
|
-
hydrationError: instance.$blac.hydration.error,
|
|
303
|
-
changedWhileHydrating: instance.$blac.hydration.changedWhileHydrating,
|
|
304
|
-
args: instance.args
|
|
305
|
-
};
|
|
306
|
-
},
|
|
307
|
-
getState: (instance) => {
|
|
308
|
-
return instance.state;
|
|
309
|
-
},
|
|
310
|
-
getHydrationStatus: (instance) => {
|
|
311
|
-
return instance.$blac.hydration.status;
|
|
312
|
-
},
|
|
313
|
-
startHydration: (instance) => {
|
|
314
|
-
instance.$blac.hydration.begin();
|
|
315
|
-
},
|
|
316
|
-
applyHydratedState: (instance, state) => {
|
|
317
|
-
return instance.$blac.hydration.apply(state);
|
|
318
|
-
},
|
|
319
|
-
finishHydration: (instance) => {
|
|
320
|
-
instance.$blac.hydration.finish();
|
|
321
|
-
},
|
|
322
|
-
failHydration: (instance, error) => {
|
|
323
|
-
instance.$blac.hydration.fail(error);
|
|
324
|
-
},
|
|
325
|
-
waitForHydration: (instance) => {
|
|
326
|
-
return instance.$blac.hydration.wait();
|
|
327
|
-
},
|
|
328
|
-
queryInstances: (typeClass) => {
|
|
329
|
-
return registry.getAll(typeClass);
|
|
330
|
-
},
|
|
331
|
-
getAllTypes: () => {
|
|
332
|
-
return registry.getTypes();
|
|
333
|
-
},
|
|
334
|
-
getStats: () => {
|
|
335
|
-
return registry.getStats();
|
|
336
|
-
},
|
|
337
|
-
getRefIds: (instanceId) => {
|
|
338
|
-
for (const Type of registry.getTypes()) {
|
|
339
|
-
const map = registry.getInstancesMap(Type);
|
|
340
|
-
for (const [, entry] of map) if (entry.instance.$blac.id === instanceId) return Array.from(entry.refs.keys());
|
|
341
|
-
}
|
|
342
|
-
return [];
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Check if plugin should be enabled based on environment
|
|
348
|
-
*/
|
|
349
|
-
shouldEnablePlugin(config) {
|
|
350
|
-
if (!config.enabled) return false;
|
|
351
|
-
if (config.environment === "all") return true;
|
|
352
|
-
return this.getCurrentEnvironment() === config.environment;
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Get current environment
|
|
356
|
-
*/
|
|
357
|
-
getCurrentEnvironment() {
|
|
358
|
-
if (typeof process !== "undefined") {
|
|
359
|
-
if (process.env.NODE_ENV === "test") return "test";
|
|
360
|
-
if (process.env.NODE_ENV === "production") return "production";
|
|
361
|
-
return "development";
|
|
362
|
-
}
|
|
363
|
-
return "development";
|
|
364
|
-
}
|
|
365
|
-
};
|
|
366
|
-
/**
|
|
367
|
-
* Create a plugin manager instance
|
|
368
|
-
* @param registry - The StateContainerRegistry to monitor for lifecycle events
|
|
369
|
-
* @returns A new PluginManager instance
|
|
370
|
-
*/
|
|
371
|
-
function createPluginManager(registry) {
|
|
372
|
-
return new PluginManager(registry);
|
|
373
|
-
}
|
|
374
|
-
//#endregion
|
|
375
58
|
//#region src/constants.ts
|
|
376
59
|
/**
|
|
377
60
|
* Default configuration constants for BlaC
|
|
@@ -379,19 +62,6 @@ function createPluginManager(registry) {
|
|
|
379
62
|
* Centralized location for all magic numbers and default values.
|
|
380
63
|
*/
|
|
381
64
|
/**
|
|
382
|
-
* Default configuration constants for BlaC
|
|
383
|
-
*/
|
|
384
|
-
const BLAC_DEFAULTS = {
|
|
385
|
-
/**
|
|
386
|
-
* Default instance key for shared instances
|
|
387
|
-
*/
|
|
388
|
-
DEFAULT_INSTANCE_KEY: "default",
|
|
389
|
-
/**
|
|
390
|
-
* Maximum getter nesting depth (prevents infinite recursion)
|
|
391
|
-
*/
|
|
392
|
-
MAX_GETTER_DEPTH: 10
|
|
393
|
-
};
|
|
394
|
-
/**
|
|
395
65
|
* Static property names for StateContainer classes
|
|
396
66
|
* Used for feature flags and configuration on bloc classes
|
|
397
67
|
*/
|
|
@@ -416,19 +86,33 @@ const BLAC_STATIC_PROPS = {
|
|
|
416
86
|
* instead of using a structural hash of `args`. Allows blocs to ignore
|
|
417
87
|
* non-identity fields (e.g., `readonly` flags) while still keying by id.
|
|
418
88
|
*/
|
|
419
|
-
KEY: "key"
|
|
89
|
+
KEY: "key",
|
|
90
|
+
/**
|
|
91
|
+
* Explicit, minification-safe identity for a bloc class: `static blacName = '...'`.
|
|
92
|
+
* When unset, identity falls back to `constructor.name`.
|
|
93
|
+
*/
|
|
94
|
+
BLAC_NAME: "blacName"
|
|
420
95
|
};
|
|
421
96
|
/**
|
|
422
97
|
* Standard error message prefix
|
|
423
98
|
*/
|
|
424
99
|
const BLAC_ERROR_PREFIX = "[BlaC]";
|
|
100
|
+
/**
|
|
101
|
+
* True outside production builds.
|
|
102
|
+
*
|
|
103
|
+
* Reads `process.env.NODE_ENV` defensively: plain ESM in the browser, Deno and
|
|
104
|
+
* some test runners have no `process` binding, where a bare read throws.
|
|
105
|
+
* Bundlers that define `process.env.NODE_ENV` still constant-fold this.
|
|
106
|
+
*/
|
|
107
|
+
const IS_DEV = typeof process === "undefined" || process.env?.NODE_ENV !== "production";
|
|
425
108
|
//#endregion
|
|
426
109
|
//#region src/utils/static-props.ts
|
|
427
110
|
/**
|
|
428
111
|
* Utility functions for accessing static properties on StateContainer classes
|
|
429
112
|
*/
|
|
430
113
|
/**
|
|
431
|
-
* Get a static property from a class constructor
|
|
114
|
+
* Get a static property from a class constructor, walking the prototype
|
|
115
|
+
* chain so subclasses inherit the value unless they define their own.
|
|
432
116
|
* Type-safe helper that avoids (Type as any) casts
|
|
433
117
|
*
|
|
434
118
|
* @param Type - The class constructor
|
|
@@ -440,8 +124,20 @@ function getStaticProp(Type, propName, defaultValue) {
|
|
|
440
124
|
return Type[propName] ?? defaultValue;
|
|
441
125
|
}
|
|
442
126
|
/**
|
|
127
|
+
* Get a static property declared directly on `Type`, ignoring the prototype
|
|
128
|
+
* chain, so subclasses never inherit a base class's value.
|
|
129
|
+
*
|
|
130
|
+
* @param Type - The class constructor
|
|
131
|
+
* @param propName - The property name to access
|
|
132
|
+
* @returns The own property value or `undefined`
|
|
133
|
+
*/
|
|
134
|
+
function getOwnStaticProp(Type, propName) {
|
|
135
|
+
return Object.hasOwn(Type, propName) ? Type[propName] : void 0;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
443
138
|
* Check if a class is marked as keepAlive.
|
|
444
139
|
* KeepAlive classes are never auto-disposed when ref count reaches 0.
|
|
140
|
+
* Inherited: a subclass keeps a base class's `keepAlive` unless overridden.
|
|
445
141
|
* @param Type - The class constructor to check
|
|
446
142
|
* @returns true if the class has `static keepAlive = true`
|
|
447
143
|
*/
|
|
@@ -451,6 +147,7 @@ function isKeepAliveClass(Type) {
|
|
|
451
147
|
/**
|
|
452
148
|
* Check if a class should be excluded from DevTools.
|
|
453
149
|
* Used to prevent infinite loops when DevTools tracks itself.
|
|
150
|
+
* Inherited: a subclass keeps a base class's exclusion unless overridden.
|
|
454
151
|
* @param Type - The class constructor to check
|
|
455
152
|
* @returns true if the class has `static __excludeFromDevTools = true`
|
|
456
153
|
*/
|
|
@@ -459,6 +156,7 @@ function isExcludedFromDevTools(Type) {
|
|
|
459
156
|
}
|
|
460
157
|
/**
|
|
461
158
|
* Get the per-class equality function set via `@blac({ equality })`, if any.
|
|
159
|
+
* Inherited: a subclass keeps a base class's equality fn unless overridden.
|
|
462
160
|
* @param Type - The class constructor to check
|
|
463
161
|
* @returns the equality function or `undefined`
|
|
464
162
|
*/
|
|
@@ -467,13 +165,26 @@ function getClassEquality(Type) {
|
|
|
467
165
|
return typeof fn === "function" ? fn : void 0;
|
|
468
166
|
}
|
|
469
167
|
/**
|
|
168
|
+
* Get a class's minification-safe identity name.
|
|
169
|
+
* Own only: a subclass never inherits a base class's explicit `blacName`,
|
|
170
|
+
* since that would collapse two distinct blocs onto one identity.
|
|
171
|
+
* Falls back to `Type.name` (the runtime `constructor.name`) when unset.
|
|
172
|
+
* @param Type - The class constructor to check
|
|
173
|
+
* @returns the explicit `static blacName` or `Type.name`
|
|
174
|
+
*/
|
|
175
|
+
function getBlacName(Type) {
|
|
176
|
+
return getOwnStaticProp(Type, BLAC_STATIC_PROPS.BLAC_NAME) ?? Type.name;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
470
179
|
* Get the per-class key function set via `@blac({ key })` or `static key = …`, if any.
|
|
471
180
|
* Used by the registry to derive a stable instance key from `args`.
|
|
181
|
+
* Own only: a subclass never inherits a base class's `key`, since a
|
|
182
|
+
* different `Args` shape would derive the wrong instance key.
|
|
472
183
|
* @param Type - The class constructor to check
|
|
473
184
|
* @returns the key function or `undefined`
|
|
474
185
|
*/
|
|
475
186
|
function getClassKey(Type) {
|
|
476
|
-
const fn =
|
|
187
|
+
const fn = getOwnStaticProp(Type, BLAC_STATIC_PROPS.KEY);
|
|
477
188
|
return typeof fn === "function" ? fn : void 0;
|
|
478
189
|
}
|
|
479
190
|
//#endregion
|
|
@@ -490,11 +201,24 @@ const DEFAULT_STRUCTURAL_KEY = "default";
|
|
|
490
201
|
* - Object keys are sorted for order-independence.
|
|
491
202
|
* - Arrays keep their insertion order.
|
|
492
203
|
* - Functions throw — they must be passed via `deps`, not `args`.
|
|
204
|
+
* - Object args are memoized by identity; callers on hot paths (`resolveKey`,
|
|
205
|
+
* `depend`) re-resolve the same args object on every call.
|
|
493
206
|
*/
|
|
207
|
+
const keyCache = /* @__PURE__ */ new WeakMap();
|
|
494
208
|
function structuralKey(args) {
|
|
495
209
|
if (args === void 0 || args === null) return DEFAULT_STRUCTURAL_KEY;
|
|
210
|
+
if (typeof args === "object") {
|
|
211
|
+
const cached = keyCache.get(args);
|
|
212
|
+
if (cached !== void 0) return cached;
|
|
213
|
+
const key = serialize(args);
|
|
214
|
+
keyCache.set(args, key);
|
|
215
|
+
return key;
|
|
216
|
+
}
|
|
217
|
+
return serialize(args);
|
|
218
|
+
}
|
|
219
|
+
function serialize(args) {
|
|
496
220
|
return JSON.stringify(args, function(_k, v) {
|
|
497
|
-
if (typeof v === "function") throw new Error(
|
|
221
|
+
if (typeof v === "function") throw new Error(`[blac] args must be serializable; put refs/callbacks in \`deps\` (found a function at key "${_k || "(root)"}")`);
|
|
498
222
|
if (v && typeof v === "object" && !Array.isArray(v)) return Object.keys(v).sort().reduce((o, k) => {
|
|
499
223
|
o[k] = v[k];
|
|
500
224
|
return o;
|
|
@@ -506,7 +230,7 @@ function structuralKey(args) {
|
|
|
506
230
|
//#region src/core/symbols.ts
|
|
507
231
|
/**
|
|
508
232
|
* @internal Apply one owner's (consumer's) deps slice to an instance.
|
|
509
|
-
* Called by framework adapters (e.g.
|
|
233
|
+
* Called by framework adapters (e.g. `@blac/react` useBloc) — not public API.
|
|
510
234
|
*/
|
|
511
235
|
const APPLY_DEPS = Symbol("blac.applyDeps");
|
|
512
236
|
/**
|
|
@@ -515,6 +239,12 @@ const APPLY_DEPS = Symbol("blac.applyDeps");
|
|
|
515
239
|
*/
|
|
516
240
|
const REMOVE_DEPS_OWNER = Symbol("blac.removeDepsOwner");
|
|
517
241
|
/**
|
|
242
|
+
* @internal Subscribe to this specific instance's own disposal, bypassing
|
|
243
|
+
* the global registry `'disposed'` event. Called by `watch()` — not public
|
|
244
|
+
* API.
|
|
245
|
+
*/
|
|
246
|
+
const ON_DISPOSE = Symbol("blac.onDispose");
|
|
247
|
+
/**
|
|
518
248
|
* @internal Symbol-keyed configuration entry point on `StateContainer`.
|
|
519
249
|
* Writes the instance's identity fields (`_name`/`_debug`/`_instanceId`),
|
|
520
250
|
* resolves per-class equality, emits the registry `created` event, and runs
|
|
@@ -524,8 +254,27 @@ const REMOVE_DEPS_OWNER = Symbol("blac.removeDepsOwner");
|
|
|
524
254
|
* helpers are the sole callers, mirroring the `APPLY_DEPS` precedent.
|
|
525
255
|
*/
|
|
526
256
|
const INIT_CONFIG = Symbol("blac.initConfig");
|
|
257
|
+
/**
|
|
258
|
+
* @internal Run `fn` with `state` temporarily reporting a render's tracking
|
|
259
|
+
* proxy, so getters record the paths they read. Called by `@blac/react`'s
|
|
260
|
+
* `buildTrackedProxy` — not public API.
|
|
261
|
+
*
|
|
262
|
+
* Replaces the old `this`-Proxy receiver: getters now run with `this` bound to
|
|
263
|
+
* the real instance, so ES `#private` works in user blocs.
|
|
264
|
+
*/
|
|
265
|
+
const WITH_TRACKED_STATE = Symbol("blac.withTrackedState");
|
|
266
|
+
/**
|
|
267
|
+
* @internal Drive the activation lifecycle from the registry's 0↔1 ownership
|
|
268
|
+
* transition. Owns the per-instance AbortController so `onActivate`'s signal
|
|
269
|
+
* aborts on the matching deactivation and on dispose.
|
|
270
|
+
*
|
|
271
|
+
* Framework-only — `StateContainerRegistry` is the sole caller.
|
|
272
|
+
*/
|
|
273
|
+
const SET_ACTIVE = Symbol("blac.setActive");
|
|
527
274
|
//#endregion
|
|
528
275
|
//#region src/core/StateContainerRegistry.ts
|
|
276
|
+
/** Shared, read-only Map returned by `getInstancesMap` for unregistered types. */
|
|
277
|
+
const EMPTY_INSTANCES_MAP = /* @__PURE__ */ new Map();
|
|
529
278
|
/**
|
|
530
279
|
* Central registry for managing StateContainer instances.
|
|
531
280
|
* Handles instance lifecycle, named ref tracking, and lifecycle event emission.
|
|
@@ -539,19 +288,113 @@ const INIT_CONFIG = Symbol("blac.initConfig");
|
|
|
539
288
|
* console.log('State changed:', prev, '->', next);
|
|
540
289
|
* });
|
|
541
290
|
* ```
|
|
291
|
+
*
|
|
292
|
+
* `stateChanged` fires once per emit (microtask-deferred but uncoalesced), so
|
|
293
|
+
* listeners see every intermediate transition. Plugins' `onStateChange` fires
|
|
294
|
+
* once per channel flush with coalesced `prev`/`next` and a `PathSet`. Pick
|
|
295
|
+
* the transition log for devtools/time-travel, the plugin hook for
|
|
296
|
+
* change-driven work.
|
|
542
297
|
*/
|
|
543
298
|
var StateContainerRegistry = class {
|
|
299
|
+
get hasStateChangedListeners() {
|
|
300
|
+
return this._stateChangedListenerCount > 0;
|
|
301
|
+
}
|
|
544
302
|
constructor() {
|
|
545
303
|
this.instancesByConstructor = /* @__PURE__ */ new WeakMap();
|
|
546
304
|
this.types = /* @__PURE__ */ new Set();
|
|
547
|
-
this.
|
|
305
|
+
this._dependentEdges = /* @__PURE__ */ new WeakMap();
|
|
306
|
+
this._entryByInstance = /* @__PURE__ */ new WeakMap();
|
|
307
|
+
this._entryById = /* @__PURE__ */ new Map();
|
|
548
308
|
this.listeners = /* @__PURE__ */ new Map();
|
|
549
309
|
this._stateChangedListenerCount = 0;
|
|
550
310
|
this._pendingStateChanges = null;
|
|
551
311
|
this._autoRefIdCounter = 0;
|
|
312
|
+
this.on("disposed", (container) => this._handleDisposed(container));
|
|
552
313
|
}
|
|
553
|
-
|
|
554
|
-
|
|
314
|
+
/**
|
|
315
|
+
* Registry-internal reaction to any instance's `disposed` lifecycle event.
|
|
316
|
+
* If the disposing container is itself tracked in this registry (i.e. it
|
|
317
|
+
* was `acquire()`/`ensure()`'d, not a bare `new`), prune its Map entry and
|
|
318
|
+
* release its dependent edges on whatever it `depend()`'d on.
|
|
319
|
+
*/
|
|
320
|
+
_handleDisposed(container) {
|
|
321
|
+
const Type = container.constructor;
|
|
322
|
+
if (!this._pruneEntry(Type, container)) return;
|
|
323
|
+
const edges = this._dependentEdges.get(container);
|
|
324
|
+
if (!edges) return;
|
|
325
|
+
this._dependentEdges.delete(container);
|
|
326
|
+
for (const [DepType, keys] of edges) for (const depKey of keys) this._releaseDependent(DepType, depKey, container);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* An entry may be disposed only when nothing owns it: no public refs, no
|
|
330
|
+
* `depend()` dependents, and not keepAlive. Every dispose decision goes
|
|
331
|
+
* through here so `release()` and `_releaseDependent` cannot disagree.
|
|
332
|
+
*/
|
|
333
|
+
_isUnowned(Type, entry) {
|
|
334
|
+
return this._hasNoOwners(entry) && !isKeepAliveClass(Type);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Pure ownership: refs plus `depend()` dependents, with no keepAlive term.
|
|
338
|
+
* `_isUnowned` is "may be disposed"; this is "nothing is using it", which is
|
|
339
|
+
* what the activation lifecycle keys off — a keepAlive instance still
|
|
340
|
+
* deactivates when its last owner goes.
|
|
341
|
+
*/
|
|
342
|
+
_hasNoOwners(entry) {
|
|
343
|
+
return entry.refs.size === 0 && (entry.dependents === void 0 || entry.dependents.size === 0);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Single funnel for the 0↔1 ownership transition. `SET_ACTIVE` is idempotent,
|
|
347
|
+
* so every acquire/release path can call this unconditionally rather than
|
|
348
|
+
* each computing the edge itself. Emits `activated`/`deactivated` for
|
|
349
|
+
* plugins to observe the same transition `onActivate`/`onDeactivate` expose
|
|
350
|
+
* to bloc authors — after `SET_ACTIVE` has already run the instance's own
|
|
351
|
+
* hook, so plugins always see a container that has finished reacting.
|
|
352
|
+
*/
|
|
353
|
+
_syncActivation(entry) {
|
|
354
|
+
const transition = entry.instance[SET_ACTIVE](!this._hasNoOwners(entry));
|
|
355
|
+
if (transition === "none") return;
|
|
356
|
+
if (transition === "deactivated") this.emit("deactivated", entry.instance);
|
|
357
|
+
else this.emit("activated", entry.instance, transition.signal);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Record that `dependent` resolved `Type` at `key`, so the edge can be
|
|
361
|
+
* released on the owner's disposal. Keyed per resolved key, not per type:
|
|
362
|
+
* one `depend()` handle resolves a distinct key for every `args` it is
|
|
363
|
+
* called with, and all of them must be swept.
|
|
364
|
+
*/
|
|
365
|
+
_recordDependentEdge(dependent, Type, key) {
|
|
366
|
+
let byType = this._dependentEdges.get(dependent);
|
|
367
|
+
if (!byType) this._dependentEdges.set(dependent, byType = /* @__PURE__ */ new Map());
|
|
368
|
+
let keys = byType.get(Type);
|
|
369
|
+
if (!keys) byType.set(Type, keys = /* @__PURE__ */ new Set());
|
|
370
|
+
keys.add(key);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Remove the Map entry for `container`, if this registry is tracking it.
|
|
374
|
+
* @returns true if an entry was found and removed
|
|
375
|
+
*/
|
|
376
|
+
_pruneEntry(Type, container) {
|
|
377
|
+
const entry = this._entryByInstance.get(container);
|
|
378
|
+
if (!entry) return false;
|
|
379
|
+
this.instancesByConstructor.get(Type)?.delete(entry.key);
|
|
380
|
+
this._entryById.delete(container.$blac.id);
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Drop `dependent`'s edge on the `Type`/`key` entry (a `depend()`-resolved
|
|
385
|
+
* instance). When that leaves the entry with no dependents AND no public
|
|
386
|
+
* refs AND it isn't keepAlive, dispose it — this recurses into the same
|
|
387
|
+
* `disposed` listener, so dep-of-dep chains unwind naturally.
|
|
388
|
+
*/
|
|
389
|
+
_releaseDependent(Type, key, dependent) {
|
|
390
|
+
const entry = this.instancesByConstructor.get(Type)?.get(key);
|
|
391
|
+
if (!entry) return;
|
|
392
|
+
entry.dependents?.delete(dependent);
|
|
393
|
+
if (this._isUnowned(Type, entry)) {
|
|
394
|
+
if (!entry.instance.$blac.disposed) entry.instance.dispose();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
this._syncActivation(entry);
|
|
555
398
|
}
|
|
556
399
|
/**
|
|
557
400
|
* Register a type for lifecycle event tracking
|
|
@@ -566,9 +409,7 @@ var StateContainerRegistry = class {
|
|
|
566
409
|
* @throws Error if type is already registered
|
|
567
410
|
*/
|
|
568
411
|
register(constructor) {
|
|
569
|
-
|
|
570
|
-
if (this.registeredTypeNames.has(className)) throw new Error(`${BLAC_ERROR_PREFIX} Type "${className}" is already registered`);
|
|
571
|
-
this.registeredTypeNames.add(className);
|
|
412
|
+
if (this.types.has(constructor)) throw new Error(`${BLAC_ERROR_PREFIX} Type "${getBlacName(constructor)}" is already registered`);
|
|
572
413
|
this.registerType(constructor);
|
|
573
414
|
}
|
|
574
415
|
ensureInstancesMap(Type) {
|
|
@@ -583,7 +424,7 @@ var StateContainerRegistry = class {
|
|
|
583
424
|
* Get the instances Map for a specific class (public API for stats/debugging)
|
|
584
425
|
*/
|
|
585
426
|
getInstancesMap(Type) {
|
|
586
|
-
return this.instancesByConstructor.get(Type) ||
|
|
427
|
+
return this.instancesByConstructor.get(Type) || EMPTY_INSTANCES_MAP;
|
|
587
428
|
}
|
|
588
429
|
/**
|
|
589
430
|
* Directly insert an instance entry into the registry without going through
|
|
@@ -600,10 +441,14 @@ var StateContainerRegistry = class {
|
|
|
600
441
|
const instances = this.ensureInstancesMap(Type);
|
|
601
442
|
const existingEntry = instances.get(instanceKey);
|
|
602
443
|
if (existingEntry && existingEntry.instance !== instance && !existingEntry.instance.$blac.disposed) existingEntry.instance.dispose();
|
|
603
|
-
|
|
444
|
+
const entry = {
|
|
604
445
|
instance,
|
|
446
|
+
key: instanceKey,
|
|
605
447
|
refs
|
|
606
|
-
}
|
|
448
|
+
};
|
|
449
|
+
instances.set(instanceKey, entry);
|
|
450
|
+
this._entryByInstance.set(instance, entry);
|
|
451
|
+
this._entryById.set(instance.$blac.id, entry);
|
|
607
452
|
}
|
|
608
453
|
/**
|
|
609
454
|
* Resolve the storage key for an instance. This is the single source of truth
|
|
@@ -611,7 +456,7 @@ var StateContainerRegistry = class {
|
|
|
611
456
|
* an args-derived key is never dropped (instance leaks).
|
|
612
457
|
*
|
|
613
458
|
* Resolution order (explicit beats derived):
|
|
614
|
-
* explicit key
|
|
459
|
+
* explicit key \> `static key(args)` \> structural hash of args \> default sentinel.
|
|
615
460
|
*
|
|
616
461
|
* @param Type - The StateContainer class constructor
|
|
617
462
|
* @param instanceKey - Explicit key, or undefined to derive from args
|
|
@@ -652,10 +497,13 @@ var StateContainerRegistry = class {
|
|
|
652
497
|
* wrapper; `useBloc` and `watch` address a pre-resolved key here.
|
|
653
498
|
* @param Type - The StateContainer class constructor
|
|
654
499
|
* @param instanceKey - Pre-resolved instance key (defaults to 'default')
|
|
655
|
-
* @param options - Acquisition options
|
|
656
|
-
*
|
|
657
|
-
*
|
|
658
|
-
*
|
|
500
|
+
* @param options - Acquisition options: `canCreate` (create when absent,
|
|
501
|
+
* default true), `countRef` (add a reference, default true), `refId`
|
|
502
|
+
* (named reference for debugging, auto-generated when omitted),
|
|
503
|
+
* `dependent` — the `depend()`-owner resolving this instance, recorded so
|
|
504
|
+
* its dependent edge is released on the owner's disposal — and
|
|
505
|
+
* `sweepIfUnowned`, for callers that create speculatively and claim
|
|
506
|
+
* ownership later (see {@link _scheduleSweep}).
|
|
659
507
|
* @returns The state container instance
|
|
660
508
|
*/
|
|
661
509
|
acquire(Type, instanceKey, options = {}) {
|
|
@@ -673,9 +521,9 @@ var StateContainerRegistry = class {
|
|
|
673
521
|
entry = void 0;
|
|
674
522
|
}
|
|
675
523
|
if (entry) {
|
|
676
|
-
if (
|
|
524
|
+
if (IS_DEV && args !== void 0 && entry.args !== void 0) {
|
|
677
525
|
const incomingKey = structuralKey(args);
|
|
678
|
-
const storedKey = structuralKey(entry.args);
|
|
526
|
+
const storedKey = entry.argsKey ??= structuralKey(entry.args);
|
|
679
527
|
if (incomingKey !== storedKey) console.warn(`${BLAC_ERROR_PREFIX} ${Type.name} instance key "${resolvedKey}" was acquired with different args. Existing args: ${storedKey}, new args: ${incomingKey}. The existing instance will be reused. If distinct args should produce distinct instances, either remove the explicit instanceKey or provide a \`static key\` function that reflects the difference.`);
|
|
680
528
|
}
|
|
681
529
|
if (countRef) {
|
|
@@ -684,6 +532,11 @@ var StateContainerRegistry = class {
|
|
|
684
532
|
this.assertRefLimit(Type, resolvedKey, entry.refs.size);
|
|
685
533
|
this.emit("refAcquired", entry.instance, refId);
|
|
686
534
|
}
|
|
535
|
+
if (options.dependent) {
|
|
536
|
+
(entry.dependents ??= /* @__PURE__ */ new Set()).add(options.dependent);
|
|
537
|
+
this._recordDependentEdge(options.dependent, Type, resolvedKey);
|
|
538
|
+
}
|
|
539
|
+
this._syncActivation(entry);
|
|
687
540
|
return entry.instance;
|
|
688
541
|
}
|
|
689
542
|
if (!canCreate) throw new Error(`${BLAC_ERROR_PREFIX} ${Type.name} instance "${resolvedKey}" not found and creation is disabled.`);
|
|
@@ -696,16 +549,46 @@ var StateContainerRegistry = class {
|
|
|
696
549
|
initialRefId = options.refId ?? `_auto_${this._autoRefIdCounter++}`;
|
|
697
550
|
initialRefs.set(initialRefId, 1);
|
|
698
551
|
}
|
|
699
|
-
|
|
552
|
+
const newEntry = {
|
|
700
553
|
instance,
|
|
554
|
+
key: resolvedKey,
|
|
701
555
|
refs: initialRefs,
|
|
702
556
|
args
|
|
703
|
-
}
|
|
557
|
+
};
|
|
558
|
+
if (options.dependent) {
|
|
559
|
+
(newEntry.dependents ??= /* @__PURE__ */ new Set()).add(options.dependent);
|
|
560
|
+
this._recordDependentEdge(options.dependent, Type, resolvedKey);
|
|
561
|
+
}
|
|
562
|
+
instances.set(resolvedKey, newEntry);
|
|
563
|
+
this._entryByInstance.set(instance, newEntry);
|
|
564
|
+
this._entryById.set(instance.$blac.id, newEntry);
|
|
704
565
|
this.registerType(Type);
|
|
705
566
|
if (initialRefId) this.emit("refAcquired", instance, initialRefId);
|
|
567
|
+
this._syncActivation(newEntry);
|
|
568
|
+
if (options.sweepIfUnowned && this._hasNoOwners(newEntry)) this._scheduleSweep(Type, newEntry);
|
|
706
569
|
return instance;
|
|
707
570
|
}
|
|
708
571
|
/**
|
|
572
|
+
* Speculative creates (`useBloc`'s render-time create) leak forever when the
|
|
573
|
+
* render is discarded or never commits — SSR has no commit at all, so nothing
|
|
574
|
+
* ever claims ownership. Sweep at the end of the microtask unless the entry
|
|
575
|
+
* gained an owner or is keepAlive.
|
|
576
|
+
*
|
|
577
|
+
* Opt-in, not automatic: a bare `ensure()` hands the instance to a caller
|
|
578
|
+
* that legitimately holds it without a ref, and sweeping those would make
|
|
579
|
+
* `ensure` unusable across an `await`.
|
|
580
|
+
*/
|
|
581
|
+
_scheduleSweep(Type, entry) {
|
|
582
|
+
queueMicrotask(() => {
|
|
583
|
+
const instances = this.instancesByConstructor.get(Type);
|
|
584
|
+
if (instances?.get(entry.key) !== entry) return;
|
|
585
|
+
if (entry.instance.$blac.disposed) return;
|
|
586
|
+
if (!this._isUnowned(Type, entry)) return;
|
|
587
|
+
entry.instance.dispose();
|
|
588
|
+
instances.delete(entry.key);
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
709
592
|
* Borrow an existing instance without adding a ref (borrowing semantics).
|
|
710
593
|
* Tracks cross-bloc dependency for reactive updates.
|
|
711
594
|
*
|
|
@@ -715,7 +598,7 @@ var StateContainerRegistry = class {
|
|
|
715
598
|
* @returns The state container instance
|
|
716
599
|
* @throws Error if instance doesn't exist
|
|
717
600
|
*/
|
|
718
|
-
borrow(Type, instanceKey =
|
|
601
|
+
borrow(Type, instanceKey = DEFAULT_STRUCTURAL_KEY) {
|
|
719
602
|
return this.acquire(Type, instanceKey, {
|
|
720
603
|
canCreate: false,
|
|
721
604
|
countRef: false
|
|
@@ -730,7 +613,7 @@ var StateContainerRegistry = class {
|
|
|
730
613
|
* @param instanceKey - Pre-resolved instance key (defaults to 'default')
|
|
731
614
|
* @returns Discriminated union with either the instance or an error
|
|
732
615
|
*/
|
|
733
|
-
borrowSafe(Type, instanceKey =
|
|
616
|
+
borrowSafe(Type, instanceKey = DEFAULT_STRUCTURAL_KEY) {
|
|
734
617
|
try {
|
|
735
618
|
return {
|
|
736
619
|
error: null,
|
|
@@ -776,7 +659,7 @@ var StateContainerRegistry = class {
|
|
|
776
659
|
* @param forceDispose - Force immediate disposal regardless of refs
|
|
777
660
|
* @param refId - The specific ref to remove; removes one arbitrary ref if omitted
|
|
778
661
|
*/
|
|
779
|
-
release(Type, instanceKey =
|
|
662
|
+
release(Type, instanceKey = DEFAULT_STRUCTURAL_KEY, forceDispose = false, refId) {
|
|
780
663
|
const instances = this.ensureInstancesMap(Type);
|
|
781
664
|
const entry = instances.get(instanceKey);
|
|
782
665
|
if (!entry) return;
|
|
@@ -801,20 +684,12 @@ var StateContainerRegistry = class {
|
|
|
801
684
|
}
|
|
802
685
|
}
|
|
803
686
|
if (releasedRefId) this.emit("refReleased", entry.instance, releasedRefId);
|
|
804
|
-
|
|
805
|
-
if (entry.refs.size === 0 && !keepAlive) {
|
|
806
|
-
const deps = entry.instance.$blac.dependencies;
|
|
687
|
+
if (this._isUnowned(Type, entry)) {
|
|
807
688
|
if (!entry.instance.$blac.disposed) entry.instance.dispose();
|
|
808
689
|
instances.delete(instanceKey);
|
|
809
|
-
|
|
810
|
-
const depInstances = this.ensureInstancesMap(DepType);
|
|
811
|
-
const depEntry = depInstances.get(depKey);
|
|
812
|
-
if (depEntry && depEntry.refs.size === 0 && !isKeepAliveClass(DepType) && !depEntry.instance.$blac.disposed) {
|
|
813
|
-
depEntry.instance.dispose();
|
|
814
|
-
depInstances.delete(depKey);
|
|
815
|
-
}
|
|
816
|
-
}
|
|
690
|
+
return;
|
|
817
691
|
}
|
|
692
|
+
this._syncActivation(entry);
|
|
818
693
|
}
|
|
819
694
|
/**
|
|
820
695
|
* Get all instances of a specific type.
|
|
@@ -824,7 +699,7 @@ var StateContainerRegistry = class {
|
|
|
824
699
|
getAll(Type) {
|
|
825
700
|
const instances = this.ensureInstancesMap(Type);
|
|
826
701
|
const result = [];
|
|
827
|
-
for (const entry of instances.values()) result.push(entry.instance);
|
|
702
|
+
for (const entry of instances.values()) if (!entry.instance.$blac.disposed) result.push(entry.instance);
|
|
828
703
|
return result;
|
|
829
704
|
}
|
|
830
705
|
/**
|
|
@@ -861,7 +736,7 @@ var StateContainerRegistry = class {
|
|
|
861
736
|
* @param instanceKey - Pre-resolved instance key (defaults to 'default')
|
|
862
737
|
* @returns Current ref count (0 if instance doesn't exist)
|
|
863
738
|
*/
|
|
864
|
-
getRefCount(Type, instanceKey =
|
|
739
|
+
getRefCount(Type, instanceKey = DEFAULT_STRUCTURAL_KEY) {
|
|
865
740
|
return this.ensureInstancesMap(Type).get(instanceKey)?.refs.size ?? 0;
|
|
866
741
|
}
|
|
867
742
|
/**
|
|
@@ -872,13 +747,23 @@ var StateContainerRegistry = class {
|
|
|
872
747
|
* @param instanceKey - Pre-resolved instance key (defaults to 'default')
|
|
873
748
|
* @returns Array of ref ID strings (empty if instance doesn't exist)
|
|
874
749
|
*/
|
|
875
|
-
getRefIds(Type, instanceKey =
|
|
750
|
+
getRefIds(Type, instanceKey = DEFAULT_STRUCTURAL_KEY) {
|
|
876
751
|
const instances = this.instancesByConstructor.get(Type);
|
|
877
752
|
if (!instances) return [];
|
|
878
753
|
const entry = instances.get(instanceKey);
|
|
879
754
|
return entry ? Array.from(entry.refs.keys()) : [];
|
|
880
755
|
}
|
|
881
756
|
/**
|
|
757
|
+
* Get all active reference IDs for an instance by its `$blac.id`, without
|
|
758
|
+
* needing the owning Type. Used by `PluginContext.getRefIds`.
|
|
759
|
+
* @param instanceId - The instance's `$blac.id`
|
|
760
|
+
* @returns Array of ref ID strings (empty if instance doesn't exist)
|
|
761
|
+
*/
|
|
762
|
+
getRefIdsById(instanceId) {
|
|
763
|
+
const entry = this._entryById.get(instanceId);
|
|
764
|
+
return entry ? Array.from(entry.refs.keys()) : [];
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
882
767
|
* Check if an instance exists.
|
|
883
768
|
*
|
|
884
769
|
* @internal Internal key tier; public callers use the args-based `hasInstance`.
|
|
@@ -886,7 +771,7 @@ var StateContainerRegistry = class {
|
|
|
886
771
|
* @param instanceKey - Pre-resolved instance key (defaults to 'default')
|
|
887
772
|
* @returns true if instance exists
|
|
888
773
|
*/
|
|
889
|
-
hasInstance(Type, instanceKey =
|
|
774
|
+
hasInstance(Type, instanceKey = DEFAULT_STRUCTURAL_KEY) {
|
|
890
775
|
return this.ensureInstancesMap(Type).has(instanceKey);
|
|
891
776
|
}
|
|
892
777
|
/**
|
|
@@ -898,7 +783,6 @@ var StateContainerRegistry = class {
|
|
|
898
783
|
clearAll() {
|
|
899
784
|
for (const Type of this.types) this.clear(Type);
|
|
900
785
|
this.types.clear();
|
|
901
|
-
this.registeredTypeNames.clear();
|
|
902
786
|
}
|
|
903
787
|
/**
|
|
904
788
|
* Get registry statistics for debugging.
|
|
@@ -933,9 +817,11 @@ var StateContainerRegistry = class {
|
|
|
933
817
|
* @returns Unsubscribe function
|
|
934
818
|
*/
|
|
935
819
|
on(event, listener) {
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
820
|
+
let instance = this.listeners.get(event);
|
|
821
|
+
if (!instance) {
|
|
822
|
+
instance = /* @__PURE__ */ new Set();
|
|
823
|
+
this.listeners.set(event, instance);
|
|
824
|
+
}
|
|
939
825
|
instance.add(listener);
|
|
940
826
|
if (event === "stateChanged") this._stateChangedListenerCount++;
|
|
941
827
|
return () => {
|
|
@@ -968,6 +854,15 @@ var StateContainerRegistry = class {
|
|
|
968
854
|
newState
|
|
969
855
|
]);
|
|
970
856
|
}
|
|
857
|
+
/**
|
|
858
|
+
* Deliver one event per emit, in order — deliberately NOT coalesced.
|
|
859
|
+
*
|
|
860
|
+
* This is a transition log: devtools, time-travel debugging and perf
|
|
861
|
+
* monitoring need every intermediate `prev`/`next`, which coalescing would
|
|
862
|
+
* destroy. The plugin `onStateChange` bridge is the coalesced, `PathSet`-
|
|
863
|
+
* carrying lane (see `PluginManager.setupLifecycleHooks`); the two differ on
|
|
864
|
+
* purpose, so a listener picks the lane that matches what it needs.
|
|
865
|
+
*/
|
|
971
866
|
flushStateChanged() {
|
|
972
867
|
const pending = this._pendingStateChanges;
|
|
973
868
|
this._pendingStateChanges = null;
|
|
@@ -977,19 +872,9 @@ var StateContainerRegistry = class {
|
|
|
977
872
|
};
|
|
978
873
|
/**
|
|
979
874
|
* Global default registry instance
|
|
875
|
+
* @public
|
|
980
876
|
*/
|
|
981
877
|
const globalRegistry = new StateContainerRegistry();
|
|
982
|
-
/**
|
|
983
|
-
* Global plugin manager (initialized lazily)
|
|
984
|
-
*/
|
|
985
|
-
let _globalPluginManager = null;
|
|
986
|
-
/**
|
|
987
|
-
* Get the global plugin manager
|
|
988
|
-
*/
|
|
989
|
-
function getPluginManager() {
|
|
990
|
-
if (!_globalPluginManager) _globalPluginManager = createPluginManager(globalRegistry);
|
|
991
|
-
return _globalPluginManager;
|
|
992
|
-
}
|
|
993
878
|
//#endregion
|
|
994
879
|
Object.defineProperty(exports, "APPLY_DEPS", {
|
|
995
880
|
enumerable: true,
|
|
@@ -1009,10 +894,16 @@ Object.defineProperty(exports, "INIT_CONFIG", {
|
|
|
1009
894
|
return INIT_CONFIG;
|
|
1010
895
|
}
|
|
1011
896
|
});
|
|
1012
|
-
Object.defineProperty(exports, "
|
|
897
|
+
Object.defineProperty(exports, "IS_DEV", {
|
|
898
|
+
enumerable: true,
|
|
899
|
+
get: function() {
|
|
900
|
+
return IS_DEV;
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
Object.defineProperty(exports, "ON_DISPOSE", {
|
|
1013
904
|
enumerable: true,
|
|
1014
905
|
get: function() {
|
|
1015
|
-
return
|
|
906
|
+
return ON_DISPOSE;
|
|
1016
907
|
}
|
|
1017
908
|
});
|
|
1018
909
|
Object.defineProperty(exports, "REMOVE_DEPS_OWNER", {
|
|
@@ -1021,12 +912,24 @@ Object.defineProperty(exports, "REMOVE_DEPS_OWNER", {
|
|
|
1021
912
|
return REMOVE_DEPS_OWNER;
|
|
1022
913
|
}
|
|
1023
914
|
});
|
|
915
|
+
Object.defineProperty(exports, "SET_ACTIVE", {
|
|
916
|
+
enumerable: true,
|
|
917
|
+
get: function() {
|
|
918
|
+
return SET_ACTIVE;
|
|
919
|
+
}
|
|
920
|
+
});
|
|
1024
921
|
Object.defineProperty(exports, "StateContainerRegistry", {
|
|
1025
922
|
enumerable: true,
|
|
1026
923
|
get: function() {
|
|
1027
924
|
return StateContainerRegistry;
|
|
1028
925
|
}
|
|
1029
926
|
});
|
|
927
|
+
Object.defineProperty(exports, "WITH_TRACKED_STATE", {
|
|
928
|
+
enumerable: true,
|
|
929
|
+
get: function() {
|
|
930
|
+
return WITH_TRACKED_STATE;
|
|
931
|
+
}
|
|
932
|
+
});
|
|
1030
933
|
Object.defineProperty(exports, "configureBlac", {
|
|
1031
934
|
enumerable: true,
|
|
1032
935
|
get: function() {
|
|
@@ -1039,16 +942,16 @@ Object.defineProperty(exports, "getBlacConfig", {
|
|
|
1039
942
|
return getBlacConfig;
|
|
1040
943
|
}
|
|
1041
944
|
});
|
|
1042
|
-
Object.defineProperty(exports, "
|
|
945
|
+
Object.defineProperty(exports, "getBlacName", {
|
|
1043
946
|
enumerable: true,
|
|
1044
947
|
get: function() {
|
|
1045
|
-
return
|
|
948
|
+
return getBlacName;
|
|
1046
949
|
}
|
|
1047
950
|
});
|
|
1048
|
-
Object.defineProperty(exports, "
|
|
951
|
+
Object.defineProperty(exports, "getClassEquality", {
|
|
1049
952
|
enumerable: true,
|
|
1050
953
|
get: function() {
|
|
1051
|
-
return
|
|
954
|
+
return getClassEquality;
|
|
1052
955
|
}
|
|
1053
956
|
});
|
|
1054
957
|
Object.defineProperty(exports, "globalRegistry", {
|
|
@@ -1082,4 +985,4 @@ Object.defineProperty(exports, "shallowEqualState", {
|
|
|
1082
985
|
}
|
|
1083
986
|
});
|
|
1084
987
|
|
|
1085
|
-
//# sourceMappingURL=StateContainerRegistry-
|
|
988
|
+
//# sourceMappingURL=StateContainerRegistry-141uHhtF.cjs.map
|