@blac/core 2.0.0-rc.13 → 2.0.0-rc.14

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.js CHANGED
@@ -275,6 +275,8 @@ var PluginManager = class {
275
275
  };
276
276
  /**
277
277
  * Create a plugin manager instance
278
+ * @param registry - The StateContainerRegistry to monitor for lifecycle events
279
+ * @returns A new PluginManager instance
278
280
  */
279
281
  function createPluginManager(registry) {
280
282
  return new PluginManager(registry);
@@ -526,22 +528,28 @@ function getStaticProp(Type, propName, defaultValue) {
526
528
  return Type[propName] ?? defaultValue;
527
529
  }
528
530
  /**
529
- * Check if a class is marked as isolated
530
- * Isolated classes create separate instances per component
531
+ * Check if a class is marked as isolated.
532
+ * Isolated classes create separate instances per component.
533
+ * @param Type - The class constructor to check
534
+ * @returns true if the class has `static isolated = true`
531
535
  */
532
536
  function isIsolatedClass(Type) {
533
537
  return getStaticProp(Type, BLAC_STATIC_PROPS.ISOLATED) === true;
534
538
  }
535
539
  /**
536
- * Check if a class is marked as keepAlive
537
- * KeepAlive classes are never auto-disposed when ref count reaches 0
540
+ * Check if a class is marked as keepAlive.
541
+ * KeepAlive classes are never auto-disposed when ref count reaches 0.
542
+ * @param Type - The class constructor to check
543
+ * @returns true if the class has `static keepAlive = true`
538
544
  */
539
545
  function isKeepAliveClass(Type) {
540
546
  return getStaticProp(Type, BLAC_STATIC_PROPS.KEEP_ALIVE) === true;
541
547
  }
542
548
  /**
543
- * Check if a class should be excluded from DevTools
544
- * Used to prevent infinite loops when DevTools tracks itself
549
+ * Check if a class should be excluded from DevTools.
550
+ * Used to prevent infinite loops when DevTools tracks itself.
551
+ * @param Type - The class constructor to check
552
+ * @returns true if the class has `static __excludeFromDevTools = true`
545
553
  */
546
554
  function isExcludedFromDevTools(Type) {
547
555
  return getStaticProp(Type, BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS) === true;
@@ -603,97 +611,111 @@ var StateContainerRegistry = class {
603
611
  getInstancesMap(Type) {
604
612
  return this.instancesByConstructor.get(Type) || /* @__PURE__ */ new Map();
605
613
  }
614
+ trackExecutionContext(instance) {
615
+ const context = getGetterExecutionContext();
616
+ if (context.tracker && context.currentBloc && context.currentBloc !== instance) context.tracker.externalDependencies.add(instance);
617
+ }
606
618
  /**
607
- * Resolve an instance with ref counting (ownership semantics)
619
+ * Resolve an instance with ref counting (ownership semantics).
620
+ * Creates a new instance if one doesn't exist, or returns existing and increments ref count.
621
+ * @param Type - The StateContainer class constructor
622
+ * @param instanceKey - Instance key (defaults to 'default')
623
+ * @param options - Resolution options
624
+ * @param options.canCreate - Whether to create new instance if not found (default: true)
625
+ * @param options.countRef - Whether to increment ref count (default: true)
626
+ * @param options.props - Props to pass to constructor if creating new instance
627
+ * @param options.trackExecutionContext - Whether to track cross-bloc dependency (default: false)
628
+ * @returns The state container instance
608
629
  */
609
- resolve(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, constructorArgs) {
630
+ resolve(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, options = {}) {
631
+ const { canCreate = true, countRef = true, props, trackExecutionContext = false } = options;
610
632
  const registryConfig = this.typeConfigs.get(Type.name);
611
633
  const isolated = isIsolatedClass(Type) || registryConfig?.isolated === true;
612
634
  const config = { instanceId: instanceKey };
635
+ if (isolated && !canCreate) throw new Error(`${BLAC_ERROR_PREFIX} Cannot get isolated instance "${instanceKey}" of ${Type.name} when creation is disabled.`);
613
636
  if (isolated) {
614
- const instance$1 = new Type(constructorArgs);
637
+ const instance$1 = new Type(props);
615
638
  instance$1.initConfig(config);
616
639
  this.registerType(Type);
640
+ if (trackExecutionContext) this.trackExecutionContext(instance$1);
617
641
  return instance$1;
618
642
  }
619
643
  const instances = this.ensureInstancesMap(Type);
620
644
  const entry = instances.get(instanceKey);
645
+ if (entry && (countRef || entry.refCount === 0)) entry.refCount++;
621
646
  if (entry) {
622
- entry.refCount++;
647
+ if (trackExecutionContext) this.trackExecutionContext(entry.instance);
623
648
  return entry.instance;
624
649
  }
625
- const instance = new Type(constructorArgs);
650
+ if (!canCreate) throw new Error(`${BLAC_ERROR_PREFIX} ${Type.name} instance "${instanceKey}" not found and creation is disabled.`);
651
+ const instance = new Type(props);
626
652
  instance.initConfig(config);
627
653
  instances.set(instanceKey, {
628
654
  instance,
629
655
  refCount: 1
630
656
  });
631
657
  this.registerType(Type);
658
+ if (trackExecutionContext) this.trackExecutionContext(instance);
632
659
  return instance;
633
660
  }
634
661
  /**
635
- * Get an existing instance without ref counting (borrowing semantics)
662
+ * Get an existing instance without incrementing ref count (borrowing semantics).
663
+ * Tracks cross-bloc dependency for reactive updates.
664
+ * @param Type - The StateContainer class constructor
665
+ * @param instanceKey - Instance key (defaults to 'default')
666
+ * @returns The state container instance
636
667
  * @throws Error if instance doesn't exist
637
668
  */
638
669
  get(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
639
- const entry = this.ensureInstancesMap(Type).get(instanceKey);
640
- if (!entry) throw new Error(`${BLAC_ERROR_PREFIX} ${Type.name} instance "${instanceKey}" not found.\nUse .resolve() to create and claim ownership, or .getSafe() for conditional access.`);
641
- const context = getGetterExecutionContext();
642
- if (context.tracker && context.currentBloc && context.currentBloc !== entry.instance) context.tracker.externalDependencies.add(entry.instance);
643
- return entry.instance;
670
+ return this.resolve(Type, instanceKey, {
671
+ canCreate: false,
672
+ trackExecutionContext: true
673
+ });
644
674
  }
645
675
  /**
646
- * Safely get an existing instance (borrowing semantics with error handling)
647
- * Returns discriminated union for type-safe conditional access
676
+ * Safely get an existing instance (borrowing semantics with error handling).
677
+ * Returns discriminated union for type-safe conditional access.
678
+ * @param Type - The StateContainer class constructor
679
+ * @param instanceKey - Instance key (defaults to 'default')
680
+ * @returns Discriminated union with either the instance or an error
648
681
  */
649
682
  getSafe(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
650
- const entry = this.ensureInstancesMap(Type).get(instanceKey);
651
- if (!entry) return {
652
- error: /* @__PURE__ */ new Error(`${BLAC_ERROR_PREFIX} ${Type.name} instance "${instanceKey}" not found`),
653
- instance: null
654
- };
655
- const context = getGetterExecutionContext();
656
- if (context.tracker && context.currentBloc && context.currentBloc !== entry.instance) context.tracker.externalDependencies.add(entry.instance);
657
- return {
658
- error: null,
659
- instance: entry.instance
660
- };
683
+ try {
684
+ return {
685
+ error: null,
686
+ instance: this.get(Type, instanceKey)
687
+ };
688
+ } catch (error$1) {
689
+ return {
690
+ error: error$1,
691
+ instance: null
692
+ };
693
+ }
661
694
  }
662
695
  /**
663
- * Connect to an instance with borrowing semantics (for B2B communication)
696
+ * Connect to an instance with borrowing semantics (for B2B communication).
664
697
  * Gets existing instance OR creates it if it doesn't exist, without incrementing ref count.
665
698
  * Tracks cross-bloc dependency for reactive updates.
666
699
  *
667
700
  * Use this in bloc-to-bloc communication when you need to ensure an instance exists
668
701
  * but don't want to claim ownership (no ref count increment).
669
- *
670
- * @param Type - The bloc class constructor
671
- * @param instanceKey - Optional instance key (defaults to 'default')
672
- * @param constructorArgs - Constructor arguments (only used if creating new instance)
673
- * @returns The bloc instance
702
+ * @param Type - The StateContainer class constructor
703
+ * @param instanceKey - Instance key (defaults to 'default')
704
+ * @returns The state container instance
674
705
  */
675
- connect(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, constructorArgs) {
676
- const registryConfig = this.typeConfigs.get(Type.name);
677
- if (isIsolatedClass(Type) || registryConfig?.isolated === true) throw new Error(`${BLAC_ERROR_PREFIX} Cannot use .connect() with isolated bloc "${Type.name}".\nIsolated blocs are component-scoped. Use .resolve() in components instead.`);
678
- const instances = this.ensureInstancesMap(Type);
679
- let entry = instances.get(instanceKey);
680
- if (!entry) {
681
- const instance = new Type(constructorArgs);
682
- const config = { instanceId: instanceKey };
683
- instance.initConfig(config);
684
- entry = {
685
- instance,
686
- refCount: 1
687
- };
688
- instances.set(instanceKey, entry);
689
- this.registerType(Type);
690
- }
691
- const context = getGetterExecutionContext();
692
- if (context.tracker && context.currentBloc && context.currentBloc !== entry.instance) context.tracker.externalDependencies.add(entry.instance);
693
- return entry.instance;
706
+ connect(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
707
+ return this.resolve(Type, instanceKey, {
708
+ canCreate: true,
709
+ countRef: false,
710
+ trackExecutionContext: true
711
+ });
694
712
  }
695
713
  /**
696
- * Release a reference to an instance
714
+ * Release a reference to an instance.
715
+ * Decrements ref count and disposes when it reaches 0 (unless keepAlive).
716
+ * @param Type - The StateContainer class constructor
717
+ * @param instanceKey - Instance key (defaults to 'default')
718
+ * @param forceDispose - Force immediate disposal regardless of ref count
697
719
  */
698
720
  release(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, forceDispose = false) {
699
721
  const instances = this.ensureInstancesMap(Type);
@@ -712,7 +734,9 @@ var StateContainerRegistry = class {
712
734
  }
713
735
  }
714
736
  /**
715
- * Get all instances of a specific type
737
+ * Get all instances of a specific type.
738
+ * @param Type - The StateContainer class constructor
739
+ * @returns Array of all instances
716
740
  */
717
741
  getAll(Type) {
718
742
  const instances = this.ensureInstancesMap(Type);
@@ -721,7 +745,10 @@ var StateContainerRegistry = class {
721
745
  return result;
722
746
  }
723
747
  /**
724
- * Safely iterate over all instances of a type
748
+ * Safely iterate over all instances of a type.
749
+ * Skips disposed instances and catches callback errors.
750
+ * @param Type - The StateContainer class constructor
751
+ * @param callback - Function to call for each instance
725
752
  */
726
753
  forEach(Type, callback) {
727
754
  const instances = this.ensureInstancesMap(Type);
@@ -735,7 +762,8 @@ var StateContainerRegistry = class {
735
762
  }
736
763
  }
737
764
  /**
738
- * Clear all instances of a specific type
765
+ * Clear all instances of a specific type (disposes them).
766
+ * @param Type - The StateContainer class constructor
739
767
  */
740
768
  clear(Type) {
741
769
  const instances = this.ensureInstancesMap(Type);
@@ -743,13 +771,19 @@ var StateContainerRegistry = class {
743
771
  instances.clear();
744
772
  }
745
773
  /**
746
- * Get reference count for an instance
774
+ * Get reference count for an instance.
775
+ * @param Type - The StateContainer class constructor
776
+ * @param instanceKey - Instance key (defaults to 'default')
777
+ * @returns Current ref count (0 if instance doesn't exist)
747
778
  */
748
779
  getRefCount(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
749
780
  return this.ensureInstancesMap(Type).get(instanceKey)?.refCount ?? 0;
750
781
  }
751
782
  /**
752
- * Check if an instance exists
783
+ * Check if an instance exists.
784
+ * @param Type - The StateContainer class constructor
785
+ * @param instanceKey - Instance key (defaults to 'default')
786
+ * @returns true if instance exists
753
787
  */
754
788
  hasInstance(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
755
789
  return this.ensureInstancesMap(Type).has(instanceKey);
@@ -766,7 +800,8 @@ var StateContainerRegistry = class {
766
800
  this.typeConfigs.clear();
767
801
  }
768
802
  /**
769
- * Get registry statistics (for debugging)
803
+ * Get registry statistics for debugging.
804
+ * @returns Object with registeredTypes, totalInstances, and typeBreakdown
770
805
  */
771
806
  getStats() {
772
807
  const typeBreakdown = {};
@@ -784,7 +819,8 @@ var StateContainerRegistry = class {
784
819
  };
785
820
  }
786
821
  /**
787
- * Get all registered types (for plugin system)
822
+ * Get all registered types (for plugin system).
823
+ * @returns Array of all registered StateContainer class constructors
788
824
  */
789
825
  getTypes() {
790
826
  return Array.from(this.types);
@@ -889,11 +925,11 @@ var StateContainer = class StateContainer {
889
925
  * @template S - Optional state type override for generic StateContainers
890
926
  * @template T - The StateContainer type (inferred from class)
891
927
  * @param instanceKey - Optional instance key (defaults to 'default')
892
- * @param constructorArgs - Arguments to pass to constructor if creating new instance
928
+ * @param options - Resolution options (canCreate, countRef, props, trackExecutionContext)
893
929
  * @returns The state container instance
894
930
  */
895
- static resolve(instanceKey, constructorArgs) {
896
- return StateContainer._registry.resolve(this, instanceKey, constructorArgs);
931
+ static resolve(instanceKey, options) {
932
+ return StateContainer._registry.resolve(this, instanceKey, options);
897
933
  }
898
934
  /**
899
935
  * Get an existing instance without incrementing ref count (borrowing semantics).
@@ -919,14 +955,14 @@ var StateContainer = class StateContainer {
919
955
  /**
920
956
  * Connect to an instance for bloc-to-bloc communication (borrowing semantics).
921
957
  * Gets or creates instance without incrementing ref count.
958
+ * Tracks cross-bloc dependency for reactive updates.
922
959
  * @template S - Optional state type override for generic StateContainers
923
960
  * @template T - The StateContainer type (inferred from class)
924
961
  * @param instanceKey - Optional instance key (defaults to 'default')
925
- * @param constructorArgs - Arguments to pass to constructor if creating new instance
926
962
  * @returns The state container instance
927
963
  */
928
- static connect(instanceKey, constructorArgs) {
929
- return StateContainer._registry.connect(this, instanceKey, constructorArgs);
964
+ static connect(instanceKey) {
965
+ return StateContainer._registry.connect(this, instanceKey);
930
966
  }
931
967
  /**
932
968
  * Release a reference to an instance.