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