@blac/core 2.0.20 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/StateContainerRegistry-C75QpeaO.cjs +1260 -0
  2. package/dist/StateContainerRegistry-C75QpeaO.cjs.map +1 -0
  3. package/dist/StateContainerRegistry-DL5Ai7wh.js +1153 -0
  4. package/dist/StateContainerRegistry-DL5Ai7wh.js.map +1 -0
  5. package/dist/StateContainerRegistry-DWOzx7Gd.js +1154 -0
  6. package/dist/StateContainerRegistry-DWOzx7Gd.js.map +1 -0
  7. package/dist/StateContainerRegistry-G81GcCRm.cjs +1261 -0
  8. package/dist/StateContainerRegistry-G81GcCRm.cjs.map +1 -0
  9. package/dist/acquire-CE0uq0Dx.cjs +46 -0
  10. package/dist/acquire-CE0uq0Dx.cjs.map +1 -0
  11. package/dist/acquire-CU0u8BMn.js +35 -0
  12. package/dist/acquire-CU0u8BMn.js.map +1 -0
  13. package/dist/acquire-CkgLJ8WL.cjs +46 -0
  14. package/dist/acquire-CkgLJ8WL.cjs.map +1 -0
  15. package/dist/acquire-DTvfYJ0y.js +35 -0
  16. package/dist/acquire-DTvfYJ0y.js.map +1 -0
  17. package/dist/config-C1T6Jw7n.cjs +32 -0
  18. package/dist/config-C1T6Jw7n.cjs.map +1 -0
  19. package/dist/config-D2A8ZYRM.js +16 -0
  20. package/dist/config-D2A8ZYRM.js.map +1 -0
  21. package/dist/config-D34BkraU.cjs +32 -0
  22. package/dist/config-D34BkraU.cjs.map +1 -0
  23. package/dist/config-ZVy_yFZ3.js +16 -0
  24. package/dist/config-ZVy_yFZ3.js.map +1 -0
  25. package/dist/config.d.cts +7 -3
  26. package/dist/config.d.ts +7 -3
  27. package/dist/constants.d.cts +2 -13
  28. package/dist/constants.d.ts +2 -13
  29. package/dist/core/StateContainer.d.ts +21 -0
  30. package/dist/core/StateContainerRegistry.d.ts +48 -5
  31. package/dist/debug.cjs +3 -3
  32. package/dist/debug.js +3 -3
  33. package/dist/decorators/blac.d.ts +2 -0
  34. package/dist/ensure-11-asM1e.js +677 -0
  35. package/dist/ensure-11-asM1e.js.map +1 -0
  36. package/dist/ensure-BEeY5Ab7.js +673 -0
  37. package/dist/ensure-BEeY5Ab7.js.map +1 -0
  38. package/dist/ensure-D3WWWwMo.cjs +714 -0
  39. package/dist/ensure-D3WWWwMo.cjs.map +1 -0
  40. package/dist/ensure-r1C_7K6_.cjs +718 -0
  41. package/dist/ensure-r1C_7K6_.cjs.map +1 -0
  42. package/dist/events.d.cts +42 -0
  43. package/dist/events.d.ts +42 -0
  44. package/dist/index.cjs +60 -6
  45. package/dist/index.cjs.map +1 -1
  46. package/dist/index.d.cts +4 -3
  47. package/dist/index.d.ts +4 -3
  48. package/dist/index.js +56 -8
  49. package/dist/index.js.map +1 -1
  50. package/dist/management-8x1OVMi6.js +38 -0
  51. package/dist/management-8x1OVMi6.js.map +1 -0
  52. package/dist/management-BZgsi29F.js +38 -0
  53. package/dist/management-BZgsi29F.js.map +1 -0
  54. package/dist/management-Dg2SxUb6.cjs +85 -0
  55. package/dist/management-Dg2SxUb6.cjs.map +1 -0
  56. package/dist/management-hkY13log.cjs +85 -0
  57. package/dist/management-hkY13log.cjs.map +1 -0
  58. package/dist/plugins.cjs +1 -1
  59. package/dist/plugins.js +1 -1
  60. package/dist/registry/index.d.ts +1 -1
  61. package/dist/registry/release.d.ts +17 -1
  62. package/dist/testing.cjs +4 -4
  63. package/dist/testing.js +4 -4
  64. package/dist/utils/static-props.d.ts +5 -0
  65. package/dist/utils/structural-key.d.ts +11 -1
  66. package/dist/watch/index.d.ts +1 -0
  67. package/dist/watch/observe.d.ts +13 -0
  68. package/dist/watch-BDiwCPmb.js +108 -0
  69. package/dist/watch-BDiwCPmb.js.map +1 -0
  70. package/dist/watch-BW7gYiDf.js +108 -0
  71. package/dist/watch-BW7gYiDf.js.map +1 -0
  72. package/dist/watch-aoNLQAXp.cjs +119 -0
  73. package/dist/watch-aoNLQAXp.cjs.map +1 -0
  74. package/dist/watch-entry.cjs +1 -1
  75. package/dist/watch-entry.js +1 -1
  76. package/dist/watch-lEco5Tbl.cjs +119 -0
  77. package/dist/watch-lEco5Tbl.cjs.map +1 -0
  78. package/package.json +3 -3
