@blac/core 2.0.22 → 2.1.1

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 (76) hide show
  1. package/dist/StateContainer-BUyuxKb3.cjs +667 -0
  2. package/dist/StateContainer-BUyuxKb3.cjs.map +1 -0
  3. package/dist/StateContainer-B_7UHc3I.js +632 -0
  4. package/dist/StateContainer-B_7UHc3I.js.map +1 -0
  5. package/dist/StateContainer-Bh2ipNYj.js +632 -0
  6. package/dist/StateContainer-Bh2ipNYj.js.map +1 -0
  7. package/dist/StateContainer-ClzwKnQZ.cjs +667 -0
  8. package/dist/StateContainer-ClzwKnQZ.cjs.map +1 -0
  9. package/dist/StateContainer-DiQATvZh.js +632 -0
  10. package/dist/StateContainer-DiQATvZh.js.map +1 -0
  11. package/dist/StateContainer-j16zciex.cjs +667 -0
  12. package/dist/StateContainer-j16zciex.cjs.map +1 -0
  13. package/dist/StateContainerRegistry-BX-DlHXO.js +747 -0
  14. package/dist/StateContainerRegistry-BX-DlHXO.js.map +1 -0
  15. package/dist/StateContainerRegistry-Bf5VuVjm.js +747 -0
  16. package/dist/StateContainerRegistry-Bf5VuVjm.js.map +1 -0
  17. package/dist/StateContainerRegistry-BvSRfhKv.cjs +866 -0
  18. package/dist/StateContainerRegistry-BvSRfhKv.cjs.map +1 -0
  19. package/dist/StateContainerRegistry-C8jxrcqk.cjs +866 -0
  20. package/dist/StateContainerRegistry-C8jxrcqk.cjs.map +1 -0
  21. package/dist/StateContainerRegistry-DjQQtlCW.cjs +870 -0
  22. package/dist/StateContainerRegistry-DjQQtlCW.cjs.map +1 -0
  23. package/dist/StateContainerRegistry-gQbEutkN.js +751 -0
  24. package/dist/StateContainerRegistry-gQbEutkN.js.map +1 -0
  25. package/dist/config.d.cts +10 -6
  26. package/dist/config.d.ts +10 -6
  27. package/dist/constants.d.cts +12 -17
  28. package/dist/constants.d.ts +12 -17
  29. package/dist/core/StateContainer.d.ts +16 -34
  30. package/dist/core/StateContainerRegistry.d.ts +57 -174
  31. package/dist/core/symbols.d.ts +7 -4
  32. package/dist/decorators/blac.d.ts +5 -2
  33. package/dist/ensure-Bi_yXk6f.js +46 -0
  34. package/dist/ensure-Bi_yXk6f.js.map +1 -0
  35. package/dist/ensure-Bx41d-il.cjs +63 -0
  36. package/dist/ensure-Bx41d-il.cjs.map +1 -0
  37. package/dist/ensure-C7UQ_mKM.js +46 -0
  38. package/dist/ensure-C7UQ_mKM.js.map +1 -0
  39. package/dist/ensure-D1D4WjYf.cjs +63 -0
  40. package/dist/ensure-D1D4WjYf.cjs.map +1 -0
  41. package/dist/ensure-DBnuRJ0R.cjs +63 -0
  42. package/dist/ensure-DBnuRJ0R.cjs.map +1 -0
  43. package/dist/ensure-NTB9nnnj.js +46 -0
  44. package/dist/ensure-NTB9nnnj.js.map +1 -0
  45. package/dist/index.cjs +70 -49
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.d.cts +2 -7
  48. package/dist/index.d.ts +2 -7
  49. package/dist/index.js +53 -26
  50. package/dist/index.js.map +1 -1
  51. package/dist/internal.cjs +10 -0
  52. package/dist/internal.d.cts +8 -0
  53. package/dist/internal.d.ts +8 -0
  54. package/dist/internal.js +3 -0
  55. package/dist/plugin/BlacPlugin.d.ts +8 -24
  56. package/dist/plugin/PluginManager.d.ts +41 -64
  57. package/dist/plugins.cjs +67 -87
  58. package/dist/plugins.cjs.map +1 -1
  59. package/dist/plugins.d.cts +7 -6
  60. package/dist/plugins.d.ts +7 -6
  61. package/dist/plugins.js +67 -87
  62. package/dist/plugins.js.map +1 -1
  63. package/dist/registry/config.d.ts +3 -0
  64. package/dist/testing.cjs +37 -35
  65. package/dist/testing.cjs.map +1 -1
  66. package/dist/testing.d.cts +5 -11
  67. package/dist/testing.d.ts +5 -11
  68. package/dist/testing.js +28 -26
  69. package/dist/testing.js.map +1 -1
  70. package/dist/types/branded.d.ts +3 -10
  71. package/dist/types/utilities.d.ts +0 -18
  72. package/dist/utils/idGenerator.d.ts +6 -13
  73. package/dist/utils/static-props.d.ts +9 -35
  74. package/dist/utils/structural-key.d.ts +0 -5
  75. package/dist/watch/watch.d.ts +4 -9
  76. package/package.json +15 -2
@@ -1,23 +1,22 @@
1
1
  import type { HydrationStatus, StateContainer } from './StateContainer';
