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

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,124 @@ 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
+ * @param instanceKey - Optional instance key (defaults to 'default')
891
+ * @param constructorArgs - Arguments to pass to constructor if creating new instance
892
+ * @returns The state container instance
893
+ */
753
894
  static resolve(instanceKey, constructorArgs) {
754
895
  return StateContainer._registry.resolve(this, instanceKey, constructorArgs);
755
896
  }
897
+ /**
898
+ * Get an existing instance without incrementing ref count (borrowing semantics).
899
+ * @param instanceKey - Optional instance key (defaults to 'default')
900
+ * @returns The state container instance
901
+ * @throws Error if instance doesn't exist
902
+ */
756
903
  static get(instanceKey) {
757
904
  return StateContainer._registry.get(this, instanceKey);
758
905
  }
906
+ /**
907
+ * Safely get an existing instance with error handling.
908
+ * @param instanceKey - Optional instance key (defaults to 'default')
909
+ * @returns Discriminated union with either the instance or an error
910
+ */
759
911
  static getSafe(instanceKey) {
760
912
  return StateContainer._registry.getSafe(this, instanceKey);
761
913
  }
914
+ /**
915
+ * Connect to an instance for bloc-to-bloc communication (borrowing semantics).
916
+ * Gets or creates instance without incrementing ref count.
917
+ * @param instanceKey - Optional instance key (defaults to 'default')
918
+ * @param constructorArgs - Arguments to pass to constructor if creating new instance
919
+ * @returns The state container instance
920
+ */
762
921
  static connect(instanceKey, constructorArgs) {
763
922
  return StateContainer._registry.connect(this, instanceKey, constructorArgs);
764
923
  }
924
+ /**
925
+ * Release a reference to an instance.
926
+ * Decrements ref count and disposes when it reaches 0 (unless keepAlive).
927
+ * @param instanceKey - Optional instance key (defaults to 'default')
928
+ * @param forceDispose - Force immediate disposal regardless of ref count
929
+ */
765
930
  static release(instanceKey, forceDispose = false) {
766
931
  StateContainer._registry.release(this, instanceKey, forceDispose);
767
932
  }
933
+ /**
934
+ * Get all instances of this class
935
+ * @returns Array of all instances
936
+ */
768
937
  static getAll() {
769
938
  return StateContainer._registry.getAll(this);
770
939
  }
940
+ /**
941
+ * Iterate over all instances of this class
942
+ * @param callback - Function to call for each instance
943
+ */
771
944
  static forEach(callback) {
772
945
  StateContainer._registry.forEach(this, callback);
773
946
  }
947
+ /**
948
+ * Clear all instances of this class (disposes them)
949
+ */
774
950
  static clear() {
775
951
  StateContainer._registry.clear(this);
776
952
  }
953
+ /**
954
+ * Clear all instances from all registered types
955
+ */
777
956
  static clearAllInstances() {
778
957
  StateContainer._registry.clearAll();
779
958
  }
959
+ /**
960
+ * Get registry statistics for debugging
961
+ * @returns Object with registeredTypes, totalInstances, and typeBreakdown
962
+ */
780
963
  static getStats() {
781
964
  return StateContainer._registry.getStats();
782
965
  }
966
+ /**
967
+ * Get reference count for an instance
968
+ * @param instanceKey - Optional instance key (defaults to 'default')
969
+ * @returns Current ref count (0 if instance doesn't exist)
970
+ */
783
971
  static getRefCount(instanceKey) {
784
972
  return StateContainer._registry.getRefCount(this, instanceKey);
785
973
  }
974
+ /**
975
+ * Check if an instance exists
976
+ * @param instanceKey - Optional instance key (defaults to 'default')
977
+ * @returns true if instance exists
978
+ */
786
979
  static hasInstance(instanceKey) {
787
980
  return StateContainer._registry.hasInstance(this, instanceKey);
788
981
  }
