@blac/core 2.0.0-rc.15 → 2.0.0-rc.17
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/dist/index.cjs +1168 -321
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +777 -263
- package/dist/index.d.ts +777 -263
- package/dist/index.js +1109 -300
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -196,17 +196,17 @@ var PluginManager = class {
|
|
|
196
196
|
* Setup lifecycle hooks to notify plugins
|
|
197
197
|
*/
|
|
198
198
|
setupLifecycleHooks() {
|
|
199
|
-
this.registry.on("created", (instance) => {
|
|
200
|
-
this.notifyPlugins("onInstanceCreated", instance);
|
|
199
|
+
this.registry.on("created", (instance$1) => {
|
|
200
|
+
this.notifyPlugins("onInstanceCreated", instance$1);
|
|
201
201
|
});
|
|
202
|
-
this.registry.on("stateChanged", (instance, previousState, currentState, callstack) => {
|
|
203
|
-
this.notifyPlugins("onStateChanged", instance, previousState, currentState, callstack);
|
|
202
|
+
this.registry.on("stateChanged", (instance$1, previousState, currentState, callstack) => {
|
|
203
|
+
this.notifyPlugins("onStateChanged", instance$1, previousState, currentState, callstack);
|
|
204
204
|
});
|
|
205
205
|
this.registry.on("eventAdded", (vertex, event) => {
|
|
206
206
|
this.notifyPlugins("onEventAdded", vertex, event);
|
|
207
207
|
});
|
|
208
|
-
this.registry.on("disposed", (instance) => {
|
|
209
|
-
this.notifyPlugins("onInstanceDisposed", instance);
|
|
208
|
+
this.registry.on("disposed", (instance$1) => {
|
|
209
|
+
this.notifyPlugins("onInstanceDisposed", instance$1);
|
|
210
210
|
});
|
|
211
211
|
}
|
|
212
212
|
/**
|
|
@@ -228,23 +228,23 @@ var PluginManager = class {
|
|
|
228
228
|
*/
|
|
229
229
|
createPluginContext() {
|
|
230
230
|
return {
|
|
231
|
-
getInstanceMetadata: (instance) => {
|
|
231
|
+
getInstanceMetadata: (instance$1) => {
|
|
232
232
|
return {
|
|
233
|
-
id: instance.instanceId,
|
|
234
|
-
className: instance.constructor.name,
|
|
235
|
-
isDisposed: instance.isDisposed,
|
|
236
|
-
name: instance.name,
|
|
237
|
-
lastStateChangeTimestamp: instance.lastUpdateTimestamp,
|
|
238
|
-
createdAt: instance.createdAt,
|
|
239
|
-
state: instance.state,
|
|
240
|
-
isIsolated: instance.instanceId.startsWith("isolated-")
|
|
233
|
+
id: instance$1.instanceId,
|
|
234
|
+
className: instance$1.constructor.name,
|
|
235
|
+
isDisposed: instance$1.isDisposed,
|
|
236
|
+
name: instance$1.name,
|
|
237
|
+
lastStateChangeTimestamp: instance$1.lastUpdateTimestamp,
|
|
238
|
+
createdAt: instance$1.createdAt,
|
|
239
|
+
state: instance$1.state,
|
|
240
|
+
isIsolated: instance$1.instanceId.startsWith("isolated-")
|
|
241
241
|
};
|
|
242
242
|
},
|
|
243
|
-
getState: (instance) => {
|
|
244
|
-
return instance.state;
|
|
243
|
+
getState: (instance$1) => {
|
|
244
|
+
return instance$1.state;
|
|
245
245
|
},
|
|
246
246
|
queryInstances: (typeClass) => {
|
|
247
|
-
return
|
|
247
|
+
return this.registry.getAll(typeClass);
|
|
248
248
|
},
|
|
249
249
|
getAllTypes: () => {
|
|
250
250
|
return this.registry.getTypes();
|
|
@@ -336,7 +336,7 @@ const getterExecutionContext = {
|
|
|
336
336
|
depth: 0,
|
|
337
337
|
visitedBlocs: /* @__PURE__ */ new Set()
|
|
338
338
|
};
|
|
339
|
-
const MAX_GETTER_DEPTH = BLAC_DEFAULTS.MAX_GETTER_DEPTH;
|
|
339
|
+
const MAX_GETTER_DEPTH$1 = BLAC_DEFAULTS.MAX_GETTER_DEPTH;
|
|
340
340
|
/**
|
|
341
341
|
* @internal
|
|
342
342
|
*/
|
|
@@ -373,7 +373,7 @@ function isGetter(obj, prop) {
|
|
|
373
373
|
/**
|
|
374
374
|
* @internal
|
|
375
375
|
*/
|
|
376
|
-
function
|
|
376
|
+
function createGetterState() {
|
|
377
377
|
return {
|
|
378
378
|
trackedValues: /* @__PURE__ */ new Map(),
|
|
379
379
|
currentlyAccessing: /* @__PURE__ */ new Set(),
|
|
@@ -424,8 +424,8 @@ function createBlocProxy(bloc) {
|
|
|
424
424
|
tracker.trackedValues.set(prop, cachedValue);
|
|
425
425
|
return cachedValue;
|
|
426
426
|
}
|
|
427
|
-
if (getterExecutionContext.depth >= MAX_GETTER_DEPTH) {
|
|
428
|
-
console.warn(`${BLAC_ERROR_PREFIX} Maximum getter depth (${MAX_GETTER_DEPTH}) exceeded. Possible circular dependency in getter "${String(prop)}" on ${target.constructor.name}. Returning undefined to prevent stack overflow.`);
|
|
427
|
+
if (getterExecutionContext.depth >= MAX_GETTER_DEPTH$1) {
|
|
428
|
+
console.warn(`${BLAC_ERROR_PREFIX} Maximum getter depth (${MAX_GETTER_DEPTH$1}) exceeded. Possible circular dependency in getter "${String(prop)}" on ${target.constructor.name}. Returning undefined to prevent stack overflow.`);
|
|
429
429
|
return;
|
|
430
430
|
}
|
|
431
431
|
if (getterExecutionContext.visitedBlocs.has(target)) {
|
|
@@ -501,7 +501,7 @@ function clearExternalDependencies(tracker) {
|
|
|
501
501
|
/**
|
|
502
502
|
* @internal
|
|
503
503
|
*/
|
|
504
|
-
function
|
|
504
|
+
function resetGetterState(tracker) {
|
|
505
505
|
tracker.trackedValues.clear();
|
|
506
506
|
tracker.currentlyAccessing.clear();
|
|
507
507
|
tracker.trackedGetters.clear();
|
|
@@ -511,6 +511,19 @@ function resetGetterTracker(tracker) {
|
|
|
511
511
|
tracker.externalDependencies.clear();
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
+
//#endregion
|
|
515
|
+
//#region src/core/markers.ts
|
|
516
|
+
/**
|
|
517
|
+
* Marker symbols for identifying container types.
|
|
518
|
+
* These are in a separate file to avoid circular dependencies.
|
|
519
|
+
* @internal
|
|
520
|
+
*/
|
|
521
|
+
/**
|
|
522
|
+
* Marker symbol to identify stateless containers at the type level.
|
|
523
|
+
* Used by React hooks to prevent `useBloc` from accepting stateless containers.
|
|
524
|
+
*/
|
|
525
|
+
const STATELESS_MARKER = Symbol("STATELESS_CONTAINER");
|
|
526
|
+
|
|
514
527
|
//#endregion
|
|
515
528
|
//#region src/utils/static-props.ts
|
|
516
529
|
/**
|
|
@@ -555,6 +568,15 @@ function isKeepAliveClass(Type) {
|
|
|
555
568
|
function isExcludedFromDevTools(Type) {
|
|
556
569
|
return getStaticProp(Type, BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS) === true;
|
|
557
570
|
}
|
|
571
|
+
/**
|
|
572
|
+
* Check if a class is a stateless container (StatelessCubit or StatelessVertex).
|
|
573
|
+
* Stateless containers don't have state, emit, update, or subscribe methods.
|
|
574
|
+
* @param Type - The class constructor to check
|
|
575
|
+
* @returns true if the class is a stateless container
|
|
576
|
+
*/
|
|
577
|
+
function isStatelessClass(Type) {
|
|
578
|
+
return Type[STATELESS_MARKER] === true;
|
|
579
|
+
}
|
|
558
580
|
|
|
559
581
|
//#endregion
|
|
560
582
|
//#region src/core/StateContainerRegistry.ts
|
|
@@ -565,7 +587,8 @@ function isExcludedFromDevTools(Type) {
|
|
|
565
587
|
* @example
|
|
566
588
|
* ```ts
|
|
567
589
|
* const registry = new StateContainerRegistry();
|
|
568
|
-
* const instance = registry.
|
|
590
|
+
* const instance = registry.acquire(MyBloc); // ownership, must release
|
|
591
|
+
* const other = registry.ensure(OtherBloc); // no ownership, bloc-to-bloc
|
|
569
592
|
* registry.on('stateChanged', (container, prev, next) => {
|
|
570
593
|
* console.log('State changed:', prev, '->', next);
|
|
571
594
|
* });
|
|
@@ -612,34 +635,35 @@ var StateContainerRegistry = class {
|
|
|
612
635
|
getInstancesMap(Type) {
|
|
613
636
|
return this.instancesByConstructor.get(Type) || /* @__PURE__ */ new Map();
|
|
614
637
|
}
|
|
615
|
-
trackExecutionContext(instance) {
|
|
638
|
+
trackExecutionContext(instance$1) {
|
|
616
639
|
const context = getGetterExecutionContext();
|
|
617
|
-
if (context.tracker && context.currentBloc && context.currentBloc !== instance) context.tracker.externalDependencies.add(instance);
|
|
640
|
+
if (context.tracker && context.currentBloc && context.currentBloc !== instance$1) context.tracker.externalDependencies.add(instance$1);
|
|
618
641
|
}
|
|
619
642
|
/**
|
|
620
|
-
*
|
|
643
|
+
* Acquire an instance with ref counting (ownership semantics).
|
|
621
644
|
* Creates a new instance if one doesn't exist, or returns existing and increments ref count.
|
|
645
|
+
* You must call `release()` when done to decrement the ref count.
|
|
622
646
|
* @param Type - The StateContainer class constructor
|
|
623
647
|
* @param instanceKey - Instance key (defaults to 'default')
|
|
624
|
-
* @param options -
|
|
648
|
+
* @param options - Acquisition options
|
|
625
649
|
* @param options.canCreate - Whether to create new instance if not found (default: true)
|
|
626
650
|
* @param options.countRef - Whether to increment ref count (default: true)
|
|
627
651
|
* @param options.props - Props to pass to constructor if creating new instance
|
|
628
652
|
* @param options.trackExecutionContext - Whether to track cross-bloc dependency (default: false)
|
|
629
653
|
* @returns The state container instance
|
|
630
654
|
*/
|
|
631
|
-
|
|
655
|
+
acquire(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, options = {}) {
|
|
632
656
|
const { canCreate = true, countRef = true, props, trackExecutionContext = false } = options;
|
|
633
657
|
const registryConfig = this.typeConfigs.get(Type.name);
|
|
634
658
|
const isolated = isIsolatedClass(Type) || registryConfig?.isolated === true;
|
|
635
659
|
const config = { instanceId: instanceKey };
|
|
636
660
|
if (isolated && !canCreate) throw new Error(`${BLAC_ERROR_PREFIX} Cannot get isolated instance "${instanceKey}" of ${Type.name} when creation is disabled.`);
|
|
637
661
|
if (isolated) {
|
|
638
|
-
const instance$
|
|
639
|
-
instance$
|
|
662
|
+
const instance$2 = new Type(props);
|
|
663
|
+
instance$2.initConfig(config);
|
|
640
664
|
this.registerType(Type);
|
|
641
|
-
if (trackExecutionContext) this.trackExecutionContext(instance$
|
|
642
|
-
return instance$
|
|
665
|
+
if (trackExecutionContext) this.trackExecutionContext(instance$2);
|
|
666
|
+
return instance$2;
|
|
643
667
|
}
|
|
644
668
|
const instances = this.ensureInstancesMap(Type);
|
|
645
669
|
const entry = instances.get(instanceKey);
|
|
@@ -649,42 +673,42 @@ var StateContainerRegistry = class {
|
|
|
649
673
|
return entry.instance;
|
|
650
674
|
}
|
|
651
675
|
if (!canCreate) throw new Error(`${BLAC_ERROR_PREFIX} ${Type.name} instance "${instanceKey}" not found and creation is disabled.`);
|
|
652
|
-
const instance = new Type(props);
|
|
653
|
-
instance.initConfig(config);
|
|
676
|
+
const instance$1 = new Type(props);
|
|
677
|
+
instance$1.initConfig(config);
|
|
654
678
|
instances.set(instanceKey, {
|
|
655
|
-
instance,
|
|
679
|
+
instance: instance$1,
|
|
656
680
|
refCount: 1
|
|
657
681
|
});
|
|
658
682
|
this.registerType(Type);
|
|
659
|
-
if (trackExecutionContext) this.trackExecutionContext(instance);
|
|
660
|
-
return instance;
|
|
683
|
+
if (trackExecutionContext) this.trackExecutionContext(instance$1);
|
|
684
|
+
return instance$1;
|
|
661
685
|
}
|
|
662
686
|
/**
|
|
663
|
-
*
|
|
687
|
+
* Borrow an existing instance without incrementing ref count (borrowing semantics).
|
|
664
688
|
* Tracks cross-bloc dependency for reactive updates.
|
|
665
689
|
* @param Type - The StateContainer class constructor
|
|
666
690
|
* @param instanceKey - Instance key (defaults to 'default')
|
|
667
691
|
* @returns The state container instance
|
|
668
692
|
* @throws Error if instance doesn't exist
|
|
669
693
|
*/
|
|
670
|
-
|
|
671
|
-
return this.
|
|
694
|
+
borrow(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
|
|
695
|
+
return this.acquire(Type, instanceKey, {
|
|
672
696
|
canCreate: false,
|
|
673
697
|
trackExecutionContext: true
|
|
674
698
|
});
|
|
675
699
|
}
|
|
676
700
|
/**
|
|
677
|
-
* Safely
|
|
701
|
+
* Safely borrow an existing instance (borrowing semantics with error handling).
|
|
678
702
|
* Returns discriminated union for type-safe conditional access.
|
|
679
703
|
* @param Type - The StateContainer class constructor
|
|
680
704
|
* @param instanceKey - Instance key (defaults to 'default')
|
|
681
705
|
* @returns Discriminated union with either the instance or an error
|
|
682
706
|
*/
|
|
683
|
-
|
|
707
|
+
borrowSafe(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
|
|
684
708
|
try {
|
|
685
709
|
return {
|
|
686
710
|
error: null,
|
|
687
|
-
instance: this.
|
|
711
|
+
instance: this.borrow(Type, instanceKey)
|
|
688
712
|
};
|
|
689
713
|
} catch (error$1) {
|
|
690
714
|
return {
|
|
@@ -694,7 +718,7 @@ var StateContainerRegistry = class {
|
|
|
694
718
|
}
|
|
695
719
|
}
|
|
696
720
|
/**
|
|
697
|
-
*
|
|
721
|
+
* Ensure an instance exists without taking ownership (for bloc-to-bloc communication).
|
|
698
722
|
* Gets existing instance OR creates it if it doesn't exist, without incrementing ref count.
|
|
699
723
|
* Tracks cross-bloc dependency for reactive updates.
|
|
700
724
|
*
|
|
@@ -704,8 +728,8 @@ var StateContainerRegistry = class {
|
|
|
704
728
|
* @param instanceKey - Instance key (defaults to 'default')
|
|
705
729
|
* @returns The state container instance
|
|
706
730
|
*/
|
|
707
|
-
|
|
708
|
-
return this.
|
|
731
|
+
ensure(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
|
|
732
|
+
return this.acquire(Type, instanceKey, {
|
|
709
733
|
canCreate: true,
|
|
710
734
|
countRef: false,
|
|
711
735
|
trackExecutionContext: true
|
|
@@ -754,9 +778,9 @@ var StateContainerRegistry = class {
|
|
|
754
778
|
forEach(Type, callback) {
|
|
755
779
|
const instances = this.ensureInstancesMap(Type);
|
|
756
780
|
for (const entry of instances.values()) {
|
|
757
|
-
const instance = entry.instance;
|
|
758
|
-
if (!instance.isDisposed) try {
|
|
759
|
-
callback(instance);
|
|
781
|
+
const instance$1 = entry.instance;
|
|
782
|
+
if (!instance$1.isDisposed) try {
|
|
783
|
+
callback(instance$1);
|
|
760
784
|
} catch (error$1) {
|
|
761
785
|
console.error(`${BLAC_ERROR_PREFIX} forEach callback error for ${Type.name}:`, error$1);
|
|
762
786
|
}
|
|
@@ -834,9 +858,9 @@ var StateContainerRegistry = class {
|
|
|
834
858
|
*/
|
|
835
859
|
on(event, listener) {
|
|
836
860
|
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
837
|
-
const instance = this.listeners.get(event);
|
|
838
|
-
if (!instance) throw new Error(`${BLAC_ERROR_PREFIX} Failed to register listener for event '${event}'`);
|
|
839
|
-
instance.add(listener);
|
|
861
|
+
const instance$1 = this.listeners.get(event);
|
|
862
|
+
if (!instance$1) throw new Error(`${BLAC_ERROR_PREFIX} Failed to register listener for event '${event}'`);
|
|
863
|
+
instance$1.add(listener);
|
|
840
864
|
return () => {
|
|
841
865
|
this.listeners.get(event)?.delete(listener);
|
|
842
866
|
};
|
|
@@ -898,132 +922,7 @@ var StateContainer = class StateContainer {
|
|
|
898
922
|
this.__excludeFromDevTools = false;
|
|
899
923
|
}
|
|
900
924
|
static {
|
|
901
|
-
this.
|
|
902
|
-
}
|
|
903
|
-
/**
|
|
904
|
-
* Get the global StateContainerRegistry
|
|
905
|
-
* @returns The registry managing all state container instances
|
|
906
|
-
*/
|
|
907
|
-
static getRegistry() {
|
|
908
|
-
return StateContainer._registry;
|
|
909
|
-
}
|
|
910
|
-
/**
|
|
911
|
-
* Replace the global registry (clears existing instances)
|
|
912
|
-
* @param registry - The new registry to use
|
|
913
|
-
*/
|
|
914
|
-
static setRegistry(registry) {
|
|
915
|
-
StateContainer._registry.clearAll();
|
|
916
|
-
StateContainer._registry = registry;
|
|
917
|
-
}
|
|
918
|
-
/**
|
|
919
|
-
* Register this class with the global registry
|
|
920
|
-
* @param isolated - Whether instances should be isolated (component-scoped)
|
|
921
|
-
*/
|
|
922
|
-
static register(isolated = false) {
|
|
923
|
-
StateContainer._registry.register(this, isolated);
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* Resolve an instance with ref counting (ownership semantics).
|
|
927
|
-
* Creates a new instance if one doesn't exist, or returns existing and increments ref count.
|
|
928
|
-
* @template S - Optional state type override for generic StateContainers
|
|
929
|
-
* @template T - The StateContainer type (inferred from class)
|
|
930
|
-
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
931
|
-
* @param options - Resolution options (canCreate, countRef, props, trackExecutionContext)
|
|
932
|
-
* @returns The state container instance
|
|
933
|
-
*/
|
|
934
|
-
static resolve(instanceKey, options) {
|
|
935
|
-
return StateContainer._registry.resolve(this, instanceKey, options);
|
|
936
|
-
}
|
|
937
|
-
/**
|
|
938
|
-
* Get an existing instance without incrementing ref count (borrowing semantics).
|
|
939
|
-
* @template S - Optional state type override for generic StateContainers
|
|
940
|
-
* @template T - The StateContainer type (inferred from class)
|
|
941
|
-
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
942
|
-
* @returns The state container instance
|
|
943
|
-
* @throws Error if instance doesn't exist
|
|
944
|
-
*/
|
|
945
|
-
static get(instanceKey) {
|
|
946
|
-
return StateContainer._registry.get(this, instanceKey);
|
|
947
|
-
}
|
|
948
|
-
/**
|
|
949
|
-
* Safely get an existing instance with error handling.
|
|
950
|
-
* @template S - Optional state type override for generic StateContainers
|
|
951
|
-
* @template T - The StateContainer type (inferred from class)
|
|
952
|
-
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
953
|
-
* @returns Discriminated union with either the instance or an error
|
|
954
|
-
*/
|
|
955
|
-
static getSafe(instanceKey) {
|
|
956
|
-
return StateContainer._registry.getSafe(this, instanceKey);
|
|
957
|
-
}
|
|
958
|
-
/**
|
|
959
|
-
* Connect to an instance for bloc-to-bloc communication (borrowing semantics).
|
|
960
|
-
* Gets or creates instance without incrementing ref count.
|
|
961
|
-
* Tracks cross-bloc dependency for reactive updates.
|
|
962
|
-
* @template S - Optional state type override for generic StateContainers
|
|
963
|
-
* @template T - The StateContainer type (inferred from class)
|
|
964
|
-
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
965
|
-
* @returns The state container instance
|
|
966
|
-
*/
|
|
967
|
-
static connect(instanceKey) {
|
|
968
|
-
return StateContainer._registry.connect(this, instanceKey);
|
|
969
|
-
}
|
|
970
|
-
/**
|
|
971
|
-
* Release a reference to an instance.
|
|
972
|
-
* Decrements ref count and disposes when it reaches 0 (unless keepAlive).
|
|
973
|
-
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
974
|
-
* @param forceDispose - Force immediate disposal regardless of ref count
|
|
975
|
-
*/
|
|
976
|
-
static release(instanceKey, forceDispose = false) {
|
|
977
|
-
StateContainer._registry.release(this, instanceKey, forceDispose);
|
|
978
|
-
}
|
|
979
|
-
/**
|
|
980
|
-
* Get all instances of this class
|
|
981
|
-
* @returns Array of all instances
|
|
982
|
-
*/
|
|
983
|
-
static getAll() {
|
|
984
|
-
return StateContainer._registry.getAll(this);
|
|
985
|
-
}
|
|
986
|
-
/**
|
|
987
|
-
* Iterate over all instances of this class
|
|
988
|
-
* @param callback - Function to call for each instance
|
|
989
|
-
*/
|
|
990
|
-
static forEach(callback) {
|
|
991
|
-
StateContainer._registry.forEach(this, callback);
|
|
992
|
-
}
|
|
993
|
-
/**
|
|
994
|
-
* Clear all instances of this class (disposes them)
|
|
995
|
-
*/
|
|
996
|
-
static clear() {
|
|
997
|
-
StateContainer._registry.clear(this);
|
|
998
|
-
}
|
|
999
|
-
/**
|
|
1000
|
-
* Clear all instances from all registered types
|
|
1001
|
-
*/
|
|
1002
|
-
static clearAllInstances() {
|
|
1003
|
-
StateContainer._registry.clearAll();
|
|
1004
|
-
}
|
|
1005
|
-
/**
|
|
1006
|
-
* Get registry statistics for debugging
|
|
1007
|
-
* @returns Object with registeredTypes, totalInstances, and typeBreakdown
|
|
1008
|
-
*/
|
|
1009
|
-
static getStats() {
|
|
1010
|
-
return StateContainer._registry.getStats();
|
|
1011
|
-
}
|
|
1012
|
-
/**
|
|
1013
|
-
* Get reference count for an instance
|
|
1014
|
-
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
1015
|
-
* @returns Current ref count (0 if instance doesn't exist)
|
|
1016
|
-
*/
|
|
1017
|
-
static getRefCount(instanceKey) {
|
|
1018
|
-
return StateContainer._registry.getRefCount(this, instanceKey);
|
|
1019
|
-
}
|
|
1020
|
-
/**
|
|
1021
|
-
* Check if an instance exists
|
|
1022
|
-
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
1023
|
-
* @returns true if instance exists
|
|
1024
|
-
*/
|
|
1025
|
-
static hasInstance(instanceKey) {
|
|
1026
|
-
return StateContainer._registry.hasInstance(this, instanceKey);
|
|
925
|
+
this.enableStackTrace = true;
|
|
1027
926
|
}
|
|
1028
927
|
/** Current props value passed to this container */
|
|
1029
928
|
get props() {
|
|
@@ -1063,7 +962,7 @@ var StateContainer = class StateContainer {
|
|
|
1063
962
|
this.name = this.config.name || this.constructor.name;
|
|
1064
963
|
this.debug = this.config.debug ?? false;
|
|
1065
964
|
this.instanceId = generateSimpleId(this.constructor.name, this.config.instanceId);
|
|
1066
|
-
|
|
965
|
+
globalRegistry.emit("created", this);
|
|
1067
966
|
}
|
|
1068
967
|
/** Current state value */
|
|
1069
968
|
get state() {
|
|
@@ -1094,7 +993,7 @@ var StateContainer = class StateContainer {
|
|
|
1094
993
|
this.emitSystemEvent("dispose", void 0);
|
|
1095
994
|
this.listeners.clear();
|
|
1096
995
|
this.systemEventHandlers.clear();
|
|
1097
|
-
|
|
996
|
+
globalRegistry.emit("disposed", this);
|
|
1098
997
|
if (this.debug) console.log(`[${this.name}] Disposed successfully`);
|
|
1099
998
|
}
|
|
1100
999
|
/**
|
|
@@ -1117,12 +1016,9 @@ var StateContainer = class StateContainer {
|
|
|
1117
1016
|
console.error(`[${this.name}] Error in listener:`, error$1);
|
|
1118
1017
|
}
|
|
1119
1018
|
const stackTrace = this.captureStackTrace();
|
|
1120
|
-
|
|
1019
|
+
globalRegistry.emit("stateChanged", this, previousState, newState, stackTrace);
|
|
1121
1020
|
this.lastUpdateTimestamp = Date.now();
|
|
1122
1021
|
}
|
|
1123
|
-
static {
|
|
1124
|
-
this.enableStackTrace = true;
|
|
1125
|
-
}
|
|
1126
1022
|
captureStackTrace() {
|
|
1127
1023
|
if (!StateContainer.enableStackTrace || typeof process !== "undefined" && process.env?.NODE_ENV === "production") return "";
|
|
1128
1024
|
try {
|
|
@@ -1238,33 +1134,70 @@ var Cubit = class extends StateContainer {
|
|
|
1238
1134
|
//#endregion
|
|
1239
1135
|
//#region src/core/Vertex.ts
|
|
1240
1136
|
/**
|
|
1241
|
-
* Event-driven state container
|
|
1242
|
-
*
|
|
1137
|
+
* Event-driven state container using discriminated union events.
|
|
1138
|
+
* Extends StateContainer with event-based state transitions and
|
|
1139
|
+
* compile-time exhaustive checking for event handlers.
|
|
1243
1140
|
*
|
|
1244
|
-
* @template S - State type
|
|
1245
|
-
* @template E - Event type (
|
|
1141
|
+
* @template S - State type (must be an object)
|
|
1142
|
+
* @template E - Event union type (discriminated by 'type' property)
|
|
1246
1143
|
* @template P - Props type (optional)
|
|
1144
|
+
*
|
|
1145
|
+
* @example
|
|
1146
|
+
* ```typescript
|
|
1147
|
+
* type CounterEvent =
|
|
1148
|
+
* | { type: 'increment'; amount: number }
|
|
1149
|
+
* | { type: 'decrement' }
|
|
1150
|
+
* | { type: 'reset' };
|
|
1151
|
+
*
|
|
1152
|
+
* class CounterVertex extends Vertex<{ count: number }, CounterEvent> {
|
|
1153
|
+
* constructor() {
|
|
1154
|
+
* super({ count: 0 });
|
|
1155
|
+
* this.createHandlers({
|
|
1156
|
+
* increment: (event, emit) => {
|
|
1157
|
+
* emit({ count: this.state.count + event.amount });
|
|
1158
|
+
* },
|
|
1159
|
+
* decrement: (_, emit) => {
|
|
1160
|
+
* emit({ count: this.state.count - 1 });
|
|
1161
|
+
* },
|
|
1162
|
+
* reset: (_, emit) => {
|
|
1163
|
+
* emit({ count: 0 });
|
|
1164
|
+
* },
|
|
1165
|
+
* });
|
|
1166
|
+
* }
|
|
1167
|
+
*
|
|
1168
|
+
* increment = (amount = 1) => this.add({ type: 'increment', amount });
|
|
1169
|
+
* }
|
|
1170
|
+
* ```
|
|
1247
1171
|
*/
|
|
1248
1172
|
var Vertex = class extends StateContainer {
|
|
1249
1173
|
constructor(initialState) {
|
|
1250
1174
|
super(initialState);
|
|
1251
|
-
this.
|
|
1175
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
1252
1176
|
this.isProcessing = false;
|
|
1253
1177
|
this.eventQueue = [];
|
|
1254
|
-
this.on = (EventClass, handler) => {
|
|
1255
|
-
const className = EventClass.name;
|
|
1256
|
-
const registrations = this.eventHandlers.get(className) || [];
|
|
1257
|
-
registrations.push({
|
|
1258
|
-
eventClass: EventClass,
|
|
1259
|
-
handler
|
|
1260
|
-
});
|
|
1261
|
-
this.eventHandlers.set(className, registrations);
|
|
1262
|
-
};
|
|
1263
1178
|
this.add = (event) => {
|
|
1264
|
-
|
|
1265
|
-
|
|
1179
|
+
const enrichedEvent = this.enrichEvent(event);
|
|
1180
|
+
globalRegistry.emit("eventAdded", this, enrichedEvent);
|
|
1181
|
+
this.processEvent(enrichedEvent);
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Register all event handlers with exhaustive type checking.
|
|
1186
|
+
* TypeScript will error if any event type from the union is missing.
|
|
1187
|
+
*
|
|
1188
|
+
* @param handlers - Map of event type to handler function
|
|
1189
|
+
*/
|
|
1190
|
+
createHandlers(handlers) {
|
|
1191
|
+
for (const [eventType, handler] of Object.entries(handlers)) this.handlers.set(eventType, handler);
|
|
1192
|
+
}
|
|
1193
|
+
/** @internal */
|
|
1194
|
+
enrichEvent(event) {
|
|
1195
|
+
return {
|
|
1196
|
+
...event,
|
|
1197
|
+
timestamp: Date.now()
|
|
1266
1198
|
};
|
|
1267
1199
|
}
|
|
1200
|
+
/** @internal */
|
|
1268
1201
|
processEvent(event) {
|
|
1269
1202
|
if (this.isProcessing) {
|
|
1270
1203
|
this.eventQueue.push(event);
|
|
@@ -1281,30 +1214,248 @@ var Vertex = class extends StateContainer {
|
|
|
1281
1214
|
this.isProcessing = false;
|
|
1282
1215
|
}
|
|
1283
1216
|
}
|
|
1217
|
+
/** @internal */
|
|
1284
1218
|
handleEvent(event) {
|
|
1285
|
-
const
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
if (this.debug) console.warn(`No handler registered for event: ${className}`);
|
|
1219
|
+
const handler = this.handlers.get(event.type);
|
|
1220
|
+
if (!handler) {
|
|
1221
|
+
if (this.debug) console.warn(`No handler registered for event type: ${event.type}`);
|
|
1289
1222
|
return;
|
|
1290
1223
|
}
|
|
1291
1224
|
const emitFn = (state) => {
|
|
1292
1225
|
this.emit(state);
|
|
1293
1226
|
};
|
|
1294
|
-
|
|
1295
|
-
|
|
1227
|
+
try {
|
|
1228
|
+
handler(event, emitFn);
|
|
1229
|
+
} catch (error$1) {
|
|
1230
|
+
if (this.debug) console.error(`Error handling event ${event.type}:`, error$1);
|
|
1231
|
+
this.onEventError(event, error$1);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Called when an error occurs during event processing.
|
|
1236
|
+
* Override to implement custom error handling.
|
|
1237
|
+
*
|
|
1238
|
+
* @param _event - The event that caused the error
|
|
1239
|
+
* @param _error - The error that occurred
|
|
1240
|
+
*/
|
|
1241
|
+
onEventError(_event, _error) {}
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
//#endregion
|
|
1245
|
+
//#region src/core/StatelessCubit.ts
|
|
1246
|
+
/**
|
|
1247
|
+
* A Cubit without state management capabilities.
|
|
1248
|
+
* Use this for action-only containers that don't need to manage or emit state.
|
|
1249
|
+
*
|
|
1250
|
+
* StatelessCubit:
|
|
1251
|
+
* - Has no `emit()`, `update()`, or `patch()` methods
|
|
1252
|
+
* - Has no accessible `state` property
|
|
1253
|
+
* - Cannot be subscribed to (throws error)
|
|
1254
|
+
* - Is rejected by `useBloc` hook (use `useBlocActions` instead)
|
|
1255
|
+
*
|
|
1256
|
+
* @template P - Props type (optional)
|
|
1257
|
+
*
|
|
1258
|
+
* @example
|
|
1259
|
+
* ```typescript
|
|
1260
|
+
* class AnalyticsService extends StatelessCubit {
|
|
1261
|
+
* trackPageView(page: string) {
|
|
1262
|
+
* analytics.track('page_view', { page });
|
|
1263
|
+
* }
|
|
1264
|
+
*
|
|
1265
|
+
* trackClick(element: string) {
|
|
1266
|
+
* analytics.track('click', { element });
|
|
1267
|
+
* }
|
|
1268
|
+
* }
|
|
1269
|
+
*
|
|
1270
|
+
* // In React component:
|
|
1271
|
+
* const analytics = useBlocActions(AnalyticsService);
|
|
1272
|
+
* analytics.trackPageView('/home');
|
|
1273
|
+
* ```
|
|
1274
|
+
*/
|
|
1275
|
+
var StatelessCubit = class extends Cubit {
|
|
1276
|
+
static {
|
|
1277
|
+
this[STATELESS_MARKER] = true;
|
|
1278
|
+
}
|
|
1279
|
+
constructor() {
|
|
1280
|
+
super({});
|
|
1281
|
+
this.patch = (_partial) => {
|
|
1282
|
+
throw new Error(`${this.name} is a StatelessCubit and does not support patch(). Use a regular Cubit if you need state management.`);
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* State is not available on StatelessCubit.
|
|
1287
|
+
* @throws Always throws an error when accessed.
|
|
1288
|
+
*/
|
|
1289
|
+
get state() {
|
|
1290
|
+
throw new Error(`${this.name} is a StatelessCubit and does not have state. Use a regular Cubit if you need state management.`);
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Subscriptions are not available on StatelessCubit.
|
|
1294
|
+
* @throws Always throws an error when called.
|
|
1295
|
+
*/
|
|
1296
|
+
subscribe(_listener) {
|
|
1297
|
+
throw new Error(`${this.name} is a StatelessCubit and does not support subscriptions. Use useBlocActions() instead of useBloc() in React.`);
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* emit() is not available on StatelessCubit.
|
|
1301
|
+
* TypeScript will show an error if you try to call this method.
|
|
1302
|
+
*/
|
|
1303
|
+
emit(_newState) {
|
|
1304
|
+
throw new Error(`${this.name} is a StatelessCubit and does not support emit(). Use a regular Cubit if you need state management.`);
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* update() is not available on StatelessCubit.
|
|
1308
|
+
* TypeScript will show an error if you try to call this method.
|
|
1309
|
+
*/
|
|
1310
|
+
update(_updater) {
|
|
1311
|
+
throw new Error(`${this.name} is a StatelessCubit and does not support update(). Use a regular Cubit if you need state management.`);
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
//#endregion
|
|
1316
|
+
//#region src/core/StatelessVertex.ts
|
|
1317
|
+
/**
|
|
1318
|
+
* An event-driven container without state management capabilities.
|
|
1319
|
+
* Use this for event processing that only produces side effects (logging, analytics, etc).
|
|
1320
|
+
*
|
|
1321
|
+
* StatelessVertex:
|
|
1322
|
+
* - Processes events via `add()` method
|
|
1323
|
+
* - Handlers receive only the event (no `emit` function)
|
|
1324
|
+
* - Has no accessible `state` property
|
|
1325
|
+
* - Cannot be subscribed to (throws error)
|
|
1326
|
+
* - Is rejected by `useBloc` hook (use `useBlocActions` instead)
|
|
1327
|
+
*
|
|
1328
|
+
* @template E - Event union type (discriminated by 'type' property)
|
|
1329
|
+
* @template P - Props type (optional)
|
|
1330
|
+
*
|
|
1331
|
+
* @example
|
|
1332
|
+
* ```typescript
|
|
1333
|
+
* type LogEvent =
|
|
1334
|
+
* | { type: 'info'; message: string }
|
|
1335
|
+
* | { type: 'error'; message: string; error: Error }
|
|
1336
|
+
* | { type: 'warn'; message: string };
|
|
1337
|
+
*
|
|
1338
|
+
* class LoggingVertex extends StatelessVertex<LogEvent> {
|
|
1339
|
+
* constructor() {
|
|
1340
|
+
* super();
|
|
1341
|
+
* this.createHandlers({
|
|
1342
|
+
* info: (event) => console.log('[INFO]', event.message),
|
|
1343
|
+
* error: (event) => console.error('[ERROR]', event.message, event.error),
|
|
1344
|
+
* warn: (event) => console.warn('[WARN]', event.message),
|
|
1345
|
+
* });
|
|
1346
|
+
* }
|
|
1347
|
+
*
|
|
1348
|
+
* info = (message: string) => this.add({ type: 'info', message });
|
|
1349
|
+
* error = (message: string, error: Error) => this.add({ type: 'error', message, error });
|
|
1350
|
+
* warn = (message: string) => this.add({ type: 'warn', message });
|
|
1351
|
+
* }
|
|
1352
|
+
*
|
|
1353
|
+
* // In React component:
|
|
1354
|
+
* const logger = useBlocActions(LoggingVertex);
|
|
1355
|
+
* logger.info('Page loaded');
|
|
1356
|
+
* ```
|
|
1357
|
+
*/
|
|
1358
|
+
var StatelessVertex = class extends StateContainer {
|
|
1359
|
+
static {
|
|
1360
|
+
this[STATELESS_MARKER] = true;
|
|
1361
|
+
}
|
|
1362
|
+
constructor() {
|
|
1363
|
+
super({});
|
|
1364
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
1365
|
+
this.isProcessing = false;
|
|
1366
|
+
this.eventQueue = [];
|
|
1367
|
+
this.add = (event) => {
|
|
1368
|
+
const enrichedEvent = this.enrichEvent(event);
|
|
1369
|
+
globalRegistry.emit("eventAdded", this, enrichedEvent);
|
|
1370
|
+
this.processEvent(enrichedEvent);
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* State is not available on StatelessVertex.
|
|
1375
|
+
* @throws Always throws an error when accessed.
|
|
1376
|
+
*/
|
|
1377
|
+
get state() {
|
|
1378
|
+
throw new Error(`${this.name} is a StatelessVertex and does not have state. Use a regular Vertex if you need state management.`);
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* Subscriptions are not available on StatelessVertex.
|
|
1382
|
+
* @throws Always throws an error when called.
|
|
1383
|
+
*/
|
|
1384
|
+
subscribe(_listener) {
|
|
1385
|
+
throw new Error(`${this.name} is a StatelessVertex and does not support subscriptions. Use useBlocActions() instead of useBloc() in React.`);
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Register all event handlers with exhaustive type checking.
|
|
1389
|
+
* TypeScript will error if any event type from the union is missing.
|
|
1390
|
+
*
|
|
1391
|
+
* Unlike regular Vertex, handlers do NOT receive an emit function
|
|
1392
|
+
* since StatelessVertex cannot emit state.
|
|
1393
|
+
*
|
|
1394
|
+
* @param handlers - Map of event type to handler function
|
|
1395
|
+
*/
|
|
1396
|
+
createHandlers(handlers) {
|
|
1397
|
+
for (const [eventType, handler] of Object.entries(handlers)) this.handlers.set(eventType, handler);
|
|
1398
|
+
}
|
|
1399
|
+
/** @internal */
|
|
1400
|
+
enrichEvent(event) {
|
|
1401
|
+
return {
|
|
1402
|
+
...event,
|
|
1403
|
+
timestamp: Date.now()
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
/** @internal */
|
|
1407
|
+
processEvent(event) {
|
|
1408
|
+
if (this.isProcessing) {
|
|
1409
|
+
this.eventQueue.push(event);
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
this.isProcessing = true;
|
|
1413
|
+
try {
|
|
1414
|
+
this.handleEvent(event);
|
|
1415
|
+
while (this.eventQueue.length > 0) {
|
|
1416
|
+
const nextEvent = this.eventQueue.shift();
|
|
1417
|
+
this.handleEvent(nextEvent);
|
|
1418
|
+
}
|
|
1419
|
+
} finally {
|
|
1420
|
+
this.isProcessing = false;
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
/** @internal */
|
|
1424
|
+
handleEvent(event) {
|
|
1425
|
+
const handler = this.handlers.get(event.type);
|
|
1426
|
+
if (!handler) {
|
|
1427
|
+
if (this.debug) console.warn(`No handler registered for event type: ${event.type}`);
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
try {
|
|
1431
|
+
handler(event);
|
|
1296
1432
|
} catch (error$1) {
|
|
1297
|
-
if (this.debug) console.error(`Error handling event ${
|
|
1433
|
+
if (this.debug) console.error(`Error handling event ${event.type}:`, error$1);
|
|
1298
1434
|
this.onEventError(event, error$1);
|
|
1299
1435
|
}
|
|
1300
1436
|
}
|
|
1301
1437
|
/**
|
|
1302
|
-
*
|
|
1303
|
-
* Override
|
|
1438
|
+
* Called when an error occurs during event processing.
|
|
1439
|
+
* Override to implement custom error handling.
|
|
1440
|
+
*
|
|
1304
1441
|
* @param _event - The event that caused the error
|
|
1305
1442
|
* @param _error - The error that occurred
|
|
1306
1443
|
*/
|
|
1307
1444
|
onEventError(_event, _error) {}
|
|
1445
|
+
/**
|
|
1446
|
+
* emit() is not available on StatelessVertex.
|
|
1447
|
+
* @internal
|
|
1448
|
+
*/
|
|
1449
|
+
emit(_newState) {
|
|
1450
|
+
throw new Error(`${this.name} is a StatelessVertex and does not support emit(). Use a regular Vertex if you need state management.`);
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* update() is not available on StatelessVertex.
|
|
1454
|
+
* @internal
|
|
1455
|
+
*/
|
|
1456
|
+
update(_updater) {
|
|
1457
|
+
throw new Error(`${this.name} is a StatelessVertex and does not support update(). Use a regular Vertex if you need state management.`);
|
|
1458
|
+
}
|
|
1308
1459
|
};
|
|
1309
1460
|
|
|
1310
1461
|
//#endregion
|
|
@@ -1354,7 +1505,7 @@ function isProxyable(value) {
|
|
|
1354
1505
|
*
|
|
1355
1506
|
* @internal
|
|
1356
1507
|
*/
|
|
1357
|
-
function
|
|
1508
|
+
function createProxyState() {
|
|
1358
1509
|
return {
|
|
1359
1510
|
trackedPaths: /* @__PURE__ */ new Set(),
|
|
1360
1511
|
isTracking: false,
|
|
@@ -1372,7 +1523,7 @@ function createProxyTrackerState() {
|
|
|
1372
1523
|
*
|
|
1373
1524
|
* @internal
|
|
1374
1525
|
*/
|
|
1375
|
-
function
|
|
1526
|
+
function startProxy(state) {
|
|
1376
1527
|
state.isTracking = true;
|
|
1377
1528
|
state.trackedPaths.clear();
|
|
1378
1529
|
}
|
|
@@ -1383,7 +1534,7 @@ function startProxyTracking(state) {
|
|
|
1383
1534
|
*
|
|
1384
1535
|
* @internal
|
|
1385
1536
|
*/
|
|
1386
|
-
function
|
|
1537
|
+
function stopProxy(state) {
|
|
1387
1538
|
state.isTracking = false;
|
|
1388
1539
|
return new Set(state.trackedPaths);
|
|
1389
1540
|
}
|
|
@@ -1422,7 +1573,7 @@ function createArrayProxy(state, target, path, depth = 0) {
|
|
|
1422
1573
|
if (!isNaN(index) && index >= 0) fullPath = path ? `${path}[${index}]` : `[${index}]`;
|
|
1423
1574
|
else fullPath = path ? `${path}.${prop}` : prop;
|
|
1424
1575
|
} else return value;
|
|
1425
|
-
if (isProxyable(value)) return
|
|
1576
|
+
if (isProxyable(value)) return createInternal(state, value, fullPath, depth + 1);
|
|
1426
1577
|
if (state.isTracking) state.trackedPaths.add(fullPath);
|
|
1427
1578
|
return value;
|
|
1428
1579
|
} });
|
|
@@ -1443,7 +1594,7 @@ function createArrayProxy(state, target, path, depth = 0) {
|
|
|
1443
1594
|
*
|
|
1444
1595
|
* @internal
|
|
1445
1596
|
*/
|
|
1446
|
-
function
|
|
1597
|
+
function createInternal(state, target, path = "", depth = 0) {
|
|
1447
1598
|
if (!state.isTracking || !isProxyable(target)) return target;
|
|
1448
1599
|
if (depth >= state.maxDepth) return target;
|
|
1449
1600
|
if (state.proxyCache.has(target)) return state.proxyCache.get(target);
|
|
@@ -1464,7 +1615,7 @@ function createProxyInternal(state, target, path = "", depth = 0) {
|
|
|
1464
1615
|
if (typeof prop === "string" && state.isTracking) {
|
|
1465
1616
|
if (!prop.startsWith("_") && !prop.startsWith("$$")) state.trackedPaths.add(fullPath);
|
|
1466
1617
|
}
|
|
1467
|
-
if (isProxyable(value)) return
|
|
1618
|
+
if (isProxyable(value)) return createInternal(state, value, fullPath, depth + 1);
|
|
1468
1619
|
return value;
|
|
1469
1620
|
},
|
|
1470
1621
|
has: (obj, prop) => {
|
|
@@ -1492,11 +1643,11 @@ function createProxyInternal(state, target, path = "", depth = 0) {
|
|
|
1492
1643
|
*
|
|
1493
1644
|
* @internal
|
|
1494
1645
|
*/
|
|
1495
|
-
function
|
|
1646
|
+
function createForTarget(state, target) {
|
|
1496
1647
|
if (state.lastProxiedState === target && state.lastProxy) return state.lastProxy;
|
|
1497
1648
|
state.proxyCache = /* @__PURE__ */ new WeakMap();
|
|
1498
1649
|
state.boundFunctionsCache = null;
|
|
1499
|
-
const proxy =
|
|
1650
|
+
const proxy = createInternal(state, target, "", 0);
|
|
1500
1651
|
state.lastProxiedState = target;
|
|
1501
1652
|
state.lastProxy = proxy;
|
|
1502
1653
|
return proxy;
|
|
@@ -1637,9 +1788,9 @@ function optimizeTrackedPaths(paths) {
|
|
|
1637
1788
|
/**
|
|
1638
1789
|
* @internal
|
|
1639
1790
|
*/
|
|
1640
|
-
function
|
|
1791
|
+
function createDependencyState() {
|
|
1641
1792
|
return {
|
|
1642
|
-
|
|
1793
|
+
proxyState: createProxyState(),
|
|
1643
1794
|
previousRenderPaths: /* @__PURE__ */ new Set(),
|
|
1644
1795
|
currentRenderPaths: /* @__PURE__ */ new Set(),
|
|
1645
1796
|
pathCache: /* @__PURE__ */ new Map(),
|
|
@@ -1650,21 +1801,21 @@ function createTrackerState() {
|
|
|
1650
1801
|
/**
|
|
1651
1802
|
* @internal
|
|
1652
1803
|
*/
|
|
1653
|
-
function
|
|
1654
|
-
|
|
1804
|
+
function startDependency(tracker) {
|
|
1805
|
+
startProxy(tracker.proxyState);
|
|
1655
1806
|
}
|
|
1656
1807
|
/**
|
|
1657
1808
|
* @internal
|
|
1658
1809
|
*/
|
|
1659
|
-
function
|
|
1660
|
-
return
|
|
1810
|
+
function createDependencyProxy(tracker, state) {
|
|
1811
|
+
return createForTarget(tracker.proxyState, state);
|
|
1661
1812
|
}
|
|
1662
1813
|
/**
|
|
1663
1814
|
* @internal
|
|
1664
1815
|
*/
|
|
1665
|
-
function
|
|
1816
|
+
function capturePaths(tracker, state) {
|
|
1666
1817
|
tracker.previousRenderPaths = tracker.currentRenderPaths;
|
|
1667
|
-
tracker.currentRenderPaths = optimizeTrackedPaths(
|
|
1818
|
+
tracker.currentRenderPaths = optimizeTrackedPaths(stopProxy(tracker.proxyState));
|
|
1668
1819
|
if (tracker.previousRenderPaths.size === 0 && tracker.currentRenderPaths.size === 0) return;
|
|
1669
1820
|
const trackedPathsUnion = new Set(tracker.previousRenderPaths);
|
|
1670
1821
|
for (const path of tracker.currentRenderPaths) trackedPathsUnion.add(path);
|
|
@@ -1685,7 +1836,7 @@ function captureTrackedPaths(tracker, state) {
|
|
|
1685
1836
|
/**
|
|
1686
1837
|
* @internal
|
|
1687
1838
|
*/
|
|
1688
|
-
function
|
|
1839
|
+
function hasDependencyChanges(tracker, state) {
|
|
1689
1840
|
if (tracker.pathCache.size === 0) return true;
|
|
1690
1841
|
tracker.lastCheckedValues.clear();
|
|
1691
1842
|
for (const [path, info$1] of tracker.pathCache.entries()) {
|
|
@@ -1703,7 +1854,294 @@ function hasChanges(tracker, state) {
|
|
|
1703
1854
|
* @internal
|
|
1704
1855
|
*/
|
|
1705
1856
|
function hasTrackedData(tracker) {
|
|
1706
|
-
return tracker.
|
|
1857
|
+
return tracker.proxyState.trackedPaths.size > 0 || tracker.pathCache.size > 0 || tracker.previousRenderPaths.size > 0;
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
//#endregion
|
|
1861
|
+
//#region src/tracking/tracking-proxy.ts
|
|
1862
|
+
/**
|
|
1863
|
+
* Create a new tracking proxy state.
|
|
1864
|
+
*/
|
|
1865
|
+
function createState() {
|
|
1866
|
+
return {
|
|
1867
|
+
dependencyState: createDependencyState(),
|
|
1868
|
+
getterState: createGetterState(),
|
|
1869
|
+
dependencies: /* @__PURE__ */ new Set(),
|
|
1870
|
+
isTracking: false
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
/**
|
|
1874
|
+
* Start tracking on a tracking proxy.
|
|
1875
|
+
*/
|
|
1876
|
+
function startTracking(tracker) {
|
|
1877
|
+
tracker.isTracking = true;
|
|
1878
|
+
tracker.dependencies.clear();
|
|
1879
|
+
tracker.getterState.isTracking = true;
|
|
1880
|
+
tracker.getterState.externalDependencies.clear();
|
|
1881
|
+
startDependency(tracker.dependencyState);
|
|
1882
|
+
}
|
|
1883
|
+
/**
|
|
1884
|
+
* Stop tracking and collect all dependencies.
|
|
1885
|
+
*/
|
|
1886
|
+
function stopTracking(tracker, bloc) {
|
|
1887
|
+
tracker.isTracking = false;
|
|
1888
|
+
tracker.getterState.isTracking = false;
|
|
1889
|
+
capturePaths(tracker.dependencyState, bloc.state);
|
|
1890
|
+
commitTrackedGetters(tracker.getterState);
|
|
1891
|
+
const allDeps = new Set(tracker.dependencies);
|
|
1892
|
+
for (const dep of tracker.getterState.externalDependencies) allDeps.add(dep);
|
|
1893
|
+
tracker.getterState.externalDependencies.clear();
|
|
1894
|
+
return allDeps;
|
|
1895
|
+
}
|
|
1896
|
+
/**
|
|
1897
|
+
* Check if tracked state or getters have changed.
|
|
1898
|
+
*/
|
|
1899
|
+
function hasChanges(tracker, bloc) {
|
|
1900
|
+
invalidateRenderCache(tracker.getterState);
|
|
1901
|
+
const stateChanged = hasDependencyChanges(tracker.dependencyState, bloc.state);
|
|
1902
|
+
const getterChanged = hasGetterChanges(bloc, tracker.getterState);
|
|
1903
|
+
return stateChanged || getterChanged;
|
|
1904
|
+
}
|
|
1905
|
+
const MAX_GETTER_DEPTH = BLAC_DEFAULTS.MAX_GETTER_DEPTH;
|
|
1906
|
+
/**
|
|
1907
|
+
* Create a tracking proxy for a bloc instance.
|
|
1908
|
+
* Tracks both state property access and getter access.
|
|
1909
|
+
*/
|
|
1910
|
+
function createTrackingProxy(bloc, tracker) {
|
|
1911
|
+
tracker.dependencies.add(bloc);
|
|
1912
|
+
const stateProxyCache = /* @__PURE__ */ new WeakMap();
|
|
1913
|
+
return new Proxy(bloc, { get(target, prop, receiver) {
|
|
1914
|
+
if (prop === "state") {
|
|
1915
|
+
if (!tracker.isTracking) return target.state;
|
|
1916
|
+
const rawState = target.state;
|
|
1917
|
+
if (rawState === null || typeof rawState !== "object") return rawState;
|
|
1918
|
+
if (stateProxyCache.has(rawState)) return stateProxyCache.get(rawState);
|
|
1919
|
+
const stateProxy = createDependencyProxy(tracker.dependencyState, rawState);
|
|
1920
|
+
stateProxyCache.set(rawState, stateProxy);
|
|
1921
|
+
return stateProxy;
|
|
1922
|
+
}
|
|
1923
|
+
if (typeof prop === "symbol") return Reflect.get(target, prop, receiver);
|
|
1924
|
+
const value = Reflect.get(target, prop, receiver);
|
|
1925
|
+
if (typeof value === "function") return value.bind(target);
|
|
1926
|
+
if (tracker.isTracking && isGetter(target, prop)) {
|
|
1927
|
+
tracker.getterState.currentlyAccessing.add(prop);
|
|
1928
|
+
if (tracker.getterState.cacheValid && tracker.getterState.renderCache.has(prop)) {
|
|
1929
|
+
const cachedValue = tracker.getterState.renderCache.get(prop);
|
|
1930
|
+
tracker.getterState.trackedValues.set(prop, cachedValue);
|
|
1931
|
+
return cachedValue;
|
|
1932
|
+
}
|
|
1933
|
+
const context = getGetterExecutionContext();
|
|
1934
|
+
if (context.depth >= MAX_GETTER_DEPTH) {
|
|
1935
|
+
console.warn(`${BLAC_ERROR_PREFIX} Maximum getter depth (${MAX_GETTER_DEPTH}) exceeded. Possible circular dependency in getter "${String(prop)}" on ${target.constructor.name}.`);
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
if (context.visitedBlocs.has(target)) {
|
|
1939
|
+
console.warn(`${BLAC_ERROR_PREFIX} Circular dependency detected: getter "${String(prop)}" on ${target.constructor.name}.`);
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
const prevContext = {
|
|
1943
|
+
tracker: context.tracker,
|
|
1944
|
+
currentBloc: context.currentBloc,
|
|
1945
|
+
depth: context.depth,
|
|
1946
|
+
visitedBlocs: new Set(context.visitedBlocs)
|
|
1947
|
+
};
|
|
1948
|
+
context.tracker = tracker.getterState;
|
|
1949
|
+
context.currentBloc = target;
|
|
1950
|
+
context.depth++;
|
|
1951
|
+
context.visitedBlocs.add(target);
|
|
1952
|
+
try {
|
|
1953
|
+
const getterValue = getDescriptor(target, prop).get.call(target);
|
|
1954
|
+
tracker.getterState.trackedValues.set(prop, getterValue);
|
|
1955
|
+
return getterValue;
|
|
1956
|
+
} catch (error$1) {
|
|
1957
|
+
tracker.getterState.currentlyAccessing.delete(prop);
|
|
1958
|
+
throw error$1;
|
|
1959
|
+
} finally {
|
|
1960
|
+
context.tracker = prevContext.tracker;
|
|
1961
|
+
context.currentBloc = prevContext.currentBloc;
|
|
1962
|
+
context.depth = prevContext.depth;
|
|
1963
|
+
context.visitedBlocs = prevContext.visitedBlocs;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return value;
|
|
1967
|
+
} });
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
//#endregion
|
|
1971
|
+
//#region src/tracking/dependency-manager.ts
|
|
1972
|
+
/**
|
|
1973
|
+
* Manages subscriptions to state container dependencies.
|
|
1974
|
+
* Provides efficient sync mechanism to add/remove subscriptions
|
|
1975
|
+
* as dependencies change between callback invocations.
|
|
1976
|
+
*/
|
|
1977
|
+
var DependencyManager = class {
|
|
1978
|
+
constructor() {
|
|
1979
|
+
this.subscriptions = /* @__PURE__ */ new Map();
|
|
1980
|
+
this.currentDeps = /* @__PURE__ */ new Set();
|
|
1981
|
+
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Sync subscriptions with a new set of dependencies.
|
|
1984
|
+
* Adds subscriptions for new deps, removes subscriptions for stale deps.
|
|
1985
|
+
*
|
|
1986
|
+
* @param newDeps - The new set of dependencies to subscribe to
|
|
1987
|
+
* @param onChange - Callback to invoke when any dependency changes
|
|
1988
|
+
* @param exclude - Optional instance to exclude from subscriptions (e.g., primary bloc)
|
|
1989
|
+
* @returns true if the dependency set changed, false if unchanged
|
|
1990
|
+
*/
|
|
1991
|
+
sync(newDeps, onChange, exclude) {
|
|
1992
|
+
const filteredNewDeps = /* @__PURE__ */ new Set();
|
|
1993
|
+
for (const dep of newDeps) if (dep !== exclude && !dep.isDisposed) filteredNewDeps.add(dep);
|
|
1994
|
+
if (this.areSetsEqual(this.currentDeps, filteredNewDeps)) return false;
|
|
1995
|
+
for (const dep of this.currentDeps) if (!filteredNewDeps.has(dep)) {
|
|
1996
|
+
const unsub = this.subscriptions.get(dep);
|
|
1997
|
+
if (unsub) {
|
|
1998
|
+
unsub();
|
|
1999
|
+
this.subscriptions.delete(dep);
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
for (const dep of filteredNewDeps) if (!this.currentDeps.has(dep) && !this.subscriptions.has(dep)) {
|
|
2003
|
+
const unsub = dep.subscribe(onChange);
|
|
2004
|
+
this.subscriptions.set(dep, unsub);
|
|
2005
|
+
}
|
|
2006
|
+
this.currentDeps = filteredNewDeps;
|
|
2007
|
+
return true;
|
|
2008
|
+
}
|
|
2009
|
+
/**
|
|
2010
|
+
* Add a single dependency subscription.
|
|
2011
|
+
*/
|
|
2012
|
+
add(dep, onChange) {
|
|
2013
|
+
if (this.subscriptions.has(dep) || dep.isDisposed) return;
|
|
2014
|
+
const unsub = dep.subscribe(onChange);
|
|
2015
|
+
this.subscriptions.set(dep, unsub);
|
|
2016
|
+
this.currentDeps.add(dep);
|
|
2017
|
+
}
|
|
2018
|
+
/**
|
|
2019
|
+
* Check if a dependency is currently subscribed.
|
|
2020
|
+
*/
|
|
2021
|
+
has(dep) {
|
|
2022
|
+
return this.currentDeps.has(dep);
|
|
2023
|
+
}
|
|
2024
|
+
/**
|
|
2025
|
+
* Get the current set of dependencies.
|
|
2026
|
+
*/
|
|
2027
|
+
getDependencies() {
|
|
2028
|
+
return new Set(this.currentDeps);
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
2031
|
+
* Clean up all active subscriptions.
|
|
2032
|
+
*/
|
|
2033
|
+
cleanup() {
|
|
2034
|
+
for (const unsub of this.subscriptions.values()) unsub();
|
|
2035
|
+
this.subscriptions.clear();
|
|
2036
|
+
this.currentDeps.clear();
|
|
2037
|
+
}
|
|
2038
|
+
areSetsEqual(a, b) {
|
|
2039
|
+
if (a.size !== b.size) return false;
|
|
2040
|
+
for (const item of a) if (!b.has(item)) return false;
|
|
2041
|
+
return true;
|
|
2042
|
+
}
|
|
2043
|
+
};
|
|
2044
|
+
|
|
2045
|
+
//#endregion
|
|
2046
|
+
//#region src/tracking/tracked.ts
|
|
2047
|
+
/**
|
|
2048
|
+
* Run a callback while tracking all bloc dependencies accessed.
|
|
2049
|
+
* Returns both the result and the set of discovered dependencies.
|
|
2050
|
+
*
|
|
2051
|
+
* @example
|
|
2052
|
+
* ```ts
|
|
2053
|
+
* const { result, dependencies } = tracked(() => {
|
|
2054
|
+
* const user = ensure(UserBloc);
|
|
2055
|
+
* return user.fullName; // getter that may access other blocs
|
|
2056
|
+
* });
|
|
2057
|
+
* // dependencies contains UserBloc + any blocs accessed in fullName getter
|
|
2058
|
+
* ```
|
|
2059
|
+
*/
|
|
2060
|
+
function tracked(callback, options) {
|
|
2061
|
+
const tracker = createState();
|
|
2062
|
+
startTracking(tracker);
|
|
2063
|
+
let result;
|
|
2064
|
+
try {
|
|
2065
|
+
result = callback();
|
|
2066
|
+
} finally {
|
|
2067
|
+
stopTracking(tracker, { state: null });
|
|
2068
|
+
}
|
|
2069
|
+
const dependencies = new Set(tracker.dependencies);
|
|
2070
|
+
for (const dep of tracker.getterState.externalDependencies) dependencies.add(dep);
|
|
2071
|
+
if (options?.exclude) dependencies.delete(options.exclude);
|
|
2072
|
+
return {
|
|
2073
|
+
result,
|
|
2074
|
+
dependencies
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
/**
|
|
2078
|
+
* Context for running tracked callbacks with bloc proxies.
|
|
2079
|
+
* Provides methods to create proxies and check for changes.
|
|
2080
|
+
*/
|
|
2081
|
+
var TrackedContext = class {
|
|
2082
|
+
constructor() {
|
|
2083
|
+
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
|
|
2084
|
+
this.primaryBlocs = /* @__PURE__ */ new Set();
|
|
2085
|
+
this.tracker = createState();
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Get a tracking proxy for a bloc instance.
|
|
2089
|
+
* The proxy will track state and getter accesses.
|
|
2090
|
+
*/
|
|
2091
|
+
proxy(bloc) {
|
|
2092
|
+
const cached = this.proxiedBlocs.get(bloc);
|
|
2093
|
+
if (cached) return cached;
|
|
2094
|
+
const proxied = createTrackingProxy(bloc, this.tracker);
|
|
2095
|
+
this.proxiedBlocs.set(bloc, proxied);
|
|
2096
|
+
this.primaryBlocs.add(bloc);
|
|
2097
|
+
return proxied;
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Start tracking for a new callback execution.
|
|
2101
|
+
*/
|
|
2102
|
+
start() {
|
|
2103
|
+
startTracking(this.tracker);
|
|
2104
|
+
}
|
|
2105
|
+
/**
|
|
2106
|
+
* Stop tracking and get discovered dependencies.
|
|
2107
|
+
* Excludes primary blocs (those explicitly proxied via proxy()).
|
|
2108
|
+
*/
|
|
2109
|
+
stop() {
|
|
2110
|
+
const allDeps = /* @__PURE__ */ new Set();
|
|
2111
|
+
for (const bloc of this.primaryBlocs) {
|
|
2112
|
+
const deps = stopTracking(this.tracker, bloc);
|
|
2113
|
+
for (const dep of deps) if (!this.primaryBlocs.has(dep)) allDeps.add(dep);
|
|
2114
|
+
}
|
|
2115
|
+
for (const dep of this.tracker.getterState.externalDependencies) if (!this.primaryBlocs.has(dep)) allDeps.add(dep);
|
|
2116
|
+
return allDeps;
|
|
2117
|
+
}
|
|
2118
|
+
/**
|
|
2119
|
+
* Check if any tracked state or getters have changed.
|
|
2120
|
+
*/
|
|
2121
|
+
changed() {
|
|
2122
|
+
for (const bloc of this.primaryBlocs) if (hasChanges(this.tracker, bloc)) return true;
|
|
2123
|
+
return false;
|
|
2124
|
+
}
|
|
2125
|
+
/**
|
|
2126
|
+
* Get all primary blocs (those explicitly proxied).
|
|
2127
|
+
*/
|
|
2128
|
+
getPrimaryBlocs() {
|
|
2129
|
+
return new Set(this.primaryBlocs);
|
|
2130
|
+
}
|
|
2131
|
+
/**
|
|
2132
|
+
* Reset the context for reuse.
|
|
2133
|
+
*/
|
|
2134
|
+
reset() {
|
|
2135
|
+
this.tracker = createState();
|
|
2136
|
+
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
|
|
2137
|
+
this.primaryBlocs.clear();
|
|
2138
|
+
}
|
|
2139
|
+
};
|
|
2140
|
+
/**
|
|
2141
|
+
* Create a new tracked context for manual control over tracking.
|
|
2142
|
+
*/
|
|
2143
|
+
function createTrackedContext() {
|
|
2144
|
+
return new TrackedContext();
|
|
1707
2145
|
}
|
|
1708
2146
|
|
|
1709
2147
|
//#endregion
|
|
@@ -1712,16 +2150,13 @@ function hasTrackedData(tracker) {
|
|
|
1712
2150
|
* Manages subscriptions to external bloc dependencies for getter tracking.
|
|
1713
2151
|
* When a getter accesses another bloc's state, this manager ensures
|
|
1714
2152
|
* re-renders occur when those external dependencies change.
|
|
2153
|
+
*
|
|
2154
|
+
* @deprecated Use DependencyManager from tracking module instead.
|
|
2155
|
+
* This class is kept for backward compatibility.
|
|
1715
2156
|
*/
|
|
1716
|
-
var
|
|
2157
|
+
var ExternalDepsManager = class {
|
|
1717
2158
|
constructor() {
|
|
1718
|
-
this.
|
|
1719
|
-
this.previousDeps = /* @__PURE__ */ new Set();
|
|
1720
|
-
}
|
|
1721
|
-
areDependenciesEqual(oldDeps, newDeps) {
|
|
1722
|
-
if (oldDeps.size !== newDeps.size) return false;
|
|
1723
|
-
for (const dep of newDeps) if (!oldDeps.has(dep)) return false;
|
|
1724
|
-
return true;
|
|
2159
|
+
this.manager = new DependencyManager();
|
|
1725
2160
|
}
|
|
1726
2161
|
/**
|
|
1727
2162
|
* Update subscriptions to external bloc dependencies.
|
|
@@ -1731,32 +2166,22 @@ var ExternalDependencyManager = class {
|
|
|
1731
2166
|
* @param onGetterChange - Callback to invoke when external dependency changes
|
|
1732
2167
|
* @returns true if subscriptions were updated, false if unchanged
|
|
1733
2168
|
*/
|
|
1734
|
-
updateSubscriptions(
|
|
1735
|
-
if (!
|
|
1736
|
-
const currentDeps =
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
}
|
|
1741
|
-
this.
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
const unsub = externalBloc.subscribe(() => {
|
|
1745
|
-
invalidateRenderCache(getterTracker);
|
|
1746
|
-
if (hasGetterChanges(rawInstance, getterTracker)) onGetterChange();
|
|
1747
|
-
});
|
|
1748
|
-
this.subscriptions.push(unsub);
|
|
1749
|
-
}
|
|
1750
|
-
this.previousDeps = new Set(currentDeps);
|
|
1751
|
-
clearExternalDependencies(getterTracker);
|
|
1752
|
-
return true;
|
|
2169
|
+
updateSubscriptions(getterState, rawInstance, onGetterChange) {
|
|
2170
|
+
if (!getterState?.externalDependencies) return false;
|
|
2171
|
+
const currentDeps = getterState.externalDependencies;
|
|
2172
|
+
const onExternalChange = () => {
|
|
2173
|
+
invalidateRenderCache(getterState);
|
|
2174
|
+
if (hasGetterChanges(rawInstance, getterState)) onGetterChange();
|
|
2175
|
+
};
|
|
2176
|
+
const changed = this.manager.sync(currentDeps, onExternalChange, rawInstance);
|
|
2177
|
+
clearExternalDependencies(getterState);
|
|
2178
|
+
return changed;
|
|
1753
2179
|
}
|
|
1754
2180
|
/**
|
|
1755
2181
|
* Clean up all active subscriptions
|
|
1756
2182
|
*/
|
|
1757
2183
|
cleanup() {
|
|
1758
|
-
this.
|
|
1759
|
-
this.subscriptions = [];
|
|
2184
|
+
this.manager.cleanup();
|
|
1760
2185
|
}
|
|
1761
2186
|
};
|
|
1762
2187
|
/**
|
|
@@ -1766,21 +2191,21 @@ var ExternalDependencyManager = class {
|
|
|
1766
2191
|
* @param adapterState - The adapter state for tracking
|
|
1767
2192
|
* @returns Subscribe function for use with useSyncExternalStore
|
|
1768
2193
|
*/
|
|
1769
|
-
function
|
|
2194
|
+
function autoTrackSubscribe(instance$1, adapterState) {
|
|
1770
2195
|
return (callback) => {
|
|
1771
|
-
return instance.subscribe(() => {
|
|
1772
|
-
const
|
|
1773
|
-
const hasStateDeps =
|
|
1774
|
-
const hasGetterDeps = adapterState.
|
|
1775
|
-
const isPrimitiveState = instance.state !== null && typeof instance.state !== "object" && typeof instance.state !== "function";
|
|
2196
|
+
return instance$1.subscribe(() => {
|
|
2197
|
+
const depState = adapterState.dependencyState || (adapterState.dependencyState = createDependencyState());
|
|
2198
|
+
const hasStateDeps = depState.pathCache && depState.pathCache.size > 0;
|
|
2199
|
+
const hasGetterDeps = adapterState.getterState && adapterState.getterState.trackedGetters.size > 0;
|
|
2200
|
+
const isPrimitiveState = instance$1.state !== null && typeof instance$1.state !== "object" && typeof instance$1.state !== "function";
|
|
1776
2201
|
if (!hasStateDeps && !hasGetterDeps && !isPrimitiveState) return;
|
|
1777
|
-
let stateChanged =
|
|
2202
|
+
let stateChanged = hasDependencyChanges(depState, instance$1.state);
|
|
1778
2203
|
if (!hasStateDeps && hasGetterDeps) stateChanged = false;
|
|
1779
2204
|
if (stateChanged) {
|
|
1780
2205
|
callback();
|
|
1781
2206
|
return;
|
|
1782
2207
|
}
|
|
1783
|
-
if (hasGetterChanges(instance, adapterState.
|
|
2208
|
+
if (hasGetterChanges(instance$1, adapterState.getterState)) callback();
|
|
1784
2209
|
});
|
|
1785
2210
|
};
|
|
1786
2211
|
}
|
|
@@ -1792,10 +2217,10 @@ function createAutoTrackSubscribe(instance, adapterState) {
|
|
|
1792
2217
|
* @param config - Configuration with dependencies function
|
|
1793
2218
|
* @returns Subscribe function for use with useSyncExternalStore
|
|
1794
2219
|
*/
|
|
1795
|
-
function
|
|
2220
|
+
function manualDepsSubscribe(instance$1, adapterState, config) {
|
|
1796
2221
|
return (callback) => {
|
|
1797
|
-
return instance.subscribe(() => {
|
|
1798
|
-
const newDeps = config.dependencies(instance.state, instance);
|
|
2222
|
+
return instance$1.subscribe(() => {
|
|
2223
|
+
const newDeps = config.dependencies(instance$1.state, instance$1);
|
|
1799
2224
|
if (!adapterState.manualDepsCache || !shallowEqual(adapterState.manualDepsCache, newDeps)) {
|
|
1800
2225
|
adapterState.manualDepsCache = newDeps;
|
|
1801
2226
|
callback();
|
|
@@ -1809,8 +2234,8 @@ function createManualDepsSubscribe(instance, adapterState, config) {
|
|
|
1809
2234
|
* @param instance - The state container instance
|
|
1810
2235
|
* @returns Subscribe function for use with useSyncExternalStore
|
|
1811
2236
|
*/
|
|
1812
|
-
function
|
|
1813
|
-
return (callback) => instance.subscribe(callback);
|
|
2237
|
+
function noTrackSubscribe(instance$1) {
|
|
2238
|
+
return (callback) => instance$1.subscribe(callback);
|
|
1814
2239
|
}
|
|
1815
2240
|
/**
|
|
1816
2241
|
* Create a snapshot function for auto-tracking mode.
|
|
@@ -1819,18 +2244,18 @@ function createNoTrackSubscribe(instance) {
|
|
|
1819
2244
|
* @param adapterState - The adapter state for tracking
|
|
1820
2245
|
* @returns Snapshot function for use with useSyncExternalStore
|
|
1821
2246
|
*/
|
|
1822
|
-
function
|
|
2247
|
+
function autoTrackSnapshot(instance$1, adapterState) {
|
|
1823
2248
|
return () => {
|
|
1824
|
-
const
|
|
1825
|
-
if (hasTrackedData(
|
|
1826
|
-
if (adapterState.
|
|
1827
|
-
invalidateRenderCache(adapterState.
|
|
1828
|
-
commitTrackedGetters(adapterState.
|
|
1829
|
-
adapterState.
|
|
1830
|
-
setActiveTracker(instance, adapterState.
|
|
2249
|
+
const depState = adapterState.dependencyState || (adapterState.dependencyState = createDependencyState());
|
|
2250
|
+
if (hasTrackedData(depState)) capturePaths(depState, instance$1.state);
|
|
2251
|
+
if (adapterState.getterState) {
|
|
2252
|
+
invalidateRenderCache(adapterState.getterState);
|
|
2253
|
+
commitTrackedGetters(adapterState.getterState);
|
|
2254
|
+
adapterState.getterState.isTracking = true;
|
|
2255
|
+
setActiveTracker(instance$1, adapterState.getterState);
|
|
1831
2256
|
}
|
|
1832
|
-
|
|
1833
|
-
return
|
|
2257
|
+
startDependency(depState);
|
|
2258
|
+
return createDependencyProxy(depState, instance$1.state);
|
|
1834
2259
|
};
|
|
1835
2260
|
}
|
|
1836
2261
|
/**
|
|
@@ -1841,10 +2266,10 @@ function createAutoTrackSnapshot(instance, adapterState) {
|
|
|
1841
2266
|
* @param config - Configuration with dependencies function
|
|
1842
2267
|
* @returns Snapshot function for use with useSyncExternalStore
|
|
1843
2268
|
*/
|
|
1844
|
-
function
|
|
2269
|
+
function manualDepsSnapshot(instance$1, adapterState, config) {
|
|
1845
2270
|
return () => {
|
|
1846
|
-
adapterState.manualDepsCache = config.dependencies(instance.state, instance);
|
|
1847
|
-
return instance.state;
|
|
2271
|
+
adapterState.manualDepsCache = config.dependencies(instance$1.state, instance$1);
|
|
2272
|
+
return instance$1.state;
|
|
1848
2273
|
};
|
|
1849
2274
|
}
|
|
1850
2275
|
/**
|
|
@@ -1853,8 +2278,8 @@ function createManualDepsSnapshot(instance, adapterState, config) {
|
|
|
1853
2278
|
* @param instance - The state container instance
|
|
1854
2279
|
* @returns Snapshot function for use with useSyncExternalStore
|
|
1855
2280
|
*/
|
|
1856
|
-
function
|
|
1857
|
-
return () => instance.state;
|
|
2281
|
+
function noTrackSnapshot(instance$1) {
|
|
2282
|
+
return () => instance$1.state;
|
|
1858
2283
|
}
|
|
1859
2284
|
/**
|
|
1860
2285
|
* Initialize adapter state for auto-tracking mode.
|
|
@@ -1862,12 +2287,12 @@ function createNoTrackSnapshot(instance) {
|
|
|
1862
2287
|
* @param instance - The state container instance
|
|
1863
2288
|
* @returns Initialized adapter state
|
|
1864
2289
|
*/
|
|
1865
|
-
function
|
|
2290
|
+
function autoTrackInit(instance$1) {
|
|
1866
2291
|
return {
|
|
1867
|
-
|
|
2292
|
+
dependencyState: null,
|
|
1868
2293
|
manualDepsCache: null,
|
|
1869
|
-
|
|
1870
|
-
proxiedBloc: createBlocProxy(instance)
|
|
2294
|
+
getterState: createGetterState(),
|
|
2295
|
+
proxiedBloc: createBlocProxy(instance$1)
|
|
1871
2296
|
};
|
|
1872
2297
|
}
|
|
1873
2298
|
/**
|
|
@@ -1876,12 +2301,12 @@ function initAutoTrackState(instance) {
|
|
|
1876
2301
|
* @param instance - The state container instance
|
|
1877
2302
|
* @returns Initialized adapter state
|
|
1878
2303
|
*/
|
|
1879
|
-
function
|
|
2304
|
+
function manualDepsInit(instance$1) {
|
|
1880
2305
|
return {
|
|
1881
|
-
|
|
2306
|
+
dependencyState: null,
|
|
1882
2307
|
manualDepsCache: null,
|
|
1883
|
-
|
|
1884
|
-
proxiedBloc: instance
|
|
2308
|
+
getterState: null,
|
|
2309
|
+
proxiedBloc: instance$1
|
|
1885
2310
|
};
|
|
1886
2311
|
}
|
|
1887
2312
|
/**
|
|
@@ -1890,12 +2315,12 @@ function initManualDepsState(instance) {
|
|
|
1890
2315
|
* @param instance - The state container instance
|
|
1891
2316
|
* @returns Initialized adapter state
|
|
1892
2317
|
*/
|
|
1893
|
-
function
|
|
2318
|
+
function noTrackInit(instance$1) {
|
|
1894
2319
|
return {
|
|
1895
|
-
|
|
2320
|
+
dependencyState: null,
|
|
1896
2321
|
manualDepsCache: null,
|
|
1897
|
-
|
|
1898
|
-
proxiedBloc: instance
|
|
2322
|
+
getterState: null,
|
|
2323
|
+
proxiedBloc: instance$1
|
|
1899
2324
|
};
|
|
1900
2325
|
}
|
|
1901
2326
|
/**
|
|
@@ -1905,8 +2330,8 @@ function initNoTrackState(instance) {
|
|
|
1905
2330
|
* @param rawInstance - The raw bloc instance
|
|
1906
2331
|
*/
|
|
1907
2332
|
function disableGetterTracking(adapterState, rawInstance) {
|
|
1908
|
-
if (adapterState.
|
|
1909
|
-
adapterState.
|
|
2333
|
+
if (adapterState.getterState) {
|
|
2334
|
+
adapterState.getterState.isTracking = false;
|
|
1910
2335
|
clearActiveTracker(rawInstance);
|
|
1911
2336
|
}
|
|
1912
2337
|
}
|
|
@@ -2038,6 +2463,67 @@ function configureLogger(opts) {
|
|
|
2038
2463
|
defaultLogger = createLogger(currentConfig);
|
|
2039
2464
|
}
|
|
2040
2465
|
|
|
2466
|
+
//#endregion
|
|
2467
|
+
//#region src/config.ts
|
|
2468
|
+
const defaultConfig = {
|
|
2469
|
+
devMode: process.env.NODE_ENV !== "production",
|
|
2470
|
+
logger: {
|
|
2471
|
+
enabled: false,
|
|
2472
|
+
level: LogLevel.INFO
|
|
2473
|
+
}
|
|
2474
|
+
};
|
|
2475
|
+
let globalConfig = { ...defaultConfig };
|
|
2476
|
+
/**
|
|
2477
|
+
* Configure global defaults for @blac/core.
|
|
2478
|
+
*
|
|
2479
|
+
* @example
|
|
2480
|
+
* ```ts
|
|
2481
|
+
* import { configureBlac, LogLevel } from '@blac/core';
|
|
2482
|
+
*
|
|
2483
|
+
* configureBlac({
|
|
2484
|
+
* devMode: true,
|
|
2485
|
+
* logger: {
|
|
2486
|
+
* enabled: true,
|
|
2487
|
+
* level: LogLevel.DEBUG
|
|
2488
|
+
* }
|
|
2489
|
+
* });
|
|
2490
|
+
* ```
|
|
2491
|
+
*
|
|
2492
|
+
* @param config - Partial configuration to merge with defaults
|
|
2493
|
+
*/
|
|
2494
|
+
function configureBlac(config) {
|
|
2495
|
+
globalConfig = {
|
|
2496
|
+
...globalConfig,
|
|
2497
|
+
...config,
|
|
2498
|
+
logger: {
|
|
2499
|
+
...globalConfig.logger,
|
|
2500
|
+
...config.logger
|
|
2501
|
+
}
|
|
2502
|
+
};
|
|
2503
|
+
if (config.logger) configureLogger(config.logger);
|
|
2504
|
+
}
|
|
2505
|
+
/**
|
|
2506
|
+
* Get the current global configuration.
|
|
2507
|
+
* @internal
|
|
2508
|
+
*/
|
|
2509
|
+
function getBlacConfig() {
|
|
2510
|
+
return globalConfig;
|
|
2511
|
+
}
|
|
2512
|
+
/**
|
|
2513
|
+
* Check if development mode is enabled.
|
|
2514
|
+
*/
|
|
2515
|
+
function isDevMode() {
|
|
2516
|
+
return globalConfig.devMode;
|
|
2517
|
+
}
|
|
2518
|
+
/**
|
|
2519
|
+
* Reset configuration to defaults (useful for testing).
|
|
2520
|
+
* @internal
|
|
2521
|
+
*/
|
|
2522
|
+
function resetBlacConfig() {
|
|
2523
|
+
globalConfig = { ...defaultConfig };
|
|
2524
|
+
configureLogger(defaultConfig.logger);
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2041
2527
|
//#endregion
|
|
2042
2528
|
//#region src/decorators/blac.ts
|
|
2043
2529
|
/**
|
|
@@ -2071,76 +2557,437 @@ function blac(options) {
|
|
|
2071
2557
|
};
|
|
2072
2558
|
}
|
|
2073
2559
|
|
|
2560
|
+
//#endregion
|
|
2561
|
+
//#region src/registry/acquire.ts
|
|
2562
|
+
function acquire(BlocClass, instanceKey, options) {
|
|
2563
|
+
return globalRegistry.acquire(BlocClass, instanceKey, {
|
|
2564
|
+
canCreate: true,
|
|
2565
|
+
countRef: true,
|
|
2566
|
+
props: options?.props
|
|
2567
|
+
});
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
//#endregion
|
|
2571
|
+
//#region src/registry/borrow.ts
|
|
2572
|
+
function borrow(BlocClass, instanceKey) {
|
|
2573
|
+
return globalRegistry.borrow(BlocClass, instanceKey);
|
|
2574
|
+
}
|
|
2575
|
+
function borrowSafe(BlocClass, instanceKey) {
|
|
2576
|
+
return globalRegistry.borrowSafe(BlocClass, instanceKey);
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
//#endregion
|
|
2580
|
+
//#region src/registry/ensure.ts
|
|
2581
|
+
function ensure(BlocClass, instanceKey) {
|
|
2582
|
+
return globalRegistry.ensure(BlocClass, instanceKey);
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
//#endregion
|
|
2586
|
+
//#region src/registry/release.ts
|
|
2587
|
+
function release(BlocClass, instanceKey, forceDispose = false) {
|
|
2588
|
+
globalRegistry.release(BlocClass, instanceKey, forceDispose);
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
//#endregion
|
|
2592
|
+
//#region src/registry/queries.ts
|
|
2593
|
+
function hasInstance(BlocClass, instanceKey) {
|
|
2594
|
+
return globalRegistry.hasInstance(BlocClass, instanceKey);
|
|
2595
|
+
}
|
|
2596
|
+
function getRefCount(BlocClass, instanceKey) {
|
|
2597
|
+
return globalRegistry.getRefCount(BlocClass, instanceKey);
|
|
2598
|
+
}
|
|
2599
|
+
function getAll(BlocClass) {
|
|
2600
|
+
return globalRegistry.getAll(BlocClass);
|
|
2601
|
+
}
|
|
2602
|
+
function forEach(BlocClass, callback) {
|
|
2603
|
+
globalRegistry.forEach(BlocClass, callback);
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
//#endregion
|
|
2607
|
+
//#region src/registry/management.ts
|
|
2608
|
+
function clear(BlocClass) {
|
|
2609
|
+
globalRegistry.clear(BlocClass);
|
|
2610
|
+
}
|
|
2611
|
+
function clearAll() {
|
|
2612
|
+
globalRegistry.clearAll();
|
|
2613
|
+
}
|
|
2614
|
+
function register(BlocClass, isolated = false) {
|
|
2615
|
+
globalRegistry.register(BlocClass, isolated);
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2618
|
+
//#endregion
|
|
2619
|
+
//#region src/registry/config.ts
|
|
2620
|
+
let _registry = globalRegistry;
|
|
2621
|
+
function getRegistry() {
|
|
2622
|
+
return _registry;
|
|
2623
|
+
}
|
|
2624
|
+
function setRegistry(registry) {
|
|
2625
|
+
_registry.clearAll();
|
|
2626
|
+
_registry = registry;
|
|
2627
|
+
}
|
|
2628
|
+
function getStats() {
|
|
2629
|
+
return _registry.getStats();
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2632
|
+
//#endregion
|
|
2633
|
+
//#region src/waitUntil/errors.ts
|
|
2634
|
+
var WaitUntilTimeoutError = class extends Error {
|
|
2635
|
+
constructor(timeout) {
|
|
2636
|
+
super(`waitUntil timed out after ${timeout}ms`);
|
|
2637
|
+
this.name = "WaitUntilTimeoutError";
|
|
2638
|
+
}
|
|
2639
|
+
};
|
|
2640
|
+
var WaitUntilAbortedError = class extends Error {
|
|
2641
|
+
constructor() {
|
|
2642
|
+
super("waitUntil was aborted");
|
|
2643
|
+
this.name = "WaitUntilAbortedError";
|
|
2644
|
+
}
|
|
2645
|
+
};
|
|
2646
|
+
var WaitUntilDisposedError = class extends Error {
|
|
2647
|
+
constructor(blocName) {
|
|
2648
|
+
super(`waitUntil failed: ${blocName} was disposed while waiting`);
|
|
2649
|
+
this.name = "WaitUntilDisposedError";
|
|
2650
|
+
}
|
|
2651
|
+
};
|
|
2652
|
+
|
|
2653
|
+
//#endregion
|
|
2654
|
+
//#region src/waitUntil/waitUntil.ts
|
|
2655
|
+
function waitUntil(BlocClass, selectorOrPredicate, predicateOrOptions, maybeOptions) {
|
|
2656
|
+
if (typeof predicateOrOptions !== "function") return waitUntilSimple(BlocClass, selectorOrPredicate, predicateOrOptions);
|
|
2657
|
+
else return waitUntilSelector(BlocClass, selectorOrPredicate, predicateOrOptions, maybeOptions);
|
|
2658
|
+
}
|
|
2659
|
+
function waitUntilSimple(BlocClass, predicate, options) {
|
|
2660
|
+
const { instanceId = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, timeout, signal } = options ?? {};
|
|
2661
|
+
return new Promise((resolve, reject) => {
|
|
2662
|
+
if (signal?.aborted) {
|
|
2663
|
+
reject(new WaitUntilAbortedError());
|
|
2664
|
+
return;
|
|
2665
|
+
}
|
|
2666
|
+
const bloc = ensure(BlocClass, instanceId);
|
|
2667
|
+
if (bloc.isDisposed) {
|
|
2668
|
+
reject(new WaitUntilDisposedError(BlocClass.name));
|
|
2669
|
+
return;
|
|
2670
|
+
}
|
|
2671
|
+
const tracker = createState();
|
|
2672
|
+
const proxiedBloc = createTrackingProxy(bloc, tracker);
|
|
2673
|
+
const externalDepsManager = new DependencyManager();
|
|
2674
|
+
const runPredicate = () => {
|
|
2675
|
+
startTracking(tracker);
|
|
2676
|
+
try {
|
|
2677
|
+
return predicate(proxiedBloc);
|
|
2678
|
+
} finally {
|
|
2679
|
+
const deps = stopTracking(tracker, bloc);
|
|
2680
|
+
for (const dep of tracker.getterState.externalDependencies) deps.add(dep);
|
|
2681
|
+
deps.delete(bloc);
|
|
2682
|
+
externalDepsManager.sync(deps, checkCondition, bloc);
|
|
2683
|
+
}
|
|
2684
|
+
};
|
|
2685
|
+
if (runPredicate()) {
|
|
2686
|
+
resolve(bloc);
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
let unsubscribe = null;
|
|
2690
|
+
let unsubscribeDispose = null;
|
|
2691
|
+
let timeoutId = null;
|
|
2692
|
+
let abortHandler = null;
|
|
2693
|
+
const cleanup = () => {
|
|
2694
|
+
unsubscribe?.();
|
|
2695
|
+
unsubscribeDispose?.();
|
|
2696
|
+
externalDepsManager.cleanup();
|
|
2697
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
2698
|
+
if (abortHandler && signal) signal.removeEventListener("abort", abortHandler);
|
|
2699
|
+
};
|
|
2700
|
+
function checkCondition() {
|
|
2701
|
+
try {
|
|
2702
|
+
if (runPredicate()) {
|
|
2703
|
+
cleanup();
|
|
2704
|
+
resolve(bloc);
|
|
2705
|
+
}
|
|
2706
|
+
} catch (error$1) {
|
|
2707
|
+
cleanup();
|
|
2708
|
+
reject(error$1);
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
unsubscribe = bloc.subscribe(checkCondition);
|
|
2712
|
+
unsubscribeDispose = getRegistry().on("disposed", (instance$1) => {
|
|
2713
|
+
if (instance$1 === bloc) {
|
|
2714
|
+
cleanup();
|
|
2715
|
+
reject(new WaitUntilDisposedError(BlocClass.name));
|
|
2716
|
+
}
|
|
2717
|
+
});
|
|
2718
|
+
if (timeout !== void 0) timeoutId = setTimeout(() => {
|
|
2719
|
+
cleanup();
|
|
2720
|
+
reject(new WaitUntilTimeoutError(timeout));
|
|
2721
|
+
}, timeout);
|
|
2722
|
+
if (signal) {
|
|
2723
|
+
abortHandler = () => {
|
|
2724
|
+
cleanup();
|
|
2725
|
+
reject(new WaitUntilAbortedError());
|
|
2726
|
+
};
|
|
2727
|
+
signal.addEventListener("abort", abortHandler);
|
|
2728
|
+
}
|
|
2729
|
+
});
|
|
2730
|
+
}
|
|
2731
|
+
function waitUntilSelector(BlocClass, selector, predicate, options) {
|
|
2732
|
+
const { instanceId = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, timeout, signal } = options ?? {};
|
|
2733
|
+
return new Promise((resolve, reject) => {
|
|
2734
|
+
if (signal?.aborted) {
|
|
2735
|
+
reject(new WaitUntilAbortedError());
|
|
2736
|
+
return;
|
|
2737
|
+
}
|
|
2738
|
+
const bloc = ensure(BlocClass, instanceId);
|
|
2739
|
+
if (bloc.isDisposed) {
|
|
2740
|
+
reject(new WaitUntilDisposedError(BlocClass.name));
|
|
2741
|
+
return;
|
|
2742
|
+
}
|
|
2743
|
+
const tracker = createState();
|
|
2744
|
+
const proxiedBloc = createTrackingProxy(bloc, tracker);
|
|
2745
|
+
const externalDepsManager = new DependencyManager();
|
|
2746
|
+
const runSelector = () => {
|
|
2747
|
+
startTracking(tracker);
|
|
2748
|
+
try {
|
|
2749
|
+
const value = selector(proxiedBloc);
|
|
2750
|
+
return {
|
|
2751
|
+
value,
|
|
2752
|
+
matches: predicate(value)
|
|
2753
|
+
};
|
|
2754
|
+
} finally {
|
|
2755
|
+
const deps = stopTracking(tracker, bloc);
|
|
2756
|
+
for (const dep of tracker.getterState.externalDependencies) deps.add(dep);
|
|
2757
|
+
deps.delete(bloc);
|
|
2758
|
+
externalDepsManager.sync(deps, checkCondition, bloc);
|
|
2759
|
+
}
|
|
2760
|
+
};
|
|
2761
|
+
const initial = runSelector();
|
|
2762
|
+
if (initial.matches) {
|
|
2763
|
+
resolve(initial.value);
|
|
2764
|
+
return;
|
|
2765
|
+
}
|
|
2766
|
+
let unsubscribe = null;
|
|
2767
|
+
let unsubscribeDispose = null;
|
|
2768
|
+
let timeoutId = null;
|
|
2769
|
+
let abortHandler = null;
|
|
2770
|
+
const cleanup = () => {
|
|
2771
|
+
unsubscribe?.();
|
|
2772
|
+
unsubscribeDispose?.();
|
|
2773
|
+
externalDepsManager.cleanup();
|
|
2774
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
2775
|
+
if (abortHandler && signal) signal.removeEventListener("abort", abortHandler);
|
|
2776
|
+
};
|
|
2777
|
+
function checkCondition() {
|
|
2778
|
+
try {
|
|
2779
|
+
const result = runSelector();
|
|
2780
|
+
if (result.matches) {
|
|
2781
|
+
cleanup();
|
|
2782
|
+
resolve(result.value);
|
|
2783
|
+
}
|
|
2784
|
+
} catch (error$1) {
|
|
2785
|
+
cleanup();
|
|
2786
|
+
reject(error$1);
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
unsubscribe = bloc.subscribe(checkCondition);
|
|
2790
|
+
unsubscribeDispose = getRegistry().on("disposed", (instance$1) => {
|
|
2791
|
+
if (instance$1 === bloc) {
|
|
2792
|
+
cleanup();
|
|
2793
|
+
reject(new WaitUntilDisposedError(BlocClass.name));
|
|
2794
|
+
}
|
|
2795
|
+
});
|
|
2796
|
+
if (timeout !== void 0) timeoutId = setTimeout(() => {
|
|
2797
|
+
cleanup();
|
|
2798
|
+
reject(new WaitUntilTimeoutError(timeout));
|
|
2799
|
+
}, timeout);
|
|
2800
|
+
if (signal) {
|
|
2801
|
+
abortHandler = () => {
|
|
2802
|
+
cleanup();
|
|
2803
|
+
reject(new WaitUntilAbortedError());
|
|
2804
|
+
};
|
|
2805
|
+
signal.addEventListener("abort", abortHandler);
|
|
2806
|
+
}
|
|
2807
|
+
});
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
//#endregion
|
|
2811
|
+
//#region src/watch/watch.ts
|
|
2812
|
+
const STOP = Symbol("watch.STOP");
|
|
2813
|
+
const BLOC_REF_MARKER = Symbol("BlocRef");
|
|
2814
|
+
/**
|
|
2815
|
+
* Create a reference to a specific bloc instance.
|
|
2816
|
+
*
|
|
2817
|
+
* @example
|
|
2818
|
+
* ```ts
|
|
2819
|
+
* watch(instance(UserBloc, 'user-123'), (userBloc) => {
|
|
2820
|
+
* console.log(userBloc.state.name);
|
|
2821
|
+
* });
|
|
2822
|
+
* ```
|
|
2823
|
+
*/
|
|
2824
|
+
function instance(BlocClass, instanceId) {
|
|
2825
|
+
return {
|
|
2826
|
+
[BLOC_REF_MARKER]: true,
|
|
2827
|
+
blocClass: BlocClass,
|
|
2828
|
+
instanceId
|
|
2829
|
+
};
|
|
2830
|
+
}
|
|
2831
|
+
function isBlocRef(input) {
|
|
2832
|
+
return typeof input === "object" && input !== null && BLOC_REF_MARKER in input;
|
|
2833
|
+
}
|
|
2834
|
+
function resolveBloc(input) {
|
|
2835
|
+
if (isBlocRef(input)) return ensure(input.blocClass, input.instanceId);
|
|
2836
|
+
return ensure(input, BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY);
|
|
2837
|
+
}
|
|
2838
|
+
function isArray(input) {
|
|
2839
|
+
return Array.isArray(input);
|
|
2840
|
+
}
|
|
2841
|
+
function watchImpl(blocsOrBloc, callback) {
|
|
2842
|
+
const isSingle = !isArray(blocsOrBloc);
|
|
2843
|
+
const instances = (isSingle ? [blocsOrBloc] : blocsOrBloc).map(resolveBloc);
|
|
2844
|
+
const tracker = createState();
|
|
2845
|
+
const proxiedInstances = instances.map((inst) => createTrackingProxy(inst, tracker));
|
|
2846
|
+
const externalDepsManager = new DependencyManager();
|
|
2847
|
+
let disposed = false;
|
|
2848
|
+
const primarySubscriptions = [];
|
|
2849
|
+
const cleanup = () => {
|
|
2850
|
+
if (disposed) return;
|
|
2851
|
+
disposed = true;
|
|
2852
|
+
primarySubscriptions.forEach((unsub) => unsub());
|
|
2853
|
+
externalDepsManager.cleanup();
|
|
2854
|
+
};
|
|
2855
|
+
const runCallback = () => {
|
|
2856
|
+
if (disposed) return;
|
|
2857
|
+
startTracking(tracker);
|
|
2858
|
+
let result;
|
|
2859
|
+
try {
|
|
2860
|
+
result = callback(isSingle ? proxiedInstances[0] : proxiedInstances);
|
|
2861
|
+
} finally {
|
|
2862
|
+
const externalDeps = /* @__PURE__ */ new Set();
|
|
2863
|
+
for (const inst of instances) {
|
|
2864
|
+
const deps = stopTracking(tracker, inst);
|
|
2865
|
+
for (const dep of deps) externalDeps.add(dep);
|
|
2866
|
+
}
|
|
2867
|
+
for (const dep of tracker.getterState.externalDependencies) externalDeps.add(dep);
|
|
2868
|
+
for (const inst of instances) externalDeps.delete(inst);
|
|
2869
|
+
externalDepsManager.sync(externalDeps, runCallback);
|
|
2870
|
+
}
|
|
2871
|
+
if (result === STOP) cleanup();
|
|
2872
|
+
};
|
|
2873
|
+
const onChange = () => {
|
|
2874
|
+
if (disposed) return;
|
|
2875
|
+
runCallback();
|
|
2876
|
+
};
|
|
2877
|
+
for (const inst of instances) primarySubscriptions.push(inst.subscribe(onChange));
|
|
2878
|
+
runCallback();
|
|
2879
|
+
return cleanup;
|
|
2880
|
+
}
|
|
2881
|
+
const watch = Object.assign(watchImpl, { STOP });
|
|
2882
|
+
|
|
2074
2883
|
//#endregion
|
|
2075
2884
|
exports.BLAC_DEFAULTS = BLAC_DEFAULTS;
|
|
2076
2885
|
exports.BLAC_ERROR_PREFIX = BLAC_ERROR_PREFIX;
|
|
2077
2886
|
exports.BLAC_ID_PATTERNS = BLAC_ID_PATTERNS;
|
|
2078
2887
|
exports.BLAC_STATIC_PROPS = BLAC_STATIC_PROPS;
|
|
2079
2888
|
exports.Cubit = Cubit;
|
|
2080
|
-
exports.
|
|
2889
|
+
exports.DependencyManager = DependencyManager;
|
|
2890
|
+
exports.ExternalDepsManager = ExternalDepsManager;
|
|
2081
2891
|
exports.LogLevel = LogLevel;
|
|
2082
2892
|
exports.PluginManager = PluginManager;
|
|
2893
|
+
exports.STATELESS_MARKER = STATELESS_MARKER;
|
|
2083
2894
|
exports.StateContainer = StateContainer;
|
|
2084
2895
|
exports.StateContainerRegistry = StateContainerRegistry;
|
|
2896
|
+
exports.StatelessCubit = StatelessCubit;
|
|
2897
|
+
exports.StatelessVertex = StatelessVertex;
|
|
2898
|
+
exports.TrackedContext = TrackedContext;
|
|
2085
2899
|
exports.Vertex = Vertex;
|
|
2900
|
+
exports.WaitUntilAbortedError = WaitUntilAbortedError;
|
|
2901
|
+
exports.WaitUntilDisposedError = WaitUntilDisposedError;
|
|
2902
|
+
exports.WaitUntilTimeoutError = WaitUntilTimeoutError;
|
|
2086
2903
|
exports.__resetIdCounters = __resetIdCounters;
|
|
2904
|
+
exports.acquire = acquire;
|
|
2905
|
+
exports.autoTrackInit = autoTrackInit;
|
|
2906
|
+
exports.autoTrackSnapshot = autoTrackSnapshot;
|
|
2907
|
+
exports.autoTrackSubscribe = autoTrackSubscribe;
|
|
2087
2908
|
exports.blac = blac;
|
|
2088
|
-
exports.
|
|
2909
|
+
exports.borrow = borrow;
|
|
2910
|
+
exports.borrowSafe = borrowSafe;
|
|
2911
|
+
exports.capturePaths = capturePaths;
|
|
2912
|
+
exports.clear = clear;
|
|
2089
2913
|
exports.clearActiveTracker = clearActiveTracker;
|
|
2914
|
+
exports.clearAll = clearAll;
|
|
2090
2915
|
exports.clearExternalDependencies = clearExternalDependencies;
|
|
2091
2916
|
exports.commitTrackedGetters = commitTrackedGetters;
|
|
2917
|
+
exports.configureBlac = configureBlac;
|
|
2092
2918
|
exports.configureLogger = configureLogger;
|
|
2093
2919
|
exports.createArrayProxy = createArrayProxy;
|
|
2094
|
-
exports.createAutoTrackSnapshot = createAutoTrackSnapshot;
|
|
2095
|
-
exports.createAutoTrackSubscribe = createAutoTrackSubscribe;
|
|
2096
2920
|
exports.createBlocProxy = createBlocProxy;
|
|
2097
|
-
exports.
|
|
2921
|
+
exports.createDependencyProxy = createDependencyProxy;
|
|
2922
|
+
exports.createDependencyState = createDependencyState;
|
|
2923
|
+
exports.createForTarget = createForTarget;
|
|
2924
|
+
exports.createGetterState = createGetterState;
|
|
2098
2925
|
exports.createIdGenerator = createIdGenerator;
|
|
2926
|
+
exports.createInternal = createInternal;
|
|
2099
2927
|
exports.createLogger = createLogger;
|
|
2100
|
-
exports.createManualDepsSnapshot = createManualDepsSnapshot;
|
|
2101
|
-
exports.createManualDepsSubscribe = createManualDepsSubscribe;
|
|
2102
|
-
exports.createNoTrackSnapshot = createNoTrackSnapshot;
|
|
2103
|
-
exports.createNoTrackSubscribe = createNoTrackSubscribe;
|
|
2104
2928
|
exports.createPluginManager = createPluginManager;
|
|
2105
|
-
exports.
|
|
2106
|
-
exports.
|
|
2107
|
-
exports.
|
|
2108
|
-
exports.
|
|
2109
|
-
exports.createTrackerState = createTrackerState;
|
|
2929
|
+
exports.createProxyState = createProxyState;
|
|
2930
|
+
exports.createTrackedContext = createTrackedContext;
|
|
2931
|
+
exports.createTrackingProxy = createTrackingProxy;
|
|
2932
|
+
exports.createTrackingProxyState = createState;
|
|
2110
2933
|
exports.debug = debug;
|
|
2111
2934
|
exports.disableGetterTracking = disableGetterTracking;
|
|
2935
|
+
exports.ensure = ensure;
|
|
2112
2936
|
exports.error = error;
|
|
2937
|
+
exports.forEach = forEach;
|
|
2113
2938
|
exports.generateId = generateId;
|
|
2114
2939
|
exports.generateIsolatedKey = generateIsolatedKey;
|
|
2115
2940
|
exports.generateSimpleId = generateSimpleId;
|
|
2116
2941
|
exports.getActiveTracker = getActiveTracker;
|
|
2942
|
+
exports.getAll = getAll;
|
|
2943
|
+
exports.getBlacConfig = getBlacConfig;
|
|
2117
2944
|
exports.getDescriptor = getDescriptor;
|
|
2118
2945
|
exports.getGetterExecutionContext = getGetterExecutionContext;
|
|
2119
2946
|
exports.getPluginManager = getPluginManager;
|
|
2947
|
+
exports.getRefCount = getRefCount;
|
|
2948
|
+
exports.getRegistry = getRegistry;
|
|
2120
2949
|
exports.getStaticProp = getStaticProp;
|
|
2950
|
+
exports.getStats = getStats;
|
|
2121
2951
|
exports.getValueAtPath = getValueAtPath;
|
|
2122
2952
|
exports.globalRegistry = globalRegistry;
|
|
2123
|
-
exports.
|
|
2953
|
+
exports.hasDependencyChanges = hasDependencyChanges;
|
|
2124
2954
|
exports.hasGetterChanges = hasGetterChanges;
|
|
2125
2955
|
exports.hasInitHook = hasInitHook;
|
|
2956
|
+
exports.hasInstance = hasInstance;
|
|
2126
2957
|
exports.hasTrackedData = hasTrackedData;
|
|
2958
|
+
exports.hasTrackingProxyChanges = hasChanges;
|
|
2127
2959
|
exports.info = info;
|
|
2128
|
-
exports.
|
|
2129
|
-
exports.initManualDepsState = initManualDepsState;
|
|
2130
|
-
exports.initNoTrackState = initNoTrackState;
|
|
2960
|
+
exports.instance = instance;
|
|
2131
2961
|
exports.invalidateRenderCache = invalidateRenderCache;
|
|
2962
|
+
exports.isDevMode = isDevMode;
|
|
2132
2963
|
exports.isExcludedFromDevTools = isExcludedFromDevTools;
|
|
2133
2964
|
exports.isGetter = isGetter;
|
|
2134
2965
|
exports.isIsolatedClass = isIsolatedClass;
|
|
2135
2966
|
exports.isIsolatedKey = isIsolatedKey;
|
|
2136
2967
|
exports.isKeepAliveClass = isKeepAliveClass;
|
|
2137
2968
|
exports.isProxyable = isProxyable;
|
|
2969
|
+
exports.isStatelessClass = isStatelessClass;
|
|
2970
|
+
exports.manualDepsInit = manualDepsInit;
|
|
2971
|
+
exports.manualDepsSnapshot = manualDepsSnapshot;
|
|
2972
|
+
exports.manualDepsSubscribe = manualDepsSubscribe;
|
|
2973
|
+
exports.noTrackInit = noTrackInit;
|
|
2974
|
+
exports.noTrackSnapshot = noTrackSnapshot;
|
|
2975
|
+
exports.noTrackSubscribe = noTrackSubscribe;
|
|
2138
2976
|
exports.parsePath = parsePath;
|
|
2139
|
-
exports.
|
|
2977
|
+
exports.register = register;
|
|
2978
|
+
exports.release = release;
|
|
2979
|
+
exports.resetBlacConfig = resetBlacConfig;
|
|
2980
|
+
exports.resetGetterState = resetGetterState;
|
|
2140
2981
|
exports.setActiveTracker = setActiveTracker;
|
|
2982
|
+
exports.setRegistry = setRegistry;
|
|
2141
2983
|
exports.shallowEqual = shallowEqual;
|
|
2142
|
-
exports.
|
|
2143
|
-
exports.
|
|
2144
|
-
exports.
|
|
2984
|
+
exports.startDependency = startDependency;
|
|
2985
|
+
exports.startProxy = startProxy;
|
|
2986
|
+
exports.startTrackingProxy = startTracking;
|
|
2987
|
+
exports.stopProxy = stopProxy;
|
|
2988
|
+
exports.stopTrackingProxy = stopTracking;
|
|
2989
|
+
exports.tracked = tracked;
|
|
2990
|
+
exports.waitUntil = waitUntil;
|
|
2145
2991
|
exports.warn = warn;
|
|
2992
|
+
exports.watch = watch;
|
|
2146
2993
|
//# sourceMappingURL=index.cjs.map
|