2
2
  import { InstanceReadonlyState, StateContainerConstructor } from '../types/utilities';
3
+ import { INSERT_INSTANCE } from './symbols';
3
4
  /**
4
- * Entry in the instance registry, tracking the instance and its named references
5
+ * Entry in the instance registry.
5
6
  * @typeParam T - Instance type
6
7
  * @internal
7
8
  */
8
9
  export interface InstanceEntry<T = any> {
9
- /** The state container instance */
10
10
  instance: T;
11
- /** The key this entry is stored under in its constructor's instances Map. */
12
11
  key: string;
13
- /** Map of active reference IDs to their acquire count (supports paired acquire/release) */
12
+ /** refId to acquire count. */
14
13
  refs: Map<string, number>;
15
- /** The args used when this entry was first created; used for dev-warn on arg mismatch. */
14
+ /** Args from creation, for the dev arg-mismatch warning. */
16
15
  args?: unknown;
17
- /** Memoized structuralKey(args) for the dev arg-mismatch warning. */
18
16
  argsKey?: string;
19
- /** `depend()`-owners currently holding this instance (see `acquire`'s `dependent` option). */
17
+ /** `depend()`-owners holding this instance. */
20
18
  dependents?: Set<StateContainer<any, any, any>>;
19
+ sweepTimer?: ReturnType<typeof setTimeout>;
21
20
  }
22
21
  /**
23
22
  * Lifecycle events emitted by the registry
@@ -31,8 +30,8 @@ export type LifecycleEvent = 'created' | 'stateChanged' | 'disposed' | 'refAcqui
31
30
  */
32
31
  export type LifecycleListener<E extends LifecycleEvent> = E extends 'created' ? (container: StateContainer<any, any, any>) => void : E extends 'stateChanged' ? (container: StateContainer<any, any, any>, previousState: Readonly<Record<string, unknown>>, currentState: Readonly<Record<string, unknown>>) => void : E extends 'disposed' ? (container: StateContainer<any, any, any>) => void : E extends 'refAcquired' ? (container: StateContainer<any, any, any>, refId: string) => void : E extends 'refReleased' ? (container: StateContainer<any, any, any>, refId: string) => void : E extends 'depsChanged' ? (container: StateContainer<any, any, any>, previousDeps: Readonly<Record<string, unknown>>, currentDeps: Readonly<Record<string, unknown>>) => void : E extends 'hydrationChanged' ? (container: StateContainer<any, any, any>, status: HydrationStatus, previousStatus: HydrationStatus) => void : E extends 'activated' ? (container: StateContainer<any, any, any>, signal: AbortSignal) => void : E extends 'deactivated' ? (container: StateContainer<any, any, any>) => void : never;
33
32
  /**
34
- * Central registry for managing StateContainer instances.
35
- * Handles instance lifecycle, named ref tracking, and lifecycle event emission.
33
+ * Owns StateContainer instances: creation, ref tracking, disposal and
34
+ * lifecycle events.
36
35
  *
37
36
  * @example
38
37
  * ```ts
@@ -44,89 +43,46 @@ export type LifecycleListener<E extends LifecycleEvent> = E extends 'created' ?
44
43
  * });
45
44
  * ```
46
45
  *
47
- * `stateChanged` fires once per emit (microtask-deferred but uncoalesced), so
48
- * listeners see every intermediate transition. Plugins' `onStateChange` fires
49
- * once per channel flush with coalesced `prev`/`next` and a `PathSet`. Pick
50
- * the transition log for devtools/time-travel, the plugin hook for
51
- * change-driven work.
46
+ * `stateChanged` fires once per emit (microtask-deferred, not coalesced).
47
+ * Plugins' `onStateChange` fires once per channel flush with coalesced
48
+ * `prev`/`next` and a `PathSet`.
52
49
  */