@@ -11,10 +11,6 @@ export declare const BLAC_DEFAULTS: {
11
11
  * Default instance key for shared instances
12
12
  */
13
13
  readonly DEFAULT_INSTANCE_KEY: "default";
14
- /**
15
- * Maximum getter nesting depth (prevents infinite recursion)
16
- */
17
- readonly MAX_GETTER_DEPTH: 10;
18
14
  };
19
15
  /**
20
16
  * Static property names for StateContainer classes
@@ -42,15 +38,8 @@ export declare const BLAC_STATIC_PROPS: {
42
38
  * non-identity fields (e.g., `readonly` flags) while still keying by id.
43
39
  */
44
40
  readonly KEY: "key";
45
- };
46
- /**
47
- * ID generation patterns and constants
48
- */
49
- export declare const BLAC_ID_PATTERNS: {
50
- /**
51
- * Length of generated ID portion (9 characters from base36)
52
- */
53
- readonly ID_LENGTH: 9;
41
+ /** Mark a bloc as always per-mount: `static isolated = true`. */
42
+ readonly ISOLATED: "isolated";
54
43
  };
55
44
  /**
56
45
  * Standard error message prefix
@@ -1,4 +1,5 @@
1
1
  import { StructuralContainer, type DeepPartial, type StructuralContainerOptions } from '@dirtytalk/structural';
2
+ import { type EventToken } from '../events';
2
3
  import type { ExtractArgs, ExtractState, StateContainerConstructor } from '../types/utilities';
3
4
  import { APPLY_DEPS, INIT_CONFIG, ON_DISPOSE, REMOVE_DEPS_OWNER } from './symbols';
4
5
  import { type BlacMeta } from './meta';
@@ -127,6 +128,7 @@ export declare abstract class StateContainer<S extends object = any, Args = void
127
128
  private _emitRateWarned;
128
129
  private readonly _systemEventHandlers;
129
130
  private _dependencies;
131
+ private _depEdges;
130
132
  private _pendingChange;
131
133
  private _bridgeUnsub;
132
134
  private _registry;
@@ -162,6 +164,15 @@ export declare abstract class StateContainer<S extends object = any, Args = void
162
164
  */
163
165
  protected depend<T extends StateContainerConstructor>(Type: T, defaultArgs?: ExtractArgs<T>): DepHandle<T>;
164
166
  constructor(initialState: S, options?: StructuralContainerOptions);