982
+ /** Current props value passed to this container */
789
983
  get props() {
790
984
  return this._props;
791
985
  }
@@ -813,6 +1007,11 @@ var StateContainer = class StateContainer {
813
1007
  };
814
1008
  this._state = initialState;
815
1009
  }
1010
+ /**
1011
+ * Initialize configuration for this instance.
1012
+ * Called by the registry after construction.
1013
+ * @param config - Configuration options
1014
+ */
816
1015
  initConfig(config) {
817
1016
  this.config = { ...config };
818
1017
  this.name = this.config.name || this.constructor.name;
@@ -820,17 +1019,28 @@ var StateContainer = class StateContainer {
820
1019
  this.instanceId = generateSimpleId(this.constructor.name, this.config.instanceId);
821
1020
  StateContainer._registry.emit("created", this);
822
1021
  }
1022
+ /** Current state value */
823
1023
  get state() {
824
1024
  return this._state;
825
1025
  }
1026
+ /** Whether this instance has been disposed */
826
1027
  get isDisposed() {
827
1028
  return this._disposed;
828
1029
  }
1030
+ /**
1031
+ * Subscribe to state changes
1032
+ * @param listener - Function called when state changes
1033
+ * @returns Unsubscribe function
1034
+ */
829
1035
  subscribe(listener) {
830
1036
  if (this._disposed) throw new Error(`Cannot subscribe to disposed container ${this.name}`);
831
1037
  this.listeners.add(listener);
832
1038
  return () => this.listeners.delete(listener);
833
1039
  }
1040
+ /**
1041
+ * Dispose this instance and clean up resources.
1042
+ * Clears all listeners and emits the 'dispose' system event.
1043
+ */
834
1044
  dispose() {
835
1045
  if (this._disposed) return;
836
1046
  if (this.debug) console.log(`[${this.name}] Disposing...`);
@@ -841,6 +1051,11 @@ var StateContainer = class StateContainer {
841
1051
  StateContainer._registry.emit("disposed", this);
842
1052
  if (this.debug) console.log(`[${this.name}] Disposed successfully`);
843
1053
  }
1054
+ /**
1055
+ * Emit a new state value and notify all listeners.
1056
+ * @param newState - The new state value
1057
+ * @protected
1058
+ */
844
1059
  emit(newState) {
845
1060
  if (this._disposed) throw new Error(`Cannot emit state from disposed container ${this.name}`);
846
1061
  if (this._state === newState) return;
@@ -900,6 +1115,11 @@ var StateContainer = class StateContainer {
900
1115
  if (segments.length > 3) path = segments.slice(-3).join("/");
901
1116
  return path;
902
1117
  }
1118
+ /**
1119
+ * Update state using a transform function.
1120
+ * @param updater - Function that receives current state and returns new state
1121
+ * @protected
1122
+ */
903
1123
  update(updater) {
904
1124
  if (this._disposed) throw new Error(`Cannot update state from disposed container ${this.name}`);
905
1125
  this.emit(updater(this._state));
@@ -913,6 +1133,11 @@ var StateContainer = class StateContainer {
913
1133
  console.error(`[${this.name}] Error in system event handler:`, error$1);
914
1134
  }
915
1135
  }
1136
+ /**
1137
+ * Update the props for this container.
1138
+ * Emits the 'propsUpdated' system event.
1139
+ * @param newProps - The new props value
1140
+ */
916
1141
  updateProps(newProps) {
917
1142
  if (this._disposed) throw new Error(`Cannot update props on disposed container ${this.name}`);
918
1143
  const previousProps = this._props;
@@ -930,6 +1155,13 @@ var StateContainer = class StateContainer {
930
1155
 
931
1156
  //#endregion
932
1157
  //#region src/core/Cubit.ts
1158
+ /**
1159
+ * Simple state container with direct state emission.
1160
+ * Extends StateContainer with public methods for emitting and updating state.
1161
+ *
1162
+ * @template S - State type
1163
+ * @template P - Props type (optional)
1164
+ */
933
1165
  var Cubit = class extends StateContainer {
934
1166
  constructor(initialState) {
935
1167
  super(initialState);
@@ -941,89 +1173,32 @@ var Cubit = class extends StateContainer {
941
1173
  }));
942
1174
  });
943
1175
  }
1176
+ /**
1177
+ * Replace state with a new value and notify all listeners
1178
+ * @param newState - The new state value
1179
+ */
944
1180
  emit(newState) {
945
1181
  super["emit"](newState);
946
1182
  }
1183
+ /**
1184
+ * Transform current state using an updater function and emit the new state
1185
+ * @param updater - Function that receives current state and returns new state
1186
+ */
947
1187
  update(updater) {
948
1188
  super["update"](updater);
949
1189
  }
950
1190
  };
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
1191
 
1025
1192
  //#endregion
1026
1193
  //#region src/core/Vertex.ts
1194
+ /**
1195
+ * Event-driven state container that processes events to update state.
1196
+ * Use with event handlers registered via the on() method.
1197
+ *
1198
+ * @template S - State type
1199
+ * @template E - Event type (extends BaseEvent)
1200
+ * @template P - Props type (optional)
1201
+ */
1027
1202
  var Vertex = class extends StateContainer {
1028
1203
  constructor(initialState) {
1029
1204
  super(initialState);
@@ -1077,122 +1252,22 @@ var Vertex = class extends StateContainer {
1077
1252
  this.onEventError(event, error$1);
1078
1253
  }
1079
1254
  }
1255
+ /**
1256
+ * Handle errors that occur during event processing.
1257
+ * Override this method to implement custom error handling.
1258
+ * @param _event - The event that caused the error
1259
+ * @param _error - The error that occurred
1260
+ */
1080
1261
  onEventError(_event, _error) {}
1081
1262
  };
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
1263
 
1194
1264
  //#endregion
1195
1265
  //#region src/plugin/BlacPlugin.ts
1266
+ /**
1267
+ * Type guard to check if a plugin has a required onInstall hook
1268
+ * @param plugin - The plugin to check
1269
+ * @returns true if the plugin implements BlacPluginWithInit
1270
+ */
1196
1271
  function hasInitHook(plugin) {
1197
1272
  return typeof plugin.onInstall === "function";
1198
1273
  }
@@ -1205,12 +1280,16 @@ function hasInitHook(plugin) {
1205
1280
  * This module provides a functional approach to proxy-based dependency tracking.
1206
1281
  * Unlike the class-based ProxyTracker, this uses a state object pattern that's
1207
1282
  * easier to integrate with functional programming patterns and framework hooks.
1283
+ *
1284
+ * @internal
1208
1285
  */
1209
1286
  /**
1210
1287
  * Check if a value can be proxied
1211
1288
  *
1212
1289
  * Returns true for plain objects and arrays only.
1213
1290
  * Excludes built-in objects like Date, Map, Set, etc.
1291
+ *
1292
+ * @internal
1214
1293
  */
1215
1294
  function isProxyable(value) {
1216
1295
  if (typeof value !== "object" || value === null) return false;
@@ -1226,6 +1305,8 @@ function isProxyable(value) {
1226
1305
  * const proxy = createProxyForTarget(state, myObject);
1227
1306
  * // ... use proxy ...
1228
1307
  * const paths = stopProxyTracking(state);
1308
+ *
1309
+ * @internal
1229
1310
  */
1230
1311
  function createProxyTrackerState() {
1231
1312
  return {
@@ -1242,6 +1323,8 @@ function createProxyTrackerState() {
1242
1323
  * Start tracking property accesses
1243
1324
  *
1244
1325
  * Clears previous tracked paths and enables tracking mode.
1326
+ *
1327
+ * @internal
1245
1328
  */
1246
1329
  function startProxyTracking(state) {
1247
1330
  state.isTracking = true;
@@ -1251,6 +1334,8 @@ function startProxyTracking(state) {
1251
1334
  * Stop tracking and return the tracked paths
1252
1335
  *
1253
1336
  * Returns a new Set containing all tracked paths.
1337
+ *
1338
+ * @internal
1254
1339
  */
1255
1340
  function stopProxyTracking(state) {
1256
1341
  state.isTracking = false;
@@ -1263,6 +1348,8 @@ function stopProxyTracking(state) {
1263
1348
  * - Array element access (arr[0])
1264
1349
  * - Length access (arr.length)
1265
1350
  * - Array method calls (arr.map, arr.filter, etc.)
1351
+ *
1352
+ * @internal
1266
1353
  */
1267
1354
  function createArrayProxy(state, target, path, depth = 0) {
1268
1355
  const proxy = new Proxy(target, { get: (arr, prop) => {
@@ -1307,6 +1394,8 @@ function createArrayProxy(state, target, path, depth = 0) {
1307
1394
  * - Nested property access (obj.nested.prop)
1308
1395
  * - 'in' operator usage ('prop' in obj)
1309
1396
  * - Object.keys, Object.entries, etc.
1397
+ *
1398
+ * @internal
1310
1399
  */
1311
1400
  function createProxyInternal(state, target, path = "", depth = 0) {
1312
1401
  if (!state.isTracking || !isProxyable(target)) return target;
@@ -1354,6 +1443,8 @@ function createProxyInternal(state, target, path = "", depth = 0) {
1354
1443
  * Otherwise, creates a new proxy and caches it.
1355
1444
  *
1356
1445
  * This is the main entry point for creating tracked proxies.
1446
+ *
1447
+ * @internal
1357
1448
  */
1358
1449
  function createProxyForTarget(state, target) {
1359
1450
  if (state.lastProxiedState === target && state.lastProxy) return state.lastProxy;
@@ -1372,16 +1463,22 @@ function createProxyForTarget(state, target) {
1372
1463
  *
1373
1464
  * Provides utilities for parsing property paths and extracting values
1374
1465
  * from nested objects using path strings.
1466
+ *
1467
+ * @internal
1375
1468
  */
1376
1469
  /**
1377
1470
  * Parse a property path string into an array of segments
1378
1471
  *
1472
+ * @internal
1473
+ *
1379
1474
  * Handles both dot notation (a.b.c) and bracket notation (a[0].b)
1380
1475
  *
1381
1476
  * @example
1477
+ * ```ts
1382
1478
  * parsePath('user.name') // ['user', 'name']
1383
1479
  * parsePath('items[0].name') // ['items', '0', 'name']
1384
1480
  * parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']
1481
+ * ```
1385
1482
  */
1386
1483
  function parsePath(path) {
1387
1484
  const segments = [];
@@ -1409,10 +1506,14 @@ function parsePath(path) {
1409
1506
  * Get a value from an object using a path of segments
1410
1507
  *
1411
1508
  * @example
1509
+ * ```ts
1412
1510
  * const obj = { user: { name: 'Alice', age: 30 } }
1413
1511
  * getValueAtPath(obj, ['user', 'name']) // 'Alice'
1414
1512
  * getValueAtPath(obj, ['user', 'age']) // 30
1415
1513
  * getValueAtPath(obj, ['user', 'missing']) // undefined
1514
+ * ```
1515
+ *
1516
+ * @internal
1416
1517
  */
1417
1518
  function getValueAtPath(obj, segments) {
1418
1519
  if (obj == null) return void 0;
@@ -1429,9 +1530,13 @@ function getValueAtPath(obj, segments) {
1429
1530
  * Compares two arrays element-by-element using Object.is
1430
1531
  *
1431
1532
  * @example
1533
+ * ```ts
1432
1534
  * shallowEqual([1, 2, 3], [1, 2, 3]) // true
1433
1535
  * shallowEqual([1, 2, 3], [1, 2, 4]) // false
1434
1536
  * shallowEqual([1, 2], [1, 2, 3]) // false
1537
+ * ```
1538
+ *
1539
+ * @internal
1435
1540
  */
1436
1541
  function shallowEqual(arr1, arr2) {
1437
1542
  if (arr1.length !== arr2.length) return false;
@@ -1459,6 +1564,9 @@ function getArrayParentPath(path) {
1459
1564
  if (arrayIndexMatch) return arrayIndexMatch[1];
1460
1565
  return null;
1461
1566
  }
1567
+ /**
1568
+ * @internal
1569
+ */
1462
1570
  function optimizeTrackedPaths(paths) {
1463
1571
  if (paths.size === 0) return /* @__PURE__ */ new Set();
1464
1572
  if (paths.size === 1) return new Set(paths);
@@ -1480,6 +1588,9 @@ function optimizeTrackedPaths(paths) {
1480
1588
  for (const arrayParent of arrayParents) optimized.add(arrayParent);
1481
1589
  return optimized;
1482
1590
  }
1591
+ /**
1592
+ * @internal
1593
+ */
1483
1594
  function createTrackerState() {
1484
1595
  return {
1485
1596
  proxyTrackerState: createProxyTrackerState(),
@@ -1490,12 +1601,21 @@ function createTrackerState() {
1490
1601
  lastCheckedValues: /* @__PURE__ */ new Map()
1491
1602
  };
1492
1603
  }
1604
+ /**
1605
+ * @internal
1606
+ */
1493
1607
  function startTracking(tracker) {
1494
1608
  startProxyTracking(tracker.proxyTrackerState);
1495
1609
  }
1610
+ /**
1611
+ * @internal
1612
+ */
1496
1613
  function createProxy(tracker, state) {
1497
1614
  return createProxyForTarget(tracker.proxyTrackerState, state);
1498
1615
  }
1616
+ /**
1617
+ * @internal
1618
+ */
1499
1619
  function captureTrackedPaths(tracker, state) {
1500
1620
  tracker.previousRenderPaths = tracker.currentRenderPaths;
1501
1621
  tracker.currentRenderPaths = optimizeTrackedPaths(stopProxyTracking(tracker.proxyTrackerState));
@@ -1516,6 +1636,9 @@ function captureTrackedPaths(tracker, state) {
1516
1636
  }
1517
1637
  tracker.lastCheckedValues.clear();
1518
1638
  }
1639
+ /**
1640
+ * @internal
1641
+ */
1519
1642
  function hasChanges(tracker, state) {
1520
1643
  if (tracker.pathCache.size === 0) return true;
1521
1644
  tracker.lastCheckedValues.clear();
@@ -1530,12 +1653,20 @@ function hasChanges(tracker, state) {
1530
1653
  tracker.lastCheckedState = state;
1531
1654
  return false;
1532
1655
  }
1656
+ /**
1657
+ * @internal
1658
+ */
1533
1659
  function hasTrackedData(tracker) {
1534
1660
  return tracker.proxyTrackerState.trackedPaths.size > 0 || tracker.pathCache.size > 0 || tracker.previousRenderPaths.size > 0;
1535
1661
  }
1536
1662
 
1537
1663
  //#endregion
1538
1664
  //#region src/adapter/framework-adapter.ts
1665
+ /**
1666
+ * Manages subscriptions to external bloc dependencies for getter tracking.
1667
+ * When a getter accesses another bloc's state, this manager ensures
1668
+ * re-renders occur when those external dependencies change.
1669
+ */
1539
1670
  var ExternalDependencyManager = class {
1540
1671
  constructor() {
1541
1672
  this.subscriptions = [];
@@ -1546,6 +1677,14 @@ var ExternalDependencyManager = class {
1546
1677
  for (const dep of newDeps) if (!oldDeps.has(dep)) return false;
1547
1678
  return true;
1548
1679
  }
1680
+ /**
1681
+ * Update subscriptions to external bloc dependencies.
1682
+ * Creates subscriptions to blocs accessed via getters.
1683
+ * @param getterTracker - The getter tracker state with external dependencies
1684
+ * @param rawInstance - The primary bloc instance (excluded from subscriptions)
1685
+ * @param onGetterChange - Callback to invoke when external dependency changes
1686
+ * @returns true if subscriptions were updated, false if unchanged
1687
+ */
1549
1688
  updateSubscriptions(getterTracker, rawInstance, onGetterChange) {
1550
1689
  if (!getterTracker?.externalDependencies) return false;
1551
1690
  const currentDeps = getterTracker.externalDependencies;
@@ -1566,11 +1705,21 @@ var ExternalDependencyManager = class {
1566
1705
  clearExternalDependencies(getterTracker);
1567
1706
  return true;
1568
1707
  }
1708
+ /**
1709
+ * Clean up all active subscriptions
1710
+ */
1569
1711
  cleanup() {
1570
1712
  this.subscriptions.forEach((unsub) => unsub());
1571
1713
  this.subscriptions = [];
1572
1714
  }
1573
1715
  };
1716
+ /**
1717
+ * Create a subscribe function for auto-tracking mode.
1718
+ * Only triggers callback when tracked properties change.
1719
+ * @param instance - The state container instance
1720
+ * @param adapterState - The adapter state for tracking
1721
+ * @returns Subscribe function for use with useSyncExternalStore
1722
+ */
1574
1723
  function createAutoTrackSubscribe(instance, adapterState) {
1575
1724
  return (callback) => {
1576
1725
  return instance.subscribe(() => {
@@ -1589,6 +1738,14 @@ function createAutoTrackSubscribe(instance, adapterState) {
1589
1738
  });
1590
1739
  };
1591
1740
  }
1741
+ /**
1742
+ * Create a subscribe function for manual dependency tracking mode.
1743
+ * Only triggers callback when dependencies array changes.
1744
+ * @param instance - The state container instance
1745
+ * @param adapterState - The adapter state for caching
1746
+ * @param config - Configuration with dependencies function
1747
+ * @returns Subscribe function for use with useSyncExternalStore
1748
+ */
1592
1749
  function createManualDepsSubscribe(instance, adapterState, config) {
1593
1750
  return (callback) => {
1594
1751
  return instance.subscribe(() => {
@@ -1600,9 +1757,22 @@ function createManualDepsSubscribe(instance, adapterState, config) {
1600
1757
  });
1601
1758
  };
1602
1759
  }
1760
+ /**
1761
+ * Create a subscribe function for no-tracking mode.
1762
+ * Triggers callback on every state change.
1763
+ * @param instance - The state container instance
1764
+ * @returns Subscribe function for use with useSyncExternalStore
1765
+ */
1603
1766
  function createNoTrackSubscribe(instance) {
1604
1767
  return (callback) => instance.subscribe(callback);
1605
1768
  }
1769
+ /**
1770
+ * Create a snapshot function for auto-tracking mode.
1771
+ * Returns a proxied state that tracks property access.
1772
+ * @param instance - The state container instance
1773
+ * @param adapterState - The adapter state for tracking
1774
+ * @returns Snapshot function for use with useSyncExternalStore
1775
+ */
1606
1776
  function createAutoTrackSnapshot(instance, adapterState) {
1607
1777
  return () => {
1608
1778
  const tracker = adapterState.tracker || (adapterState.tracker = createTrackerState());
@@ -1617,15 +1787,35 @@ function createAutoTrackSnapshot(instance, adapterState) {
1617
1787
  return createProxy(tracker, instance.state);
1618
1788
  };
1619
1789
  }
1790
+ /**
1791
+ * Create a snapshot function for manual dependency tracking mode.
1792
+ * Caches dependencies for comparison on next render.
1793
+ * @param instance - The state container instance
1794
+ * @param adapterState - The adapter state for caching
1795
+ * @param config - Configuration with dependencies function
1796
+ * @returns Snapshot function for use with useSyncExternalStore
1797
+ */
1620
1798
  function createManualDepsSnapshot(instance, adapterState, config) {
1621
1799
  return () => {
1622
1800
  adapterState.manualDepsCache = config.dependencies(instance.state, instance);
1623
1801
  return instance.state;
1624
1802
  };
1625
1803
  }
1804
+ /**
1805
+ * Create a snapshot function for no-tracking mode.
1806
+ * Returns the raw state directly.
1807
+ * @param instance - The state container instance
1808
+ * @returns Snapshot function for use with useSyncExternalStore
1809
+ */
1626
1810
  function createNoTrackSnapshot(instance) {
1627
1811
  return () => instance.state;
1628
1812
  }
1813
+ /**
1814
+ * Initialize adapter state for auto-tracking mode.
1815
+ * Creates getter tracker and proxied bloc instance.
1816
+ * @param instance - The state container instance
1817
+ * @returns Initialized adapter state
1818
+ */
1629
1819
  function initAutoTrackState(instance) {
1630
1820
  return {
1631
1821
  tracker: null,
@@ -1634,6 +1824,12 @@ function initAutoTrackState(instance) {
1634
1824
  proxiedBloc: createBlocProxy(instance)
1635
1825
  };
1636
1826
  }
1827
+ /**
1828
+ * Initialize adapter state for manual dependency tracking mode.
1829
+ * No proxy is created; bloc is used directly.
1830
+ * @param instance - The state container instance
1831
+ * @returns Initialized adapter state
1832
+ */
1637
1833
  function initManualDepsState(instance) {
1638
1834
  return {
1639
1835
  tracker: null,
@@ -1642,6 +1838,12 @@ function initManualDepsState(instance) {
1642
1838
  proxiedBloc: instance
1643
1839
  };
1644
1840
  }
1841
+ /**
1842
+ * Initialize adapter state for no-tracking mode.
1843
+ * No tracking or proxy is created.
1844
+ * @param instance - The state container instance
1845
+ * @returns Initialized adapter state
1846
+ */
1645
1847
  function initNoTrackState(instance) {
1646
1848
  return {
1647
1849
  tracker: null,
@@ -1650,6 +1852,12 @@ function initNoTrackState(instance) {
1650
1852
  proxiedBloc: instance
1651
1853
  };
1652
1854
  }
1855
+ /**
1856
+ * Disable getter tracking after render phase completes.
1857
+ * Clears the active tracker to prevent tracking outside of render.
1858
+ * @param adapterState - The adapter state
1859
+ * @param rawInstance - The raw bloc instance
1860
+ */
1653
1861
  function disableGetterTracking(adapterState, rawInstance) {
1654
1862
  if (adapterState.getterTracker) {
1655
1863
  adapterState.getterTracker.isTracking = false;
@@ -1659,10 +1867,17 @@ function disableGetterTracking(adapterState, rawInstance) {
1659
1867
 
1660
1868
  //#endregion
1661
1869
  //#region src/logging/Logger.ts
1870
+ /**
1871
+ * Log severity levels (lower number = higher severity)
1872
+ */
1662
1873
  let LogLevel = /* @__PURE__ */ function(LogLevel$1) {
1874
+ /** Critical errors that may cause application failure */
1663
1875
  LogLevel$1[LogLevel$1["ERROR"] = 0] = "ERROR";
1876
+ /** Warning conditions that should be addressed */
1664
1877
  LogLevel$1[LogLevel$1["WARN"] = 1] = "WARN";
1878
+ /** Informational messages about application state */
1665
1879
  LogLevel$1[LogLevel$1["INFO"] = 2] = "INFO";
1880
+ /** Detailed debugging information */
1666
1881
  LogLevel$1[LogLevel$1["DEBUG"] = 3] = "DEBUG";
1667
1882
  return LogLevel$1;
1668
1883
  }({});
@@ -1731,9 +1946,33 @@ let currentConfig = {
1731
1946
  output: (entry) => console.log(JSON.stringify(entry))
1732
1947
  };
1733
1948
  let defaultLogger = createLogger(currentConfig);
1949
+ /**
1950
+ * Log a debug message (tree-shakeable export)
1951
+ * @param context - Context identifier (module or component name)
1952
+ * @param message - Log message
1953
+ * @param data - Optional structured data
1954
+ */
1734
1955
  const debug = (context, message, data) => defaultLogger.debug(context, message, data);
1956
+ /**
1957
+ * Log an info 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
+ */
1735
1962
  const info = (context, message, data) => defaultLogger.info(context, message, data);
1963
+ /**
1964
+ * Log a warning 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
+ */
1736
1969
  const warn = (context, message, data) => defaultLogger.warn(context, message, data);
1970
+ /**
1971
+ * Log an error 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
+ */
1737
1976
  const error = (context, message, data) => defaultLogger.error(context, message, data);
1738
1977
  /**
1739
1978
  * Configuration function that recreates the default logger
@@ -1759,7 +1998,7 @@ function configureLogger(opts) {
1759
1998
  * Decorator to configure StateContainer classes.
1760
1999
  *
1761
2000
  * @example Decorator syntax (requires experimentalDecorators or TC39 decorators)
1762
- * ```typescript
2001
+ * ```ts
1763
2002
  * @blac({ isolated: true })
1764
2003
  * class FormBloc extends Cubit<FormState> {}
1765
2004
  *
@@ -1771,7 +2010,7 @@ function configureLogger(opts) {
1771
2010
  * ```
1772
2011
  *
1773
2012
  * @example Function syntax (no decorator support needed)
1774
- * ```typescript
2013
+ * ```ts
1775
2014
  * const FormBloc = blac({ isolated: true })(
1776
2015
  * class extends Cubit<FormState> {}
1777
2016
  * );
@@ -1787,25 +2026,16 @@ function blac(options) {
1787
2026
  }
1788
2027
 
1789
2028
  //#endregion
1790
- exports.AuthVertex = AuthVertex;
1791
2029
  exports.BLAC_DEFAULTS = BLAC_DEFAULTS;
1792
2030
  exports.BLAC_ERROR_PREFIX = BLAC_ERROR_PREFIX;
1793
2031
  exports.BLAC_ID_PATTERNS = BLAC_ID_PATTERNS;
1794
2032
  exports.BLAC_STATIC_PROPS = BLAC_STATIC_PROPS;
1795
- exports.CounterCubit = CounterCubit;
1796
- exports.CounterVertex = CounterVertex;
1797
2033
  exports.Cubit = Cubit;
1798
- exports.DecrementEvent = DecrementEvent;
1799
2034
  exports.ExternalDependencyManager = ExternalDependencyManager;
1800
- exports.IncrementEvent = IncrementEvent;
1801
2035
  exports.LogLevel = LogLevel;
1802
- exports.LoginEvent = LoginEvent;
1803
- exports.LogoutEvent = LogoutEvent;
1804
2036
  exports.PluginManager = PluginManager;
1805
- exports.ResetEvent = ResetEvent;
1806
2037
  exports.StateContainer = StateContainer;
1807
2038
  exports.StateContainerRegistry = StateContainerRegistry;
1808
- exports.TodoCubit = TodoCubit;
1809
2039
  exports.Vertex = Vertex;
1810
2040
  exports.__resetIdCounters = __resetIdCounters;
1811
2041
  exports.blac = blac;