53
50
  export declare class StateContainerRegistry {
54
51
  private readonly instancesByConstructor;
55
52
  private readonly types;
56
53
  /**
57
- * `depend()`-owner to the (Type, key) entries it has resolved. Keyed per
58
- * resolved key because one handle resolves a different key per `args`.
59
- * Weak so a bare `new`'d owner that is never disposed cannot pin the map.
54
+ * `depend()`-owner to the (Type, key) entries it resolved, per key because
55
+ * one handle resolves a different key per `args`.
60
56
  */
61
57
  private readonly _dependentEdges;
58
+ private readonly _entryByInstance;
62
59
  /**
63
- * Reverse lookup from `$blac.id` to its entry, for `PluginContext.getRefIds`
64
- * and the O(1) prune on dispose. Ids are `<name>:<key>`, so an entry is
65
- * matched by instance identity as well.
60
+ * Only for `PluginContext.getRefIds`: ids can collide across same-named
61
+ * classes, so nothing else may rely on it.
66
62
  */
67
63
  private readonly _entryById;
68
64
  private readonly listeners;
69
- /**
70
- * Derived from the listener Set, never a parallel counter: `on()` with the
71
- * same function twice adds once, so a counter cannot stay in step.
72
- */
73
65
  get hasStateChangedListeners(): boolean;
74
66
  private _pendingStateChanges;
75
67
  private _autoRefIdCounter;
76
68
  constructor();
77
- /**
78
- * Registry-internal reaction to any instance's `disposed` lifecycle event.
79
- * If the disposing container is itself tracked in this registry (i.e. it
80
- * was `acquire()`/`ensure()`'d, not a bare `new`), prune its Map entry and
81
- * release its dependent edges on whatever it `depend()`'d on.
82
- */
69
+ /** Prune a tracked instance's entry and release its `depend()` edges. */
83
70
  private _handleDisposed;
84
- /**
85
- * An entry may be disposed only when nothing owns it: no public refs, no
86
- * `depend()` dependents, and not keepAlive. Every dispose decision goes
87
- * through here so `release()` and `_releaseDependent` cannot disagree.
88
- */
71
+ /** The single dispose decision: no refs, no dependents, not keepAlive. */
89
72
  private _isUnowned;
90
- /**
91
- * Pure ownership: refs plus `depend()` dependents, with no keepAlive term.
92
- * `_isUnowned` is "may be disposed"; this is "nothing is using it", which is
93
- * what the activation lifecycle keys off — a keepAlive instance still
94
- * deactivates when its last owner goes.
95
- */
73
+ /** Ignores keepAlive: a keepAlive instance still deactivates. */
96
74
  private _hasNoOwners;
97
75
  /**
98
- * Single funnel for the 0↔1 ownership transition. `SET_ACTIVE` is idempotent,
99
- * so every acquire/release path can call this unconditionally rather than
100
- * each computing the edge itself. Emits `activated`/`deactivated` for
101
- * plugins to observe the same transition `onActivate`/`onDeactivate` expose
102
- * to bloc authors — after `SET_ACTIVE` has already run the instance's own
103
- * hook, so plugins always see a container that has finished reacting.
76
+ * Idempotent, so every acquire/release path calls it. The events fire after
77
+ * the instance's own `onActivate`/`onDeactivate`.
104
78
  */
105
79
  private _syncActivation;
106
- /**
107
- * Record that `dependent` resolved `Type` at `key`, so the edge can be
108
- * released on the owner's disposal. Keyed per resolved key, not per type:
109
- * one `depend()` handle resolves a distinct key for every `args` it is
110
- * called with, and all of them must be swept.
111
- */
112
80
  private _recordDependentEdge;
113
- /**
114
- * Remove the Map entry for `container`, if this registry is tracking it.
115
- * @returns true if an entry was found and removed
116
- */
81
+ /** @returns true if this registry tracked `container`. */
117
82
  private _pruneEntry;
118
- /**
119
- * Drop `dependent`'s edge on the `Type`/`key` entry (a `depend()`-resolved
120
- * instance). When that leaves the entry with no dependents AND no public
121
- * refs AND it isn't keepAlive, dispose it — this recurses into the same
122
- * `disposed` listener, so dep-of-dep chains unwind naturally.
123
- */
83
+ private _indexEntry;
84
+ /** Disposing here recurses through `disposed`, unwinding dep chains. */
124
85
  private _releaseDependent;
125
- /**
126
- * Register a type for lifecycle event tracking
127
- * @param constructor - The StateContainer class constructor
128
- */
129
- registerType<T extends StateContainerConstructor>(constructor: T): void;
130
86
  /**
131
87
  * Register a StateContainer class with configuration
132
88
  * @param constructor - The StateContainer class constructor
@@ -139,60 +95,35 @@ export declare class StateContainerRegistry {
139
95
  */
140
96
  getInstancesMap<T extends StateContainerConstructor>(Type: T): ReadonlyMap<string, InstanceEntry>;
141
97
  /**
142
- * Directly insert an instance entry into the registry without going through
143
- * acquire/release. Creates the internal WeakMap bucket for the constructor if
144
- * it does not exist yet. Replaces any existing entry for the same key.
145
- *
146
- * The provided instance is NOT configured or disposed here — callers are
147
- * responsible for any initConfig / dispose calls. Intended for testing
148
- * helpers that create stubs outside the normal acquisition path.
98
+ * Insert an entry, replacing the one at `instanceKey`. The instance is not
99
+ * configured here.
149
100
  *
150
101
  * @internal Used by testing helpers only.
151
102
  */
152
- insertInstance<T extends StateContainerConstructor>(Type: T, instanceKey: string, instance: InstanceType<T>, refs?: Map<string, number>): void;
103
+ [INSERT_INSTANCE]<T extends StateContainerConstructor>(Type: T, instanceKey: string, instance: InstanceType<T>, refs?: Map<string, number>): void;
153
104
  /**
154
- * Resolve the storage key for an instance. This is the single source of truth
155
- * for keying — `acquire` and `release` MUST agree, otherwise a ref taken under
156
- * an args-derived key is never dropped (instance leaks).
157
- *
158
- * Resolution order (explicit beats derived):
159
- * explicit key \> `static key(args)` \> structural hash of args \> default sentinel.
105
+ * The single source of keying, so `acquire` and `release` agree: explicit
106
+ * key \> `static key(args)` \> structural hash of args \> default key.
160
107
  *
161
108
  * @param Type - The StateContainer class constructor
162
109
  * @param instanceKey - Explicit key, or undefined to derive from args
163
110
  * @param args - Construction args used for structural/`static key` derivation
164
111
  */
165
112
  resolveKey<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey: string | undefined, args: unknown): string;