167
+ /**
168
+ * @internal Subscribe the channel bridge that turns flushes into
169
+ * 'stateChanged' system events. Interest is ALL_PATHS so we wake on every
170
+ * flush. Coalesced via `_pendingChange`: if no emit happened (e.g. a no-op
171
+ * patch), the bridge sees null and skips. Lazy: only subscribed while at
172
+ * least one 'stateChanged' handler exists.
173
+ */
174
+ private _subscribeBridge;
175
+ private _hasStateChangedHandlers;
165
176
  /**
166
177
  * Called once after construction with the args passed at acquire time, before the first
167
178
  * state snapshot is read by any consumer. Override to seed args-derived state (via
@@ -204,6 +215,16 @@ export declare abstract class StateContainer<S extends object = any, Args = void
204
215
  private resolveHydration;
205
216
  private rejectHydration;
206
217
  protected onSystemEvent: <E extends SystemEvent>(event: E, handler: SystemEventHandler<S, E>) => (() => void);
218
+ /**
219
+ * Subscribe to a cross-cutting application event for this container's
220
+ * lifetime. The subscription is torn down automatically on `dispose()` — no
221
+ * manual `off` in consumer code (requirements AC3).
222
+ *
223
+ * Uses THIS container's registry (`_registry`, captured at construction), not
224
+ * the ambient one, so a container always listens on the bus of the registry it
225
+ * belongs to.
226
+ */
227
+ protected on: <P>(token: EventToken<P>, handler: (payload: P) => void) => (() => void);
207
228
  private emitSystemEvent;
208
229
  /**
209
230
  * Dev-only soft circuit breaker. Counts real state changes in a rolling 1s
@@ -1,6 +1,6 @@
1
1
  import type { HydrationStatus, StateContainer } from './StateContainer';
2
2
  import { type PluginManager } from '../plugin/PluginManager';
3
- import { InstanceReadonlyState, StateContainerConstructor } from '../types/utilities';
3
+ import { InstanceReadonlyState, StateContainerConstructor, StateContainerInstance } from '../types/utilities';
4
4
  /**
5
5
  * Entry in the instance registry, tracking the instance and its named references
6
6
  * @template T - Instance type
@@ -16,6 +16,13 @@ export interface InstanceEntry<T = any> {
16
16
  argsKey?: string;
17
17
  /** `depend()`-owners currently holding this instance (see `acquire`'s `dependent` option). */
18
18
  dependents?: Set<StateContainer<any, any, any>>;
19
+ /**
20
+ * `$blac.id` this entry is indexed under in `_byId`, captured at index time.
21
+ * Removal always keys off THIS stored id (never a fresh `$blac.id` read),
22
+ * so an id that changes later (e.g. `INIT_CONFIG` running after insertion)
23
+ * can never orphan the index.
24
+ */
25
+ id?: string;
19
26
  }
20
27
  /**
21
28
  * Lifecycle events emitted by the registry
@@ -42,8 +49,15 @@ export type LifecycleListener<E extends LifecycleEvent> = E extends 'created' ?
42
49
  */
