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

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 CHANGED
@@ -39,10 +39,8 @@ function createIdGenerator(prefix) {
39
39
  * @returns Branded ID string
40
40
  *
41
41
  * @example
42
- * ```ts
43
42
  * const id = generateId('sub');
44
43
  * // Returns: "sub:1698765432100_1_a3k9d7f2q"
45
- * ```
46
44
  */
47
45
  function generateId(prefix) {
48
46
  const counter = (globalCounters.get(prefix) ?? 0) + 1;
@@ -97,12 +95,32 @@ function isIsolatedKey(key) {
97
95
 
98
96
  //#endregion
99
97
  //#region src/plugin/PluginManager.ts
98
+ /**
99
+ * Manages plugin lifecycle for the BlaC state management system.
100
+ * Plugins receive notifications about state container lifecycle events.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const manager = createPluginManager(registry);
105
+ * manager.install(myPlugin, { environment: 'development' });
106
+ * ```
107
+ */
100
108
  var PluginManager = class {
109
+ /**
110
+ * Create a new PluginManager
111
+ * @param registry - The StateContainerRegistry to monitor for lifecycle events
112
+ */
101
113
  constructor(registry) {
102
114
  this.plugins = /* @__PURE__ */ new Map();
103
115
  this.registry = registry;
104
116
  this.setupLifecycleHooks();
105
117
  }
118
+ /**
119
+ * Install a plugin with optional configuration
120
+ * @param plugin - The plugin to install
121
+ * @param config - Optional plugin configuration
122
+ * @throws Error if plugin is already installed
123
+ */
106
124
  install(plugin, config = {}) {
107
125
  const effectiveConfig = {
108
126
  enabled: true,
@@ -129,6 +147,11 @@ var PluginManager = class {
129
147
  }
130
148
  console.log(`[BlaC] Plugin "${plugin.name}" v${plugin.version} installed`);
131
149
  }
150
+ /**
151
+ * Uninstall a plugin by name
152
+ * @param pluginName - The name of the plugin to uninstall
153
+ * @throws Error if plugin is not installed
154
+ */
132
155
  uninstall(pluginName) {
133
156
  const installed = this.plugins.get(pluginName);
134
157
  if (!installed) throw new Error(`Plugin "${pluginName}" is not installed`);
@@ -140,15 +163,32 @@ var PluginManager = class {
140
163
  this.plugins.delete(pluginName);
141
164
  console.log(`[BlaC] Plugin "${pluginName}" uninstalled`);
142
165
  }
166
+ /**
167
+ * Get an installed plugin by name
168
+ * @param pluginName - The name of the plugin to retrieve
169
+ * @returns The plugin instance or undefined if not found
170
+ */
143
171
  getPlugin(pluginName) {
144
172
  return this.plugins.get(pluginName)?.plugin;
145
173
  }
174
+ /**
175
+ * Get all installed plugins
176
+ * @returns Array of all installed plugins
177
+ */
146
178
  getAllPlugins() {
147
179
  return Array.from(this.plugins.values()).map((p) => p.plugin);
148
180
  }
181
+ /**
182
+ * Check if a plugin is installed
183
+ * @param pluginName - The name of the plugin to check
184
+ * @returns true if the plugin is installed
185
+ */
149
186
  hasPlugin(pluginName) {
150
187
  return this.plugins.has(pluginName);
151
188
  }
189
+ /**
190
+ * Uninstall all plugins
191
+ */
152
192
  clear() {
153
193
  for (const name of this.plugins.keys()) this.uninstall(name);
154
194
  }
@@ -295,9 +335,15 @@ const getterExecutionContext = {
295
335
  visitedBlocs: /* @__PURE__ */ new Set()
296
336
  };
297
337
  const MAX_GETTER_DEPTH = BLAC_DEFAULTS.MAX_GETTER_DEPTH;
338
+ /**
339
+ * @internal
340
+ */
298
341
  function getGetterExecutionContext() {
299
342
  return getterExecutionContext;
300
343
  }
344
+ /**
345
+ * @internal
346
+ */
301
347
  function getDescriptor(obj, prop) {
302
348
  const constructor = obj.constructor;
303
349
  let constructorCache = descriptorCache.get(constructor);
@@ -316,9 +362,15 @@ function getDescriptor(obj, prop) {
316
362
  constructorCache.set(prop, descriptor);
317
363
  return descriptor;
318
364
  }
365
+ /**
366
+ * @internal
367
+ */
319
368
  function isGetter(obj, prop) {
320
369
  return getDescriptor(obj, prop)?.get !== void 0;
321
370
  }
371
+ /**
372
+ * @internal
373
+ */
322
374
  function createGetterTracker() {
323
375
  return {
324
376
  trackedValues: /* @__PURE__ */ new Map(),
@@ -330,19 +382,34 @@ function createGetterTracker() {
330
382
  externalDependencies: /* @__PURE__ */ new Set()
331
383
  };
332
384
  }
385
+ /**
386
+ * @internal
387
+ */
333
388
  function setActiveTracker(bloc, tracker) {
334
389
  activeTrackerMap.set(bloc, tracker);
335
390
  }
391
+ /**
392
+ * @internal
393
+ */
336
394
  function clearActiveTracker(bloc) {
337
395
  activeTrackerMap.delete(bloc);
338
396
  }
397
+ /**
398
+ * @internal
399
+ */
339
400
  function getActiveTracker(bloc) {
340
401
  return activeTrackerMap.get(bloc);
341
402
  }
403
+ /**
404
+ * @internal
405
+ */
342
406
  function commitTrackedGetters(tracker) {
343
407
  if (tracker.currentlyAccessing.size > 0) tracker.trackedGetters = new Set(tracker.currentlyAccessing);
344
408
  tracker.currentlyAccessing.clear();
345
409
  }
410
+ /**
411
+ * @internal
412
+ */
346
413
  function createBlocProxy(bloc) {
347
414
  const cached = blocProxyCache.get(bloc);
348
415
  if (cached) return cached;
@@ -392,6 +459,9 @@ function createBlocProxy(bloc) {
392
459
  blocProxyCache.set(bloc, proxy);
393
460
  return proxy;
394
461
  }
462
+ /**
463
+ * @internal
464
+ */
395
465
  function hasGetterChanges(bloc, tracker) {
396
466
  if (!tracker || tracker.trackedGetters.size === 0) return false;
397
467
  tracker.renderCache.clear();
@@ -414,12 +484,21 @@ function hasGetterChanges(bloc, tracker) {
414
484
  tracker.cacheValid = true;
415
485
  return hasAnyChange;
416
486
  }
487
+ /**
488
+ * @internal
489
+ */
417
490
  function invalidateRenderCache(tracker) {
418
491
  tracker.cacheValid = false;
419
492
  }
493
+ /**
494
+ * @internal
495
+ */
420
496
  function clearExternalDependencies(tracker) {
421
497
  tracker.externalDependencies.clear();
422
498
  }
499
+ /**
500
+ * @internal
501
+ */
423
502
  function resetGetterTracker(tracker) {
424
503
  tracker.trackedValues.clear();
425
504
  tracker.currentlyAccessing.clear();
@@ -471,6 +550,19 @@ function isExcludedFromDevTools(Type) {
471
550
 
472
551
  //#endregion
473
552
  //#region src/core/StateContainerRegistry.ts
553
+ /**
554
+ * Central registry for managing StateContainer instances.
555
+ * Handles instance lifecycle, ref counting, and lifecycle event emission.
556
+ *
557
+ * @example
558
+ * ```ts
559
+ * const registry = new StateContainerRegistry();
560
+ * const instance = registry.resolve(MyBloc);
561
+ * registry.on('stateChanged', (container, prev, next) => {
562
+ * console.log('State changed:', prev, '->', next);
563
+ * });
564
+ * ```
565
+ */
474
566
  var StateContainerRegistry = class {
475
567
  constructor() {
476
568
  this.instancesByConstructor = /* @__PURE__ */ new WeakMap();
@@ -478,9 +570,19 @@ var StateContainerRegistry = class {
478
570
  this.typeConfigs = /* @__PURE__ */ new Map();
479
571
  this.listeners = /* @__PURE__ */ new Map();
480
572
  }
573
+ /**
574
+ * Register a type for lifecycle event tracking
575
+ * @param constructor - The StateContainer class constructor
576
+ */
481
577
  registerType(constructor) {
482
578
  this.types.add(constructor);
483
579
  }
580
+ /**
581
+ * Register a StateContainer class with configuration
582
+ * @param constructor - The StateContainer class constructor
583
+ * @param isolated - Whether instances should be isolated (component-scoped)
584
+ * @throws Error if type is already registered
585
+ */
484
586
  register(constructor, isolated = false) {
485
587
  const className = constructor.name;
486
588
  if (!isolated && isIsolatedClass(constructor)) isolated = true;
@@ -733,6 +835,26 @@ function getPluginManager() {
733
835
 
734
836
  //#endregion
735
837
  //#region src/core/StateContainer.ts
838
+ /**
839
+ * Abstract base class for all state containers in BlaC.
840
+ * Provides lifecycle management, subscription handling, ref counting,
841
+ * and integration with the global registry.
842
+ *
843
+ * @template S - State type managed by this container
844
+ * @template P - Props type passed to the container (optional)
845
+ *
846
+ * @example
847
+ * ```ts
848
+ * class CounterBloc extends StateContainer<number> {
849
+ * constructor() {
850
+ * super(0);
851
+ * }
852
+ * increment() {
853
+ * this.emit(this.state + 1);
854
+ * }
855
+ * }
856
+ * ```
857
+ */
736
858
  var StateContainer = class StateContainer {
737
859
  static {
738
860
  this.__excludeFromDevTools = false;
@@ -740,52 +862,132 @@ var StateContainer = class StateContainer {
740
862
  static {
741
863
  this._registry = globalRegistry;
742
864
  }
865
+ /**
866
+ * Get the global StateContainerRegistry
867
+ * @returns The registry managing all state container instances
868
+ */
743
869
  static getRegistry() {
744
870
  return StateContainer._registry;
745
871
  }
872
+ /**
873
+ * Replace the global registry (clears existing instances)
874
+ * @param registry - The new registry to use
875
+ */
746
876
  static setRegistry(registry) {
747
877
  StateContainer._registry.clearAll();
748
878
  StateContainer._registry = registry;
749
879
  }
880
+ /**
881
+ * Register this class with the global registry
882
+ * @param isolated - Whether instances should be isolated (component-scoped)
883
+ */
750
884
  static register(isolated = false) {
751
885
  StateContainer._registry.register(this, isolated);
752
886
  }
887
+ /**
888
+ * Resolve an instance with ref counting (ownership semantics).
889
+ * Creates a new instance if one doesn't exist, or returns existing and increments ref count.
890
+ * @template S - Optional state type override for generic StateContainers
891
+ * @template T - The StateContainer type (inferred from class)
892
+ * @param instanceKey - Optional instance key (defaults to 'default')
893
+ * @param constructorArgs - Arguments to pass to constructor if creating new instance
894
+ * @returns The state container instance
895
+ */
753
896
  static resolve(instanceKey, constructorArgs) {
754
897
  return StateContainer._registry.resolve(this, instanceKey, constructorArgs);
755
898
  }
899
+ /**
900
+ * Get an existing instance without incrementing ref count (borrowing semantics).
901
+ * @template S - Optional state type override for generic StateContainers
902
+ * @template T - The StateContainer type (inferred from class)
903
+ * @param instanceKey - Optional instance key (defaults to 'default')
904
+ * @returns The state container instance
905
+ * @throws Error if instance doesn't exist
906
+ */
756
907
  static get(instanceKey) {
757
908
  return StateContainer._registry.get(this, instanceKey);
758
909
  }
910
+ /**
911
+ * Safely get an existing instance with error handling.
912
+ * @template S - Optional state type override for generic StateContainers
913
+ * @template T - The StateContainer type (inferred from class)
914
+ * @param instanceKey - Optional instance key (defaults to 'default')
915
+ * @returns Discriminated union with either the instance or an error
916
+ */
759
917
  static getSafe(instanceKey) {
760
918
  return StateContainer._registry.getSafe(this, instanceKey);
761
919
  }
920
+ /**
921
+ * Connect to an instance for bloc-to-bloc communication (borrowing semantics).
922
+ * Gets or creates instance without incrementing ref count.
923
+ * @template S - Optional state type override for generic StateContainers
924
+ * @template T - The StateContainer type (inferred from class)
925
+ * @param instanceKey - Optional instance key (defaults to 'default')
926
+ * @param constructorArgs - Arguments to pass to constructor if creating new instance
927
+ * @returns The state container instance
928
+ */
762
929
  static connect(instanceKey, constructorArgs) {
763
930
  return StateContainer._registry.connect(this, instanceKey, constructorArgs);
764
931
  }
932
+ /**
933
+ * Release a reference to an instance.
934
+ * Decrements ref count and disposes when it reaches 0 (unless keepAlive).
935
+ * @param instanceKey - Optional instance key (defaults to 'default')
936
+ * @param forceDispose - Force immediate disposal regardless of ref count
937
+ */
765
938
  static release(instanceKey, forceDispose = false) {
766
939
  StateContainer._registry.release(this, instanceKey, forceDispose);
767
940
  }
941
+ /**
942
+ * Get all instances of this class
943
+ * @returns Array of all instances
944
+ */
768
945
  static getAll() {
769
946
  return StateContainer._registry.getAll(this);
770
947
  }
948
+ /**
949
+ * Iterate over all instances of this class
950
+ * @param callback - Function to call for each instance
951
+ */
771
952
  static forEach(callback) {
772
953
  StateContainer._registry.forEach(this, callback);
773
954
  }
955
+ /**
956
+ * Clear all instances of this class (disposes them)
957
+ */
774
958
  static clear() {
775
959
  StateContainer._registry.clear(this);
776
960
  }
961
+ /**
962
+ * Clear all instances from all registered types
963
+ */
777
964
  static clearAllInstances() {
778
965
  StateContainer._registry.clearAll();
779
966
  }
967
+ /**
968
+ * Get registry statistics for debugging
969
+ * @returns Object with registeredTypes, totalInstances, and typeBreakdown
970
+ */
780
971
  static getStats() {
781
972
  return StateContainer._registry.getStats();
782
973
  }
974
+ /**
975
+ * Get reference count for an instance
976
+ * @param instanceKey - Optional instance key (defaults to 'default')
977
+ * @returns Current ref count (0 if instance doesn't exist)
978
+ */
783
979
  static getRefCount(instanceKey) {
784
980
  return StateContainer._registry.getRefCount(this, instanceKey);
785
981
  }
982
+ /**
983
+ * Check if an instance exists
984
+ * @param instanceKey - Optional instance key (defaults to 'default')
985
+ * @returns true if instance exists
986
+ */
786
987
  static hasInstance(instanceKey) {
787
988
  return StateContainer._registry.hasInstance(this, instanceKey);
788
989
  }
990
+ /** Current props value passed to this container */
789
991
  get props() {
790
992
  return this._props;
791
993
  }
@@ -813,6 +1015,11 @@ var StateContainer = class StateContainer {
813
1015
  };
814
1016
  this._state = initialState;
815
1017
  }
1018
+ /**
1019
+ * Initialize configuration for this instance.
1020
+ * Called by the registry after construction.
1021
+ * @param config - Configuration options
1022
+ */
816
1023
  initConfig(config) {
817
1024
  this.config = { ...config };
818
1025
  this.name = this.config.name || this.constructor.name;
@@ -820,17 +1027,28 @@ var StateContainer = class StateContainer {
820
1027
  this.instanceId = generateSimpleId(this.constructor.name, this.config.instanceId);
821
1028
  StateContainer._registry.emit("created", this);
822
1029
  }
1030
+ /** Current state value */
823
1031
  get state() {
824
1032
  return this._state;
825
1033
  }
1034
+ /** Whether this instance has been disposed */
826
1035
  get isDisposed() {
827
1036
  return this._disposed;
828
1037
  }
1038
+ /**
1039
+ * Subscribe to state changes
1040
+ * @param listener - Function called when state changes
1041
+ * @returns Unsubscribe function
1042
+ */
829
1043
  subscribe(listener) {
830
1044
  if (this._disposed) throw new Error(`Cannot subscribe to disposed container ${this.name}`);
831
1045
  this.listeners.add(listener);
832
1046
  return () => this.listeners.delete(listener);
833
1047
  }
1048
+ /**
1049
+ * Dispose this instance and clean up resources.
1050
+ * Clears all listeners and emits the 'dispose' system event.
1051
+ */
834
1052
  dispose() {
835
1053
  if (this._disposed) return;
836
1054
  if (this.debug) console.log(`[${this.name}] Disposing...`);
@@ -841,6 +1059,11 @@ var StateContainer = class StateContainer {
841
1059
  StateContainer._registry.emit("disposed", this);
842
1060
  if (this.debug) console.log(`[${this.name}] Disposed successfully`);
843
1061
  }
1062
+ /**
1063
+ * Emit a new state value and notify all listeners.
1064
+ * @param newState - The new state value
1065
+ * @protected
1066
+ */
844
1067
  emit(newState) {
845
1068
  if (this._disposed) throw new Error(`Cannot emit state from disposed container ${this.name}`);
846
1069
  if (this._state === newState) return;
@@ -900,6 +1123,11 @@ var StateContainer = class StateContainer {
900
1123
  if (segments.length > 3) path = segments.slice(-3).join("/");
901
1124
  return path;
902
1125
  }
1126
+ /**
1127
+ * Update state using a transform function.
1128
+ * @param updater - Function that receives current state and returns new state
1129
+ * @protected
1130
+ */
903
1131
  update(updater) {
904
1132
  if (this._disposed) throw new Error(`Cannot update state from disposed container ${this.name}`);
905
1133
  this.emit(updater(this._state));
@@ -913,6 +1141,11 @@ var StateContainer = class StateContainer {
913
1141
  console.error(`[${this.name}] Error in system event handler:`, error$1);
914
1142
  }
915
1143
  }
1144
+ /**
1145
+ * Update the props for this container.
1146
+ * Emits the 'propsUpdated' system event.
1147
+ * @param newProps - The new props value
1148
+ */
916
1149
  updateProps(newProps) {
917
1150
  if (this._disposed) throw new Error(`Cannot update props on disposed container ${this.name}`);
918
1151
  const previousProps = this._props;
@@ -930,6 +1163,13 @@ var StateContainer = class StateContainer {
930
1163
 
931
1164
  //#endregion
932
1165
  //#region src/core/Cubit.ts
1166
+ /**
1167
+ * Simple state container with direct state emission.
1168
+ * Extends StateContainer with public methods for emitting and updating state.
1169
+ *
1170
+ * @template S - State type
1171
+ * @template P - Props type (optional)
1172
+ */
933
1173
  var Cubit = class extends StateContainer {
934
1174
  constructor(initialState) {
935
1175
  super(initialState);
@@ -941,89 +1181,32 @@ var Cubit = class extends StateContainer {
941
1181
  }));
942
1182
  });
943
1183
  }
1184
+ /**
1185
+ * Replace state with a new value and notify all listeners
1186
+ * @param newState - The new state value
1187
+ */
944
1188
  emit(newState) {
945
1189
  super["emit"](newState);
946
1190
  }
1191
+ /**
1192
+ * Transform current state using an updater function and emit the new state
1193
+ * @param updater - Function that receives current state and returns new state
1194
+ */
947
1195
  update(updater) {
948
1196
  super["update"](updater);
949
1197
  }
950
1198
  };
951
- var CounterCubit = class extends Cubit {
952
- constructor() {
953
- super(0);
954
- this.increment = () => {
955
- this.emit(this.state + 1);
956
- };
957
- this.decrement = () => {
958
- this.emit(this.state - 1);
959
- };
960
- this.reset = () => {
961
- this.emit(0);
962
- };
963
- this.addAmount = (amount) => {
964
- this.emit(this.state + amount);
965
- };
966
- }
967
- };
968
- var TodoCubit = class extends Cubit {
969
- static {
970
- this.keepAlive = true;
971
- }
972
- constructor() {
973
- super({
974
- todos: [],
975
- filter: "all",
976
- isLoading: false
977
- });
978
- this.nextId = 0;
979
- this.addTodo = (text) => {
980
- this.update((state) => ({
981
- ...state,
982
- todos: [...state.todos, {
983
- id: `todo-${Date.now()}-${this.nextId++}`,
984
- text,
985
- done: false
986
- }]
987
- }));
988
- };
989
- this.toggleTodo = (id) => {
990
- this.update((state) => ({
991
- ...state,
992
- todos: state.todos.map((todo) => todo.id === id ? {
993
- ...todo,
994
- done: !todo.done
995
- } : todo)
996
- }));
997
- };
998
- this.removeTodo = (id) => {
999
- this.update((state) => ({
1000
- ...state,
1001
- todos: state.todos.filter((todo) => todo.id !== id)
1002
- }));
1003
- };
1004
- this.setFilter = (filter) => {
1005
- this.patch({ filter });
1006
- };
1007
- this.setLoading = (isLoading) => {
1008
- this.patch({ isLoading });
1009
- };
1010
- }
1011
- get visibleTodos() {
1012
- const todos = this.state.todos;
1013
- switch (this.state.filter) {
1014
- case "active": return todos.filter((t) => !t.done);
1015
- case "completed": return todos.filter((t) => t.done);
1016
- case "all":
1017
- default: return todos;
1018
- }
1019
- }
1020
- get activeTodoCount() {
1021
- return this.state.todos.filter((t) => !t.done).length;
1022
- }
1023
- };
1024
1199
 
1025
1200
  //#endregion
1026
1201
  //#region src/core/Vertex.ts
1202
+ /**
1203
+ * Event-driven state container that processes events to update state.
1204
+ * Use with event handlers registered via the on() method.
1205
+ *
1206
+ * @template S - State type
1207
+ * @template E - Event type (extends BaseEvent)
1208
+ * @template P - Props type (optional)
1209
+ */
1027
1210
  var Vertex = class extends StateContainer {
1028
1211
  constructor(initialState) {
1029
1212
  super(initialState);
@@ -1077,122 +1260,22 @@ var Vertex = class extends StateContainer {
1077
1260
  this.onEventError(event, error$1);
1078
1261
  }
1079
1262
  }
1263
+ /**
1264
+ * Handle errors that occur during event processing.
1265
+ * Override this method to implement custom error handling.
1266
+ * @param _event - The event that caused the error
1267
+ * @param _error - The error that occurred
1268
+ */
1080
1269
  onEventError(_event, _error) {}
1081
1270
  };
1082
- /**
1083
- * Example: Counter Events
1084
- */
1085
- var IncrementEvent = class {
1086
- constructor(amount = 1) {
1087
- this.amount = amount;
1088
- this.type = "increment";
1089
- this.timestamp = Date.now();
1090
- }
1091
- };
1092
- var DecrementEvent = class {
1093
- constructor(amount = 1) {
1094
- this.amount = amount;
1095
- this.type = "decrement";
1096
- this.timestamp = Date.now();
1097
- }
1098
- };
1099
- var ResetEvent = class {
1100
- constructor() {
1101
- this.type = "reset";
1102
- this.timestamp = Date.now();
1103
- }
1104
- };
1105
- /**
1106
- * Example: Counter Vertex
1107
- * Demonstrates proper typing and event handling
1108
- */
1109
- var CounterVertex = class extends Vertex {
1110
- constructor() {
1111
- super(0);
1112
- this.increment = (amount = 1) => {
1113
- this.add(new IncrementEvent(amount));
1114
- };
1115
- this.decrement = (amount = 1) => {
1116
- this.add(new DecrementEvent(amount));
1117
- };
1118
- this.reset = () => {
1119
- this.add(new ResetEvent());
1120
- };
1121
- this.on(IncrementEvent, (event, emit) => {
1122
- emit(this.state + event.amount);
1123
- });
1124
- this.on(DecrementEvent, (event, emit) => {
1125
- emit(this.state - event.amount);
1126
- });
1127
- this.on(ResetEvent, (_, emit) => {
1128
- emit(0);
1129
- });
1130
- }
1131
- };
1132
- var LoginEvent = class {
1133
- constructor(email, password) {
1134
- this.email = email;
1135
- this.password = password;
1136
- this.type = "login";
1137
- this.timestamp = Date.now();
1138
- }
1139
- };
1140
- var LogoutEvent = class {
1141
- constructor() {
1142
- this.type = "logout";
1143
- this.timestamp = Date.now();
1144
- }
1145
- };
1146
- var AuthVertex = class extends Vertex {
1147
- constructor() {
1148
- super({
1149
- isAuthenticated: false,
1150
- isLoading: false,
1151
- user: null,
1152
- error: null
1153
- });
1154
- this.login = (email, password) => {
1155
- this.add(new LoginEvent(email, password));
1156
- };
1157
- this.logout = () => {
1158
- this.add(new LogoutEvent());
1159
- };
1160
- this.on(LoginEvent, (event, emit) => {
1161
- emit({
1162
- ...this.state,
1163
- isLoading: true,
1164
- error: null
1165
- });
1166
- if (event.email === "user@example.com" && event.password === "password") emit({
1167
- isAuthenticated: true,
1168
- isLoading: false,
1169
- user: {
1170
- id: "123",
1171
- name: "Test User",
1172
- email: "user@example.com"
1173
- },
1174
- error: null
1175
- });
1176
- else emit({
1177
- isAuthenticated: false,
1178
- isLoading: false,
1179
- user: null,
1180
- error: "Invalid credentials"
1181
- });
1182
- });
1183
- this.on(LogoutEvent, (_, emit) => {
1184
- emit({
1185
- isAuthenticated: false,
1186
- isLoading: false,
1187
- user: null,
1188
- error: null
1189
- });
1190
- });
1191
- }
1192
- };
1193
1271
 
1194
1272
  //#endregion
1195
1273
  //#region src/plugin/BlacPlugin.ts
1274
+ /**
1275
+ * Type guard to check if a plugin has a required onInstall hook
1276
+ * @param plugin - The plugin to check
1277
+ * @returns true if the plugin implements BlacPluginWithInit
1278
+ */
1196
1279
  function hasInitHook(plugin) {
1197
1280
  return typeof plugin.onInstall === "function";
1198
1281
  }
@@ -1205,12 +1288,16 @@ function hasInitHook(plugin) {
1205
1288
  * This module provides a functional approach to proxy-based dependency tracking.
1206
1289
  * Unlike the class-based ProxyTracker, this uses a state object pattern that's
1207
1290
  * easier to integrate with functional programming patterns and framework hooks.
1291
+ *
1292
+ * @internal
1208
1293
  */
1209
1294
  /**
1210
1295
  * Check if a value can be proxied
1211
1296
  *
1212
1297
  * Returns true for plain objects and arrays only.
1213
1298
  * Excludes built-in objects like Date, Map, Set, etc.
1299
+ *
1300
+ * @internal
1214
1301
  */
1215
1302
  function isProxyable(value) {
1216
1303
  if (typeof value !== "object" || value === null) return false;
@@ -1226,6 +1313,8 @@ function isProxyable(value) {
1226
1313
  * const proxy = createProxyForTarget(state, myObject);
1227
1314
  * // ... use proxy ...
1228
1315
  * const paths = stopProxyTracking(state);
1316
+ *
1317
+ * @internal
1229
1318
  */
1230
1319
  function createProxyTrackerState() {
1231
1320
  return {
@@ -1242,6 +1331,8 @@ function createProxyTrackerState() {
1242
1331
  * Start tracking property accesses
1243
1332
  *
1244
1333
  * Clears previous tracked paths and enables tracking mode.
1334
+ *
1335
+ * @internal
1245
1336
  */
1246
1337
  function startProxyTracking(state) {
1247
1338
  state.isTracking = true;
@@ -1251,6 +1342,8 @@ function startProxyTracking(state) {
1251
1342
  * Stop tracking and return the tracked paths
1252
1343
  *
1253
1344
  * Returns a new Set containing all tracked paths.
1345
+ *
1346
+ * @internal
1254
1347
  */
1255
1348
  function stopProxyTracking(state) {
1256
1349
  state.isTracking = false;
@@ -1263,6 +1356,8 @@ function stopProxyTracking(state) {
1263
1356
  * - Array element access (arr[0])
1264
1357
  * - Length access (arr.length)
1265
1358
  * - Array method calls (arr.map, arr.filter, etc.)
1359
+ *
1360
+ * @internal
1266
1361
  */
1267
1362
  function createArrayProxy(state, target, path, depth = 0) {
1268
1363
  const proxy = new Proxy(target, { get: (arr, prop) => {
@@ -1307,6 +1402,8 @@ function createArrayProxy(state, target, path, depth = 0) {
1307
1402
  * - Nested property access (obj.nested.prop)
1308
1403
  * - 'in' operator usage ('prop' in obj)
1309
1404
  * - Object.keys, Object.entries, etc.
1405
+ *
1406
+ * @internal
1310
1407
  */
1311
1408
  function createProxyInternal(state, target, path = "", depth = 0) {
1312
1409
  if (!state.isTracking || !isProxyable(target)) return target;
@@ -1354,6 +1451,8 @@ function createProxyInternal(state, target, path = "", depth = 0) {
1354
1451
  * Otherwise, creates a new proxy and caches it.
1355
1452
  *
1356
1453
  * This is the main entry point for creating tracked proxies.
1454
+ *
1455
+ * @internal
1357
1456
  */
1358
1457
  function createProxyForTarget(state, target) {
1359
1458
  if (state.lastProxiedState === target && state.lastProxy) return state.lastProxy;
@@ -1372,16 +1471,22 @@ function createProxyForTarget(state, target) {
1372
1471
  *
1373
1472
  * Provides utilities for parsing property paths and extracting values
1374
1473
  * from nested objects using path strings.
1474
+ *
1475
+ * @internal
1375
1476
  */
1376
1477
  /**
1377
1478
  * Parse a property path string into an array of segments
1378
1479
  *
1480
+ * @internal
1481
+ *
1379
1482
  * Handles both dot notation (a.b.c) and bracket notation (a[0].b)
1380
1483
  *
1381
1484
  * @example
1485
+ * ```ts
1382
1486
  * parsePath('user.name') // ['user', 'name']
1383
1487
  * parsePath('items[0].name') // ['items', '0', 'name']
1384
1488
  * parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']
1489
+ * ```
1385
1490
  */
1386
1491
  function parsePath(path) {
1387
1492
  const segments = [];
@@ -1409,10 +1514,14 @@ function parsePath(path) {
1409
1514
  * Get a value from an object using a path of segments
1410
1515
  *
1411
1516
  * @example
1517
+ * ```ts
1412
1518
  * const obj = { user: { name: 'Alice', age: 30 } }
1413
1519
  * getValueAtPath(obj, ['user', 'name']) // 'Alice'
1414
1520
  * getValueAtPath(obj, ['user', 'age']) // 30
1415
1521
  * getValueAtPath(obj, ['user', 'missing']) // undefined
1522
+ * ```
1523
+ *
1524
+ * @internal
1416
1525
  */
1417
1526
  function getValueAtPath(obj, segments) {
1418
1527
  if (obj == null) return void 0;
@@ -1429,9 +1538,13 @@ function getValueAtPath(obj, segments) {
1429
1538
  * Compares two arrays element-by-element using Object.is
1430
1539
  *
1431
1540
  * @example
1541
+ * ```ts
1432
1542
  * shallowEqual([1, 2, 3], [1, 2, 3]) // true
1433
1543
  * shallowEqual([1, 2, 3], [1, 2, 4]) // false
1434
1544
  * shallowEqual([1, 2], [1, 2, 3]) // false
1545
+ * ```
1546
+ *
1547
+ * @internal
1435
1548
  */
1436
1549
  function shallowEqual(arr1, arr2) {
1437
1550
  if (arr1.length !== arr2.length) return false;
@@ -1459,6 +1572,9 @@ function getArrayParentPath(path) {
1459
1572
  if (arrayIndexMatch) return arrayIndexMatch[1];
1460
1573
  return null;
1461
1574
  }
1575
+ /**
1576
+ * @internal
1577
+ */
1462
1578
  function optimizeTrackedPaths(paths) {
1463
1579
  if (paths.size === 0) return /* @__PURE__ */ new Set();
1464
1580
  if (paths.size === 1) return new Set(paths);
@@ -1480,6 +1596,9 @@ function optimizeTrackedPaths(paths) {
1480
1596
  for (const arrayParent of arrayParents) optimized.add(arrayParent);
1481
1597
  return optimized;
1482
1598
  }
1599
+ /**
1600
+ * @internal
1601
+ */
1483
1602
  function createTrackerState() {
1484
1603
  return {
1485
1604
  proxyTrackerState: createProxyTrackerState(),
@@ -1490,12 +1609,21 @@ function createTrackerState() {
1490
1609
  lastCheckedValues: /* @__PURE__ */ new Map()
1491
1610
  };
1492
1611
  }
1612
+ /**
1613
+ * @internal
1614
+ */
1493
1615
  function startTracking(tracker) {
1494
1616
  startProxyTracking(tracker.proxyTrackerState);
1495
1617
  }
1618
+ /**
1619
+ * @internal
1620
+ */
1496
1621
  function createProxy(tracker, state) {
1497
1622
  return createProxyForTarget(tracker.proxyTrackerState, state);
1498
1623
  }
1624
+ /**
1625
+ * @internal
1626
+ */
1499
1627
  function captureTrackedPaths(tracker, state) {
1500
1628
  tracker.previousRenderPaths = tracker.currentRenderPaths;
1501
1629
  tracker.currentRenderPaths = optimizeTrackedPaths(stopProxyTracking(tracker.proxyTrackerState));
@@ -1516,6 +1644,9 @@ function captureTrackedPaths(tracker, state) {
1516
1644
  }
1517
1645
  tracker.lastCheckedValues.clear();
1518
1646
  }
1647
+ /**
1648
+ * @internal
1649
+ */
1519
1650
  function hasChanges(tracker, state) {
1520
1651
  if (tracker.pathCache.size === 0) return true;
1521
1652
  tracker.lastCheckedValues.clear();
@@ -1530,12 +1661,20 @@ function hasChanges(tracker, state) {
1530
1661
  tracker.lastCheckedState = state;
1531
1662
  return false;
1532
1663
  }
1664
+ /**
1665
+ * @internal
1666
+ */
1533
1667
  function hasTrackedData(tracker) {
1534
1668
  return tracker.proxyTrackerState.trackedPaths.size > 0 || tracker.pathCache.size > 0 || tracker.previousRenderPaths.size > 0;
1535
1669
  }
1536
1670
 
1537
1671
  //#endregion
1538
1672
  //#region src/adapter/framework-adapter.ts
1673
+ /**
1674
+ * Manages subscriptions to external bloc dependencies for getter tracking.
1675
+ * When a getter accesses another bloc's state, this manager ensures
1676
+ * re-renders occur when those external dependencies change.
1677
+ */
1539
1678
  var ExternalDependencyManager = class {
1540
1679
  constructor() {
1541
1680
  this.subscriptions = [];
@@ -1546,6 +1685,14 @@ var ExternalDependencyManager = class {
1546
1685
  for (const dep of newDeps) if (!oldDeps.has(dep)) return false;
1547
1686
  return true;
1548
1687
  }
1688
+ /**
1689
+ * Update subscriptions to external bloc dependencies.
1690
+ * Creates subscriptions to blocs accessed via getters.
1691
+ * @param getterTracker - The getter tracker state with external dependencies
1692
+ * @param rawInstance - The primary bloc instance (excluded from subscriptions)
1693
+ * @param onGetterChange - Callback to invoke when external dependency changes
1694
+ * @returns true if subscriptions were updated, false if unchanged
1695
+ */
1549
1696
  updateSubscriptions(getterTracker, rawInstance, onGetterChange) {
1550
1697
  if (!getterTracker?.externalDependencies) return false;
1551
1698
  const currentDeps = getterTracker.externalDependencies;
@@ -1566,11 +1713,21 @@ var ExternalDependencyManager = class {
1566
1713
  clearExternalDependencies(getterTracker);
1567
1714
  return true;
1568
1715
  }
1716
+ /**
1717
+ * Clean up all active subscriptions
1718
+ */
1569
1719
  cleanup() {
1570
1720
  this.subscriptions.forEach((unsub) => unsub());
1571
1721
  this.subscriptions = [];
1572
1722
  }
1573
1723
  };
1724
+ /**
1725
+ * Create a subscribe function for auto-tracking mode.
1726
+ * Only triggers callback when tracked properties change.
1727
+ * @param instance - The state container instance
1728
+ * @param adapterState - The adapter state for tracking
1729
+ * @returns Subscribe function for use with useSyncExternalStore
1730
+ */
1574
1731
  function createAutoTrackSubscribe(instance, adapterState) {
1575
1732
  return (callback) => {
1576
1733
  return instance.subscribe(() => {
@@ -1589,6 +1746,14 @@ function createAutoTrackSubscribe(instance, adapterState) {
1589
1746
  });
1590
1747
  };
1591
1748
  }
1749
+ /**
1750
+ * Create a subscribe function for manual dependency tracking mode.
1751
+ * Only triggers callback when dependencies array changes.
1752
+ * @param instance - The state container instance
1753
+ * @param adapterState - The adapter state for caching
1754
+ * @param config - Configuration with dependencies function
1755
+ * @returns Subscribe function for use with useSyncExternalStore
1756
+ */
1592
1757
  function createManualDepsSubscribe(instance, adapterState, config) {
1593
1758
  return (callback) => {
1594
1759
  return instance.subscribe(() => {
@@ -1600,9 +1765,22 @@ function createManualDepsSubscribe(instance, adapterState, config) {
1600
1765
  });
1601
1766
  };
1602
1767
  }
1768
+ /**
1769
+ * Create a subscribe function for no-tracking mode.
1770
+ * Triggers callback on every state change.
1771
+ * @param instance - The state container instance
1772
+ * @returns Subscribe function for use with useSyncExternalStore
1773
+ */
1603
1774
  function createNoTrackSubscribe(instance) {
1604
1775
  return (callback) => instance.subscribe(callback);
1605
1776
  }
1777
+ /**
1778
+ * Create a snapshot function for auto-tracking mode.
1779
+ * Returns a proxied state that tracks property access.
1780
+ * @param instance - The state container instance
1781
+ * @param adapterState - The adapter state for tracking
1782
+ * @returns Snapshot function for use with useSyncExternalStore
1783
+ */
1606
1784
  function createAutoTrackSnapshot(instance, adapterState) {
1607
1785
  return () => {
1608
1786
  const tracker = adapterState.tracker || (adapterState.tracker = createTrackerState());
@@ -1617,15 +1795,35 @@ function createAutoTrackSnapshot(instance, adapterState) {
1617
1795
  return createProxy(tracker, instance.state);
1618
1796
  };
1619
1797
  }
1798
+ /**
1799
+ * Create a snapshot function for manual dependency tracking mode.
1800
+ * Caches dependencies for comparison on next render.
1801
+ * @param instance - The state container instance
1802
+ * @param adapterState - The adapter state for caching
1803
+ * @param config - Configuration with dependencies function
1804
+ * @returns Snapshot function for use with useSyncExternalStore
1805
+ */
1620
1806
  function createManualDepsSnapshot(instance, adapterState, config) {
1621
1807
  return () => {
1622
1808
  adapterState.manualDepsCache = config.dependencies(instance.state, instance);
1623
1809
  return instance.state;
1624
1810
  };
1625
1811
  }
1812
+ /**
1813
+ * Create a snapshot function for no-tracking mode.
1814
+ * Returns the raw state directly.
1815
+ * @param instance - The state container instance
1816
+ * @returns Snapshot function for use with useSyncExternalStore
1817
+ */
1626
1818
  function createNoTrackSnapshot(instance) {
1627
1819
  return () => instance.state;
1628
1820
  }
1821
+ /**
1822
+ * Initialize adapter state for auto-tracking mode.
1823
+ * Creates getter tracker and proxied bloc instance.
1824
+ * @param instance - The state container instance
1825
+ * @returns Initialized adapter state
1826
+ */
1629
1827
  function initAutoTrackState(instance) {
1630
1828
  return {
1631
1829
  tracker: null,
@@ -1634,6 +1832,12 @@ function initAutoTrackState(instance) {
1634
1832
  proxiedBloc: createBlocProxy(instance)
1635
1833
  };
1636
1834
  }
1835
+ /**
1836
+ * Initialize adapter state for manual dependency tracking mode.
1837
+ * No proxy is created; bloc is used directly.
1838
+ * @param instance - The state container instance
1839
+ * @returns Initialized adapter state
1840
+ */
1637
1841
  function initManualDepsState(instance) {
1638
1842
  return {
1639
1843
  tracker: null,
@@ -1642,6 +1846,12 @@ function initManualDepsState(instance) {
1642
1846
  proxiedBloc: instance
1643
1847
  };
1644
1848
  }
1849
+ /**
1850
+ * Initialize adapter state for no-tracking mode.
1851
+ * No tracking or proxy is created.
1852
+ * @param instance - The state container instance
1853
+ * @returns Initialized adapter state
1854
+ */
1645
1855
  function initNoTrackState(instance) {
1646
1856
  return {
1647
1857
  tracker: null,
@@ -1650,6 +1860,12 @@ function initNoTrackState(instance) {
1650
1860
  proxiedBloc: instance
1651
1861
  };
1652
1862
  }
1863
+ /**
1864
+ * Disable getter tracking after render phase completes.
1865
+ * Clears the active tracker to prevent tracking outside of render.
1866
+ * @param adapterState - The adapter state
1867
+ * @param rawInstance - The raw bloc instance
1868
+ */
1653
1869
  function disableGetterTracking(adapterState, rawInstance) {
1654
1870
  if (adapterState.getterTracker) {
1655
1871
  adapterState.getterTracker.isTracking = false;
@@ -1659,10 +1875,17 @@ function disableGetterTracking(adapterState, rawInstance) {
1659
1875
 
1660
1876
  //#endregion
1661
1877
  //#region src/logging/Logger.ts
1878
+ /**
1879
+ * Log severity levels (lower number = higher severity)
1880
+ */
1662
1881
  let LogLevel = /* @__PURE__ */ function(LogLevel$1) {
1882
+ /** Critical errors that may cause application failure */
1663
1883
  LogLevel$1[LogLevel$1["ERROR"] = 0] = "ERROR";
1884
+ /** Warning conditions that should be addressed */
1664
1885
  LogLevel$1[LogLevel$1["WARN"] = 1] = "WARN";
1886
+ /** Informational messages about application state */
1665
1887
  LogLevel$1[LogLevel$1["INFO"] = 2] = "INFO";
1888
+ /** Detailed debugging information */
1666
1889
  LogLevel$1[LogLevel$1["DEBUG"] = 3] = "DEBUG";
1667
1890
  return LogLevel$1;
1668
1891
  }({});
@@ -1731,9 +1954,33 @@ let currentConfig = {
1731
1954
  output: (entry) => console.log(JSON.stringify(entry))
1732
1955
  };
1733
1956
  let defaultLogger = createLogger(currentConfig);
1957
+ /**
1958
+ * Log a debug message (tree-shakeable export)
1959
+ * @param context - Context identifier (module or component name)
1960
+ * @param message - Log message
1961
+ * @param data - Optional structured data
1962
+ */
1734
1963
  const debug = (context, message, data) => defaultLogger.debug(context, message, data);
1964
+ /**
1965
+ * Log an info message (tree-shakeable export)
1966
+ * @param context - Context identifier (module or component name)
1967
+ * @param message - Log message
1968
+ * @param data - Optional structured data
1969
+ */
1735
1970
  const info = (context, message, data) => defaultLogger.info(context, message, data);
1971
+ /**
1972
+ * Log a warning message (tree-shakeable export)
1973
+ * @param context - Context identifier (module or component name)
1974
+ * @param message - Log message
1975
+ * @param data - Optional structured data
1976
+ */
1736
1977
  const warn = (context, message, data) => defaultLogger.warn(context, message, data);
1978
+ /**
1979
+ * Log an error message (tree-shakeable export)
1980
+ * @param context - Context identifier (module or component name)
1981
+ * @param message - Log message
1982
+ * @param data - Optional structured data
1983
+ */
1737
1984
  const error = (context, message, data) => defaultLogger.error(context, message, data);
1738
1985
  /**
1739
1986
  * Configuration function that recreates the default logger
@@ -1759,7 +2006,7 @@ function configureLogger(opts) {
1759
2006
  * Decorator to configure StateContainer classes.
1760
2007
  *
1761
2008
  * @example Decorator syntax (requires experimentalDecorators or TC39 decorators)
1762
- * ```typescript
2009
+ * ```ts
1763
2010
  * @blac({ isolated: true })
1764
2011
  * class FormBloc extends Cubit<FormState> {}
1765
2012
  *
@@ -1771,7 +2018,7 @@ function configureLogger(opts) {
1771
2018
  * ```
1772
2019
  *
1773
2020
  * @example Function syntax (no decorator support needed)
1774
- * ```typescript
2021
+ * ```ts
1775
2022
  * const FormBloc = blac({ isolated: true })(
1776
2023
  * class extends Cubit<FormState> {}
1777
2024
  * );
@@ -1787,25 +2034,16 @@ function blac(options) {
1787
2034
  }
1788
2035
 
1789
2036
  //#endregion
1790
- exports.AuthVertex = AuthVertex;
1791
2037
  exports.BLAC_DEFAULTS = BLAC_DEFAULTS;
1792
2038
  exports.BLAC_ERROR_PREFIX = BLAC_ERROR_PREFIX;
1793
2039
  exports.BLAC_ID_PATTERNS = BLAC_ID_PATTERNS;
1794
2040
  exports.BLAC_STATIC_PROPS = BLAC_STATIC_PROPS;
1795
- exports.CounterCubit = CounterCubit;
1796
- exports.CounterVertex = CounterVertex;
1797
2041
  exports.Cubit = Cubit;
1798
- exports.DecrementEvent = DecrementEvent;
1799
2042
  exports.ExternalDependencyManager = ExternalDependencyManager;
1800
- exports.IncrementEvent = IncrementEvent;
1801
2043
  exports.LogLevel = LogLevel;
1802
- exports.LoginEvent = LoginEvent;
1803
- exports.LogoutEvent = LogoutEvent;
1804
2044
  exports.PluginManager = PluginManager;
1805
- exports.ResetEvent = ResetEvent;
1806
2045
  exports.StateContainer = StateContainer;
1807
2046
  exports.StateContainerRegistry = StateContainerRegistry;
1808
- exports.TodoCubit = TodoCubit;
1809
2047
  exports.Vertex = Vertex;
1810
2048
  exports.__resetIdCounters = __resetIdCounters;
1811
2049
  exports.blac = blac;