166
- /**
167
- * Circuit breaker for runaway instance creation. Throws when a single
168
- * constructor would exceed `maxInstancesPerType` live instances — almost
169
- * always an unstable instance key (e.g. a new object/array passed as `args`
170
- * every render, or a missing `static key`) leaking an instance per render.
171
- */
172
113
  private assertInstanceLimit;
173
- /**
174
- * Circuit breaker for runaway reference growth. Throws when one instance
175
- * accumulates more than `maxRefsPerInstance` distinct live refs — almost
176
- * always consumer cleanup (e.g. `useBloc`'s unmount `release`) never firing.
177
- */
178
114
  private assertRefLimit;
179
115
  /**
180
- * Acquire an instance with ref tracking (ownership semantics).
181
- * Creates a new instance if one doesn't exist, or returns existing and adds a ref.
182
- * You must call `release()` with the same refId when done.
116
+ * Get or create an instance and add a ref; `release()` it with the same
117
+ * refId.
183
118
  *
184
119
  * @internal Internal key tier. Public callers use the args-based `acquire`
185
120
  * wrapper; `useBloc` and `watch` address a pre-resolved key here.
186
121
  * @param Type - The StateContainer class constructor
187
122
  * @param instanceKey - Pre-resolved instance key (defaults to 'default')
188
- * @param options - Acquisition options: `canCreate` (create when absent,
189
- * default true), `countRef` (add a reference, default true), `refId`
190
- * (named reference for debugging, auto-generated when omitted),
191
- * `dependent` — the `depend()`-owner resolving this instance, recorded so
192
- * its dependent edge is released on the owner's disposal — and
193
- * `sweepIfUnowned`, for callers that create speculatively and claim
194
- * ownership later (see {@link _scheduleSweep}).
195
- * @returns The state container instance
123
+ * @param options - `canCreate` and `countRef` default to true; `refId` is
124
+ * auto-generated when omitted; `dependent` is the `depend()`-owner, whose
125
+ * edge is released on its disposal; `sweepIfUnowned` is for speculative
126
+ * creates (see `_scheduleSweep`).
196
127
  */
197
128
  acquire<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string, options?: {
198
129
  canCreate?: boolean;
@@ -203,19 +134,14 @@ export declare class StateContainerRegistry {
203
134
  sweepIfUnowned?: boolean;
204
135
  }): InstanceType<T>;
205
136
  /**
206
- * Speculative creates (`useBloc`'s render-time create) leak forever when the
207
- * render is discarded or never commits — SSR has no commit at all, so nothing
208
- * ever claims ownership. Sweep at the end of the microtask unless the entry
209
- * gained an owner or is keepAlive.
210
- *
211
- * Opt-in, not automatic: a bare `ensure()` hands the instance to a caller
212
- * that legitimately holds it without a ref, and sweeping those would make
213
- * `ensure` unusable across an `await`.
137
+ * Dispose a speculative create (a render that never commits, SSR) that is
138
+ * still unowned after `unownedSweepDelayMs`. The delay must outlast a
139
+ * time-sliced render; a repeat speculative acquire restarts it. Opt-in, so a
140
+ * bare `ensure()` stays usable across an `await`.
214
141
  */
215
142
  private _scheduleSweep;
216
143
  /**
217
- * Borrow an existing instance without adding a ref (borrowing semantics).
218
- * Tracks cross-bloc dependency for reactive updates.
144
+ * Get an existing instance without adding a ref.
219
145
  *
220
146
  * @internal Internal key tier; public callers use the args-based `borrow`.
221
147
  * @param Type - The StateContainer class constructor
@@ -225,8 +151,7 @@ export declare class StateContainerRegistry {
225
151
  */
226
152
  borrow<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): InstanceType<T>;
227
153
  /**
228
- * Safely borrow an existing instance (borrowing semantics with error handling).
229
- * Returns discriminated union for type-safe conditional access.
154
+ * Like `borrow`, but returns the error instead of throwing.
230
155
  *
231
156
  * @internal Internal key tier; public callers use the args-based `borrowSafe`.
232
157
  * @param Type - The StateContainer class constructor
@@ -241,12 +166,7 @@ export declare class StateContainerRegistry {
241
166
  instance: InstanceType<T>;
242
167
  };
243
168
  /**
244
- * Ensure an instance exists without taking ownership (for bloc-to-bloc communication).
245
- * Gets existing instance OR creates it if it doesn't exist, without adding a ref.
246
- * Tracks cross-bloc dependency for reactive updates.
247
- *
248
- * Use this in bloc-to-bloc communication when you need to ensure an instance exists
249
- * but don't want to claim ownership (no ref added).
169
+ * Get or create an instance without adding a ref.
250
170
  *
251
171
  * @internal Internal key tier; public callers use the args-based `ensure`.
252
172
  * @param Type - The StateContainer class constructor
@@ -257,9 +177,8 @@ export declare class StateContainerRegistry {
257
177
  */
258
178
  ensure<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string, args?: unknown): InstanceType<T>;