43
50
  export declare class StateContainerRegistry {
44
51
  private readonly instancesByConstructor;
52
+ /**
53
+ * Known storage key for each live instance, so disposal can delete its
54
+ * Map entry directly instead of scanning every entry for identity (P3).
55
+ */
56
+ private readonly _keyByInstance;
57
+ /** Id index for O(1) `findEntryById` lookups (P6, used by devtools' `getRefIds`). */
58
+ private readonly _byId;
45
59
  private readonly types;
46
- private readonly registeredTypeNames;
60
+ private _registeredTypes;
47
61
  private readonly listeners;
48
62
  private _stateChangedListenerCount;
49
63
  get hasStateChangedListeners(): boolean;
@@ -52,16 +66,45 @@ export declare class StateContainerRegistry {
52
66
  constructor();
53
67
  /**
54
68
  * Registry-internal reaction to any instance's `disposed` lifecycle event.
55
- * If the disposing container is itself tracked in this registry (i.e. it
56
- * was `acquire()`/`ensure()`'d, not a bare `new`), prune its Map entry and
57
- * release its dependent edges on whatever it `depend()`'d on.
69
+ * Prunes its Map entry, if this registry was tracking it (i.e. it was
70
+ * `acquire()`/`ensure()`'d, not a bare `new`), and always releases its
71
+ * dependent edges on whatever it `depend()`'d on.
58
72
  */
59
73
  private _handleDisposed;
60
74
  /**
61
75
  * Remove the Map entry for `container`, if this registry is tracking it.
76
+ * O(1): looks up the entry's key via `_keyByInstance` instead of scanning
77
+ * every entry for identity. Keeps an identity guard so a recreated entry
78
+ * under the same key (a fresh instance under a reused/derived key) is
79
+ * never deleted by a stale container's disposal.
62
80
  * @returns true if an entry was found and removed
63
81
  */
64
82
  private _pruneEntry;
83
+ /**
84
+ * Single removal point for the `_byId` index (P6). Every path that drops
85
+ * an `InstanceEntry` from the registry MUST route through this so the
86
+ * index can never leak a stale id -> entry mapping.
87
+ */
88
+ private _forgetEntry;
89
+ /**
90
+ * O(1) entry lookup by `$blac.id`, used by `PluginContext.getRefIds`
91
+ * instead of a nested scan over every type x every instance.
92
+ */
93
+ findEntryById(id: string): InstanceEntry | undefined;
94
+ /**
95
+ * Storage key `container` is CURRENTLY indexed under, or `undefined` if this
96
+ * registry never tracked it (bare `new`) or no longer does (disposed/pruned,
97
+ * or its key was taken over by a newer instance). Lets callers that hold only
98
+ * an instance address it without knowing the `args` it was acquired with.
99
+ */
100
+ keyOf(instance: StateContainerInstance): string | undefined;
101
+ /**
102
+ * Drop `Type` from `types` once its instances map is empty, so constructors
103
+ * (and anything keyed on them, e.g. a per-class PathInterner) aren't held
104
+ * alive forever. Deliberate consequence: `getStats()`/`getTypes()` no
105
+ * longer list types with zero live instances.
106
+ */
107
+ private _maybeDropType;
65
108
  /**
66
109
  * Drop `dependent`'s edge on the `Type`/`key` entry (a `depend()`-resolved
67
110
  * instance). When that leaves the entry with no dependents AND no public
package/dist/debug.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_StateContainerRegistry = require("./StateContainerRegistry-CS18y4au.cjs");
3
- const require_config = require("./config-DWUq7zEQ.cjs");
4
- const require_management = require("./management-QWLpbXlW.cjs");
2
+ const require_StateContainerRegistry = require("./StateContainerRegistry-G81GcCRm.cjs");
3
+ const require_config = require("./config-C1T6Jw7n.cjs");
4
+ const require_management = require("./management-hkY13log.cjs");
5
5
  exports.forEach = require_management.forEach;
6
6
  exports.getAll = require_management.getAll;
7
7
  exports.getRefCount = require_management.getRefCount;
package/dist/debug.js CHANGED
@@ -1,4 +1,4 @@
1
- import { r as globalRegistry } from "./StateContainerRegistry-D8nu7Z0T.js";
2
- import { n as getStats, r as setRegistry, t as getRegistry } from "./config-DXI3kzmA.js";
3
- import { a as getAll, c as hasInstance, i as forEach, o as getRefCount, r as register, s as getRefIds } from "./management-C-WGcwPD.js";
1
+ import { r as globalRegistry } from "./StateContainerRegistry-DWOzx7Gd.js";
2
+ import { n as getStats, r as setRegistry, t as getRegistry } from "./config-D2A8ZYRM.js";
3
+ import { a as getAll, c as hasInstance, i as forEach, o as getRefCount, r as register, s as getRefIds } from "./management-8x1OVMi6.js";
4
4
  export { forEach, getAll, getRefCount, getRefIds, getRegistry, getStats, globalRegistry, hasInstance, register, setRegistry };
@@ -15,6 +15,8 @@ export type BlacOptions =
15
15
  /**
16
16
  * Override the global equality check for this bloc.
17
17
  * Return `true` to skip the emit (states considered equal).
18
+ * Applies to `emit`/`update` only — `patch` does not consult this fn; it
19
+ * still skips structural no-ops on its own.
18
20
  */
19
21
  | {
20
22
  equality: EqualityFn;