259
179
  /**
260
- * Release a reference to an instance.
261
- * Removes the ref and disposes when refs is empty (unless keepAlive).
262
- * Releasing an already-removed refId is a no-op (idempotent).
180
+ * Remove a ref and dispose the instance once nothing owns it. Releasing a
181
+ * ref that isn't held is a no-op.
263
182
  *
264
183
  * @internal Internal key tier; public callers use the args-based `release`.
265
184
  * @param Type - The StateContainer class constructor
@@ -268,23 +187,11 @@ export declare class StateContainerRegistry {
268
187
  * @param refId - The specific ref to remove; removes one arbitrary ref if omitted
269
188
  */
270
189
  release<T extends StateContainerConstructor>(Type: T, instanceKey?: string, forceDispose?: boolean, refId?: string): void;
271
- /**
272
- * Get all instances of a specific type.
273
- * @param Type - The StateContainer class constructor
274
- * @returns Array of all instances
275
- */
190
+ /** Live instances of `Type`. */
276
191
  getAll<T extends StateContainerConstructor>(Type: T): InstanceReadonlyState<T>[];
277
- /**
278
- * Safely iterate over all instances of a type.
279
- * Skips disposed instances and catches callback errors.
280
- * @param Type - The StateContainer class constructor
281
- * @param callback - Function to call for each instance
282
- */
192
+ /** Iterate live instances of `Type`; callback errors are logged. */
283
193
  forEach<T extends StateContainerConstructor>(Type: T, callback: (instance: InstanceReadonlyState<T>) => void): void;
284
- /**
285
- * Clear all instances of a specific type (disposes them).
286
- * @param Type - The StateContainer class constructor
287
- */
194
+ /** Dispose all instances of `Type`. */
288
195
  clear<T extends StateContainerConstructor>(Type: T): void;
289
196
  /**
290
197
  * Get reference count for an instance (number of active refs).
@@ -304,12 +211,7 @@ export declare class StateContainerRegistry {
304
211
  * @returns Array of ref ID strings (empty if instance doesn't exist)
305
212
  */
306
213
  getRefIds<T extends StateContainerConstructor>(Type: T, instanceKey?: string): string[];
307
- /**
308
- * Get all active reference IDs for an instance by its `$blac.id`, without
309
- * needing the owning Type. Used by `PluginContext.getRefIds`.
310
- * @param instanceId - The instance's `$blac.id`
311
- * @returns Array of ref ID strings (empty if instance doesn't exist)
312
- */
214
+ /** Ref ids by `$blac.id`, for `PluginContext.getRefIds`. */
313
215
  getRefIdsById(instanceId: string): string[];
314
216
  /**
315
217
  * Check if an instance exists.
@@ -317,34 +219,21 @@ export declare class StateContainerRegistry {
317
219
  * @internal Internal key tier; public callers use the args-based `hasInstance`.
318
220
  * @param Type - The StateContainer class constructor
319
221
  * @param instanceKey - Pre-resolved instance key (defaults to 'default')
320
- * @returns true if instance exists
222
+ * @returns true if a live (not disposed) instance exists
321
223
  */
322
224
  hasInstance<T extends StateContainerConstructor>(Type: T, instanceKey?: string): boolean;
323
- /**
324
- * Clear all instances from all types (for testing)
325
- *
326
- * Iterates all registered types and clears their instances.
327
- * Also clears type tracking to reset the registry state.
328
- */
225
+ /** Dispose every instance and forget all types (for testing). */
329
226
  clearAll(): void;
330
- /**
331
- * Get registry statistics for debugging.
332
- * @returns Object with registeredTypes, totalInstances, and typeBreakdown
333
- */
227
+ /** Instance counts, for debugging. */
334
228
  getStats(): {
335
229
  registeredTypes: number;
336
230
  totalInstances: number;
337
231
  typeBreakdown: Record<string, number>;
338
232
  };
339
- /**
340
- * Get all registered types (for plugin system).
341
- * @returns Array of all registered StateContainer class constructors
342
- */
233
+ /** All registered types (for plugins). */
343
234
  getTypes(): StateContainerConstructor[];
344
235
  /**
345
- * Subscribe to lifecycle events
346
- * @param event - The lifecycle event to listen for
347
- * @param listener - The listener function to call when the event occurs
236
+ * Subscribe to a lifecycle event.
348
237
  * @returns Unsubscribe function
349
238
  */
350
239
  on<E extends LifecycleEvent>(event: E, listener: LifecycleListener<E>): () => void;
@@ -362,24 +251,18 @@ export declare class StateContainerRegistry {
362
251
  emit(event: 'activated', container: StateContainer<any, any, any>, signal: AbortSignal): void;
363
252
  emit(event: 'deactivated', container: StateContainer<any, any, any>): void;
364
253
  /**
365
- * Schedule a deferred stateChanged notification via microtask.
366
- * Skips entirely when no stateChanged listeners are registered.
254
+ * Queue a microtask-deferred `stateChanged`.
367
255
  * @internal - Called by StateContainer.applyState
368
256
  */
369
257
  notifyStateChanged(container: StateContainer<any, any, any>, previousState: any, newState: any): void;
370
258
  /**
371
- * Deliver one event per emit, in order — deliberately NOT coalesced.
372
- *
373
- * This is a transition log: devtools, time-travel debugging and perf
374
- * monitoring need every intermediate `prev`/`next`, which coalescing would
375
- * destroy. The plugin `onStateChange` bridge is the coalesced, `PathSet`-
376
- * carrying lane (see `PluginManager.setupLifecycleHooks`); the two differ on
377
- * purpose, so a listener picks the lane that matches what it needs.
259
+ * One event per emit, deliberately not coalesced: devtools and time-travel
260
+ * need every intermediate transition. Plugins get the coalesced lane.
378
261
  */
379
262
  private flushStateChanged;
380
263
  }
381
264
  /**
382
- * Global default registry instance
265
+ * The global default registry.
383
266
  * @public
384
267
  */
385
268
  export declare const globalRegistry: StateContainerRegistry;
@@ -27,10 +27,8 @@ export declare const INIT_CONFIG: unique symbol;
27
27
  /**
28
28
  * @internal Run `fn` with `state` temporarily reporting a render's tracking
29
29
  * proxy, so getters record the paths they read. Called by `@blac/react`'s
30
- * `buildTrackedProxy` — not public API.
31
- *
32
- * Replaces the old `this`-Proxy receiver: getters now run with `this` bound to
33
- * the real instance, so ES `#private` works in user blocs.
30
+ * `buildTrackedProxy` — not public API. Getters run with `this` bound to the
31
+ * real instance, so ES `#private` works in user blocs.
34
32
  */
35
33
  export declare const WITH_TRACKED_STATE: unique symbol;
36
34
  /**
@@ -41,3 +39,8 @@ export declare const WITH_TRACKED_STATE: unique symbol;
41
39
  * Framework-only — `StateContainerRegistry` is the sole caller.
42
40
  */
43
41
  export declare const SET_ACTIVE: unique symbol;
42
+ /**
43
+ * @internal Insert an instance entry directly, bypassing acquire/release.
44
+ * Called by the testing helpers — not public API.
45
+ */
46
+ export declare const INSERT_INSTANCE: unique symbol;
@@ -4,8 +4,11 @@ import type { EqualityFn } from '../config';
4
4
  * given at once.
5
5
  */
6
6
  export interface BlacOptions {
7
- /** Mark bloc to never be auto-disposed when ref count reaches 0 */
8
- keepAlive?: true;
7
+ /**
8
+ * Keep the bloc alive when its ref count reaches 0. `false` turns off a
9
+ * `keepAlive` inherited from a base class.
10
+ */
11
+ keepAlive?: boolean;
9
12
  /** Exclude bloc from DevTools tracking (prevents infinite loops) */
10
13
  excludeFromDevTools?: true;
11
14
  /**
@@ -0,0 +1,46 @@
1
+ import { i as getRegistry } from "./StateContainer-Bh2ipNYj.js";
2
+ //#region src/registry/acquire.ts
3
+ /**
4
+ * Acquire an instance with ref tracking (ownership semantics). Instance
5
+ * identity is derived purely from `args` (via the class's `static key(args)`,
6
+ * a structural hash of `args`, or the default sentinel when there are none).
7
+ *
8
+ * @param BlocClass - The StateContainer class constructor
9
+ * @param opts - `args` derives the instance key; `refId` names the reference
10
+ * for debugging and is auto-generated when omitted.
11
+ */
12
+ function acquire(BlocClass, opts) {
13
+ const registry = getRegistry();
14
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
15
+ return registry.acquire(BlocClass, key, {
16
+ canCreate: true,
17
+ countRef: true,
18
+ refId: opts?.refId,
19
+ args: opts?.args
20
+ });
21
+ }
22
+ /**
23
+ * Resolve the storage key an instance would be acquired under, given its
24
+ * construction `args`. This is the canonical key-computation path. Callers that
25
+ * both acquire and release against the `@internal` registry tier (e.g.
26
+ * `@blac/react` `useBloc`) must use this once and pass the same resolved key to
27
+ * both, so the ref is dropped under the key it was taken.
28
+ */
29
+ function resolveInstanceKey(BlocClass, args) {
30
+ return getRegistry().resolveKey(BlocClass, void 0, args);
31
+ }
32
+ //#endregion
33
+ //#region src/registry/ensure.ts
34
+ /**
35
+ * Ensure an instance exists without taking ownership (no ref added). Instance
36
+ * identity is derived purely from `args`, matching `acquire`.
37
+ */
38
+ function ensure(BlocClass, opts) {
39
+ const registry = getRegistry();
40
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
41
+ return registry.ensure(BlocClass, key, opts?.args);
42
+ }
43
+ //#endregion
44
+ export { acquire as n, resolveInstanceKey as r, ensure as t };
45
+
46
+ //# sourceMappingURL=ensure-Bi_yXk6f.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-Bi_yXk6f.js","names":[],"sources":["../src/registry/acquire.ts","../src/registry/ensure.ts"],"sourcesContent":["import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Acquire an instance with ref tracking (ownership semantics). Instance\n * identity is derived purely from `args` (via the class's `static key(args)`,\n * a structural hash of `args`, or the default sentinel when there are none).\n *\n * @param BlocClass - The StateContainer class constructor\n * @param opts - `args` derives the instance key; `refId` names the reference\n * for debugging and is auto-generated when omitted.\n */\nexport function acquire<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.acquire(BlocClass, key, {\n canCreate: true,\n countRef: true,\n refId: opts?.refId,\n args: opts?.args,\n });\n}\n\n/**\n * Resolve the storage key an instance would be acquired under, given its\n * construction `args`. This is the canonical key-computation path. Callers that\n * both acquire and release against the `@internal` registry tier (e.g.\n * `@blac/react` `useBloc`) must use this once and pass the same resolved key to\n * both, so the ref is dropped under the key it was taken.\n */\nexport function resolveInstanceKey<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, args);\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Ensure an instance exists without taking ownership (no ref added). Instance\n * identity is derived purely from `args`, matching `acquire`.\n */\nexport function ensure<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.ensure(BlocClass, key, opts?.args);\n}\n"],"mappings":";;;;;;;;;;;AAeA,SAAgB,QACd,WACA,MACiB;CACjB,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,QAAQ,WAAW,KAAK;EACtC,WAAW;EACX,UAAU;EACV,OAAO,MAAM;EACb,MAAM,MAAM;CACd,CAAC;AACH;;;;;;;;AASA,SAAgB,mBACd,WACA,MACQ;CACR,OAAO,YAAY,EAAE,WAAW,WAAW,KAAA,GAAW,IAAI;AAC5D;;;;;;;AC/BA,SAAgB,OACd,WACA,MACiB;CACjB,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,OAAO,WAAW,KAAK,MAAM,IAAI;AACnD"}
@@ -0,0 +1,63 @@
1
+ const require_StateContainer = require("./StateContainer-ClzwKnQZ.cjs");
2
+ //#region src/registry/acquire.ts
3
+ /**
4
+ * Acquire an instance with ref tracking (ownership semantics). Instance
5
+ * identity is derived purely from `args` (via the class's `static key(args)`,
6
+ * a structural hash of `args`, or the default sentinel when there are none).
7
+ *
8
+ * @param BlocClass - The StateContainer class constructor
9
+ * @param opts - `args` derives the instance key; `refId` names the reference
10
+ * for debugging and is auto-generated when omitted.
11
+ */
12
+ function acquire(BlocClass, opts) {
13
+ const registry = require_StateContainer.getRegistry();
14
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
15
+ return registry.acquire(BlocClass, key, {
16
+ canCreate: true,
17
+ countRef: true,
18
+ refId: opts?.refId,
19
+ args: opts?.args
20
+ });
21
+ }
22
+ /**
23
+ * Resolve the storage key an instance would be acquired under, given its
24
+ * construction `args`. This is the canonical key-computation path. Callers that
25
+ * both acquire and release against the `@internal` registry tier (e.g.
26
+ * `@blac/react` `useBloc`) must use this once and pass the same resolved key to
27
+ * both, so the ref is dropped under the key it was taken.
28
+ */
29
+ function resolveInstanceKey(BlocClass, args) {
30
+ return require_StateContainer.getRegistry().resolveKey(BlocClass, void 0, args);
31
+ }
32
+ //#endregion
33
+ //#region src/registry/ensure.ts
34
+ /**
35
+ * Ensure an instance exists without taking ownership (no ref added). Instance
36
+ * identity is derived purely from `args`, matching `acquire`.
37
+ */
38
+ function ensure(BlocClass, opts) {
39
+ const registry = require_StateContainer.getRegistry();
40
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
41
+ return registry.ensure(BlocClass, key, opts?.args);
42
+ }
43
+ //#endregion
44
+ Object.defineProperty(exports, "acquire", {
45
+ enumerable: true,
46
+ get: function() {
47
+ return acquire;
48
+ }
49
+ });
50
+ Object.defineProperty(exports, "ensure", {
51
+ enumerable: true,
52
+ get: function() {
53
+ return ensure;
54
+ }
55
+ });
56
+ Object.defineProperty(exports, "resolveInstanceKey", {
57
+ enumerable: true,
58
+ get: function() {
59
+ return resolveInstanceKey;
60
+ }
61
+ });
62
+
63
+ //# sourceMappingURL=ensure-Bx41d-il.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-Bx41d-il.cjs","names":["getRegistry","getRegistry"],"sources":["../src/registry/acquire.ts","../src/registry/ensure.ts"],"sourcesContent":["import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Acquire an instance with ref tracking (ownership semantics). Instance\n * identity is derived purely from `args` (via the class's `static key(args)`,\n * a structural hash of `args`, or the default sentinel when there are none).\n *\n * @param BlocClass - The StateContainer class constructor\n * @param opts - `args` derives the instance key; `refId` names the reference\n * for debugging and is auto-generated when omitted.\n */\nexport function acquire<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.acquire(BlocClass, key, {\n canCreate: true,\n countRef: true,\n refId: opts?.refId,\n args: opts?.args,\n });\n}\n\n/**\n * Resolve the storage key an instance would be acquired under, given its\n * construction `args`. This is the canonical key-computation path. Callers that\n * both acquire and release against the `@internal` registry tier (e.g.\n * `@blac/react` `useBloc`) must use this once and pass the same resolved key to\n * both, so the ref is dropped under the key it was taken.\n */\nexport function resolveInstanceKey<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, args);\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Ensure an instance exists without taking ownership (no ref added). Instance\n * identity is derived purely from `args`, matching `acquire`.\n */\nexport function ensure<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.ensure(BlocClass, key, opts?.args);\n}\n"],"mappings":";;;;;;;;;;;AAeA,SAAgB,QACd,WACA,MACiB;CACjB,MAAM,WAAWA,uBAAAA,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,QAAQ,WAAW,KAAK;EACtC,WAAW;EACX,UAAU;EACV,OAAO,MAAM;EACb,MAAM,MAAM;CACd,CAAC;AACH;;;;;;;;AASA,SAAgB,mBACd,WACA,MACQ;CACR,OAAOA,uBAAAA,YAAY,EAAE,WAAW,WAAW,KAAA,GAAW,IAAI;AAC5D;;;;;;;AC/BA,SAAgB,OACd,WACA,MACiB;CACjB,MAAM,WAAWC,uBAAAA,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,OAAO,WAAW,KAAK,MAAM,IAAI;AACnD"}
@@ -0,0 +1,46 @@
1
+ import { i as getRegistry } from "./StateContainer-B_7UHc3I.js";
2
+ //#region src/registry/acquire.ts
3
+ /**
4
+ * Acquire an instance with ref tracking (ownership semantics). Instance
5
+ * identity is derived purely from `args` (via the class's `static key(args)`,
6
+ * a structural hash of `args`, or the default sentinel when there are none).
7
+ *
8
+ * @param BlocClass - The StateContainer class constructor
9
+ * @param opts - `args` derives the instance key; `refId` names the reference
10
+ * for debugging and is auto-generated when omitted.
11
+ */
12
+ function acquire(BlocClass, opts) {
13
+ const registry = getRegistry();
14
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
15
+ return registry.acquire(BlocClass, key, {
16
+ canCreate: true,
17
+ countRef: true,
18
+ refId: opts?.refId,
19
+ args: opts?.args
20
+ });
21
+ }
22
+ /**
23
+ * Resolve the storage key an instance would be acquired under, given its
24
+ * construction `args`. This is the canonical key-computation path. Callers that
25
+ * both acquire and release against the `@internal` registry tier (e.g.
26
+ * `@blac/react` `useBloc`) must use this once and pass the same resolved key to
27
+ * both, so the ref is dropped under the key it was taken.
28
+ */
29
+ function resolveInstanceKey(BlocClass, args) {
30
+ return getRegistry().resolveKey(BlocClass, void 0, args);
31
+ }
32
+ //#endregion
33
+ //#region src/registry/ensure.ts
34
+ /**
35
+ * Ensure an instance exists without taking ownership (no ref added). Instance
36
+ * identity is derived purely from `args`, matching `acquire`.
37
+ */
38
+ function ensure(BlocClass, opts) {
39
+ const registry = getRegistry();
40
+ const key = registry.resolveKey(BlocClass, void 0, opts?.args);
41
+ return registry.ensure(BlocClass, key, opts?.args);
42
+ }
43
+ //#endregion
44
+ export { acquire as n, resolveInstanceKey as r, ensure as t };
45
+
46
+ //# sourceMappingURL=ensure-C7UQ_mKM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-C7UQ_mKM.js","names":[],"sources":["../src/registry/acquire.ts","../src/registry/ensure.ts"],"sourcesContent":["import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Acquire an instance with ref tracking (ownership semantics). Instance\n * identity is derived purely from `args` (via the class's `static key(args)`,\n * a structural hash of `args`, or the default sentinel when there are none).\n *\n * @param BlocClass - The StateContainer class constructor\n * @param opts - `args` derives the instance key; `refId` names the reference\n * for debugging and is auto-generated when omitted.\n */\nexport function acquire<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.acquire(BlocClass, key, {\n canCreate: true,\n countRef: true,\n refId: opts?.refId,\n args: opts?.args,\n });\n}\n\n/**\n * Resolve the storage key an instance would be acquired under, given its\n * construction `args`. This is the canonical key-computation path. Callers that\n * both acquire and release against the `@internal` registry tier (e.g.\n * `@blac/react` `useBloc`) must use this once and pass the same resolved key to\n * both, so the ref is dropped under the key it was taken.\n */\nexport function resolveInstanceKey<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, args);\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Ensure an instance exists without taking ownership (no ref added). Instance\n * identity is derived purely from `args`, matching `acquire`.\n */\nexport function ensure<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.ensure(BlocClass, key, opts?.args);\n}\n"],"mappings":";;;;;;;;;;;AAeA,SAAgB,QACd,WACA,MACiB;CACjB,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,QAAQ,WAAW,KAAK;EACtC,WAAW;EACX,UAAU;EACV,OAAO,MAAM;EACb,MAAM,MAAM;CACd,CAAC;AACH;;;;;;;;AASA,SAAgB,mBACd,WACA,MACQ;CACR,OAAO,YAAY,EAAE,WAAW,WAAW,KAAA,GAAW,IAAI;AAC5D;;;;;;;AC/BA,SAAgB,OACd,WACA,MACiB;CACjB,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,OAAO,WAAW,KAAK,MAAM,IAAI;AACnD"}