@blac/core 2.0.0 โ†’ 2.0.3

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.
Files changed (60) hide show
  1. package/README.md +137 -177
  2. package/dist/StateContainerRegistry.cjs.map +1 -0
  3. package/dist/StateContainerRegistry.js.map +1 -0
  4. package/dist/debug.cjs +27 -0
  5. package/dist/debug.cjs.map +1 -0
  6. package/dist/debug.js +19 -0
  7. package/dist/debug.js.map +1 -0
  8. package/dist/dependency-manager.cjs.map +1 -0
  9. package/dist/dependency-manager.js.map +1 -0
  10. package/dist/index.cjs +346 -0
  11. package/dist/index.cjs.map +1 -0
  12. package/dist/index.d.cts +794 -0
  13. package/dist/index.d.ts +675 -386
  14. package/dist/index.js +310 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/management.cjs.map +1 -0
  17. package/dist/management.js.map +1 -0
  18. package/dist/plugins.cjs +4 -0
  19. package/dist/plugins.js +3 -0
  20. package/dist/tracking/dependency-manager.d.ts +37 -0
  21. package/dist/tracking/index.d.ts +12 -0
  22. package/dist/tracking/path-utils.d.ts +52 -0
  23. package/dist/tracking/tracked.d.ts +70 -0
  24. package/dist/tracking/tracking-proxy.d.ts +197 -0
  25. package/dist/tracking-proxy.cjs.map +1 -0
  26. package/dist/tracking-proxy.js.map +1 -0
  27. package/dist/tracking.cjs +19 -0
  28. package/dist/tracking.d.cts +9 -0
  29. package/dist/tracking.d.ts +9 -0
  30. package/dist/tracking.js +4 -0
  31. package/dist/types.cjs +14 -0
  32. package/dist/types.cjs.map +1 -0
  33. package/dist/types.d.cts +8 -0
  34. package/dist/types.d.ts +8 -0
  35. package/dist/types.js +13 -0
  36. package/dist/types.js.map +1 -0
  37. package/dist/watch-entry.cjs +111 -0
  38. package/dist/watch-entry.cjs.map +1 -0
  39. package/dist/watch-entry.js +107 -0
  40. package/dist/watch-entry.js.map +1 -0
  41. package/dist/watch.cjs.map +1 -0
  42. package/dist/watch.js.map +1 -0
  43. package/package.json +122 -19
  44. package/dist/index.cjs.js +0 -2
  45. package/dist/index.cjs.js.map +0 -1
  46. package/dist/index.es.js +0 -670
  47. package/dist/index.es.js.map +0 -1
  48. package/src/Blac.ts +0 -483
  49. package/src/BlacEvent.ts +0 -5
  50. package/src/BlacObservable.ts +0 -88
  51. package/src/BlacObserver.ts +0 -129
  52. package/src/BlacPlugin.ts +0 -13
  53. package/src/Bloc.ts +0 -109
  54. package/src/BlocBase.ts +0 -248
  55. package/src/Cubit.ts +0 -69
  56. package/src/addons/BlacAddon.ts +0 -17
  57. package/src/addons/Persist.ts +0 -105
  58. package/src/addons/index.ts +0 -1
  59. package/src/index.ts +0 -8
  60. package/src/types.ts +0 -63
package/README.md CHANGED
@@ -1,252 +1,212 @@
1
1
  # @blac/core
2
2
 
3
- A lightweight, flexible state management library for JavaScript/TypeScript applications focusing on predictable state transitions.
4
-
5
- ## Features
6
-
7
- - ๐Ÿ”„ Predictable unidirectional data flow
8
- - ๐Ÿงฉ Modular architecture with Blocs and Cubits
9
- - ๐Ÿงช Unit test friendly
10
- - ๐Ÿ”’ Isolated state instances when needed
11
- - ๐Ÿ”Œ Plugin system for extensibility
3
+ Core state management library implementing the BloC pattern for TypeScript applications.
12
4
 
13
5
  ## Installation
14
6
 
15
- Install `@blac/core` using your favorite package manager:
16
-
17
7
  ```bash
18
- # pnpm
8
+ npm install @blac/core
9
+ # or
19
10
  pnpm add @blac/core
20
-
21
- # yarn
11
+ # or
22
12
  yarn add @blac/core
23
-
24
- # npm
25
- npm install @blac/core
26
13
  ```
27
14
 
28
15
  ## Core Concepts
29
16
 
30
- ### Blocs and Cubits
17
+ ### Cubit
31
18
 
32
- **Cubit**: A simple state container with methods to emit new states.
19
+ Simple state container with direct state emission. Use when you need straightforward state updates.
33
20
 
34
21
  ```typescript
35
- class CounterCubit extends Cubit<number> {
22
+ import { Cubit } from '@blac/core';
23
+
24
+ class CounterCubit extends Cubit<{ count: number }> {
36
25
  constructor() {
37
- super(0); // Initial state
26
+ super({ count: 0 });
27
+ }
28
+
29
+ increment() {
30
+ this.emit({ count: this.state.count + 1 });
38
31
  }
39
32
 
40
- increment = () => {
41
- this.emit(this.state + 1);
33
+ decrement() {
34
+ this.update((state) => ({ count: state.count - 1 }));
42
35
  }
43
36
 
44
- decrement = () => {
45
- this.emit(this.state - 1);
37
+ reset() {
38
+ this.patch({ count: 0 });
46
39
  }
47
40
  }
48
41
  ```
49
42
 
50
- **Bloc**: More powerful state container with a reducer pattern for action-based state transitions.
43
+ ## Registry API
44
+
45
+ Manage state container instances with the registry functions:
51
46
 
52
47
  ```typescript
53
- // Define actions
54
- type CounterAction =
55
- | { type: 'increment', amount: number }
56
- | { type: 'decrement', amount: number };
48
+ import { acquire, release, borrow, hasInstance, clear } from '@blac/core';
57
49
 
58
- class CounterBloc extends Bloc<number, CounterAction> {
59
- constructor() {
60
- super(0); // Initial state
61
- }
50
+ // Acquire an instance (creates if needed, increments ref count)
51
+ const counter = acquire(CounterCubit);
62
52
 
63
- reducer = (action: CounterAction, state: number): number => {
64
- switch (action.type) {
65
- case 'increment':
66
- return state + action.amount;
67
- case 'decrement':
68
- return state - action.amount;
69
- }
70
- }
53
+ // Release when done (decrements ref count, disposes when 0)
54
+ release(CounterCubit);
71
55
 
72
- increment = (amount = 1) => {
73
- this.add({ type: 'increment', amount });
74
- }
56
+ // Borrow without affecting ref count
57
+ const instance = borrow(CounterCubit);
75
58
 
76
- decrement = (amount = 1) => {
77
- this.add({ type: 'decrement', amount });
78
- }
59
+ // Check if instance exists
60
+ if (hasInstance(CounterCubit)) {
61
+ // ...
79
62
  }
63
+
64
+ // Clear a specific class
65
+ clear(CounterCubit);
66
+
67
+ // Clear all instances
68
+ clearAll();
80
69
  ```
81
70
 
82
- ### Important: Arrow Functions Required
71
+ ## Decorators
83
72
 
84
- All methods in Bloc or Cubit classes must use arrow function syntax (`method = () => {}`) instead of the traditional method syntax (`method() {}`). This is because arrow functions automatically bind `this` to the class instance. Without this binding, methods called from React components would lose their context and could not access instance properties like `this.state` or `this.emit()`.
73
+ Use the `@blac` decorator to configure container behavior:
85
74
 
86
- ### State Management Patterns
75
+ ```typescript
76
+ import { Cubit, blac } from '@blac/core';
87
77
 
88
- #### Shared State (Default)
78
+ @blac({ isolated: true }) // Each consumer gets its own instance
79
+ class FormCubit extends Cubit<FormState> {}
89
80
 
90
- By default, bloc instances are shared across all consumers:
81
+ @blac({ keepAlive: true }) // Never auto-dispose
82
+ class AuthCubit extends Cubit<AuthState> {}
91
83
 
92
- ```typescript
93
- class GlobalCounterCubit extends Cubit<number> {
94
- constructor() {
95
- super(0);
96
- }
97
-
98
- increment = () => {
99
- this.emit(this.state + 1);
100
- }
101
- }
84
+ @blac({ excludeFromDevTools: true }) // Hide from DevTools
85
+ class InternalCubit extends Cubit<State> {}
102
86
  ```
103
87
 
104
- #### Isolated State
88
+ ## Utilities
89
+
90
+ ### waitUntil
105
91
 
106
- When each consumer needs its own state instance:
92
+ Wait for a specific state condition:
107
93
 
108
94
  ```typescript
109
- class LocalCounterCubit extends Cubit<number> {
110
- static isolated = true; // Each consumer gets its own instance
111
-
112
- constructor() {
113
- super(0);
114
- }
115
-
116
- increment = () => {
117
- this.emit(this.state + 1);
118
- }
119
- }
120
- ```
95
+ import { waitUntil } from '@blac/core';
121
96
 
122
- #### Persistent State
97
+ const counter = acquire(CounterCubit);
123
98
 
124
- Keep state alive even when no consumers are using it:
99
+ // Wait until count reaches 10
100
+ await waitUntil(counter, (state) => state.count >= 10);
125
101
 
126
- ```typescript
127
- class PersistentCounterCubit extends Cubit<number> {
128
- static keepAlive = true; // State persists even when no consumers
129
-
130
- constructor() {
131
- super(0);
132
- }
133
-
134
- increment = () => {
135
- this.emit(this.state + 1);
136
- }
137
- }
102
+ // With timeout
103
+ await waitUntil(counter, (state) => state.count >= 10, {
104
+ timeout: 5000,
105
+ });
138
106
  ```
139
107
 
140
- ## Advanced Usage
141
-
142
- ### Custom Plugins
108
+ ### watch
143
109
 
144
- Create plugins to add functionality like logging, persistence, or analytics:
110
+ Create computed values that react to state changes:
145
111
 
146
112
  ```typescript
147
- import { BlacPlugin, BlacLifecycleEvent, BlocBase } from '@blac/core';
148
-
149
- class LoggerPlugin implements BlacPlugin {
150
- name = 'LoggerPlugin';
151
-
152
- onEvent(event: BlacLifecycleEvent, bloc: BlocBase, params?: any) {
153
- if (event === BlacLifecycleEvent.STATE_CHANGED) {
154
- console.log(`[${bloc._name}] State changed:`, bloc.state);
155
- }
113
+ import { watch, instance } from '@blac/core';
114
+
115
+ class DashboardCubit extends Cubit<DashboardState> {
116
+ constructor() {
117
+ super({ items: [] });
118
+
119
+ // Watch another bloc's state
120
+ watch(
121
+ instance(UserCubit),
122
+ (userState) => userState.preferences,
123
+ (preferences) => this.onPreferencesChanged(preferences),
124
+ );
156
125
  }
157
126
  }
158
-
159
- // Add the plugin to Blac
160
- import { Blac } from '@blac/core';
161
- Blac.addPlugin(new LoggerPlugin());
162
127
  ```
163
128
 
164
- ### Using Props with Blocs
129
+ ## Plugins
165
130
 
166
- Blocs can be designed to accept properties through their constructor, allowing for configurable instances. Here's an example of a `UserProfileBloc` that takes a `userId` prop:
131
+ Extend functionality with plugins:
167
132
 
168
133
  ```typescript
169
- import { Bloc } from '@blac/core'; // Or your specific import path
134
+ import { getPluginManager, type BlacPlugin } from '@blac/core';
170
135
 
171
- // Define props interface (optional, but good practice)
172
- interface UserProfileProps {
173
- userId: string;
174
- }
136
+ const loggingPlugin: BlacPlugin = {
137
+ name: 'logging',
138
+ onStateChange: (container, prevState, newState) => {
139
+ console.log(`[${container.constructor.name}]`, prevState, '->', newState);
140
+ },
141
+ };
175
142
 
176
- // Define state interface
177
- interface UserProfileState {
178
- loading: boolean;
179
- userData: { id: string; name: string; bio?: string } | null;
180
- error: string | null;
181
- }
143
+ getPluginManager().register(loggingPlugin);
144
+ ```
182
145
 
183
- // Define actions (if any, for this example we'll focus on constructor and an async method)
184
- type UserProfileAction = { type: 'dataLoaded', data: any } | { type: 'error', error: string };
185
-
186
- class UserProfileBloc extends Bloc<UserProfileState, UserProfileAction> {
187
- private userId: string;
188
-
189
- // The Blac library or its React bindings (like @blac/react)
190
- // might provide a way to pass these props during instantiation.
191
- // For example, `useBloc(UserProfileBloc, { props: { userId: '123' } })`
192
- constructor(props: UserProfileProps) {
193
- super({ loading: true, userData: null, error: null }); // Initial state
194
- this.userId = props.userId;
195
- // Optional: Set a dynamic name for easier debugging with multiple instances
196
- this._name = `UserProfileBloc_${this.userId}`;
197
- this.fetchUserProfile();
198
- }
146
+ ## Configuration
199
147
 
200
- // Example reducer
201
- reducer = (action: UserProfileAction, state: UserProfileState): UserProfileState => {
202
- switch (action.type) {
203
- case 'dataLoaded':
204
- return { ...state, loading: false, userData: action.data, error: null };
205
- case 'error':
206
- return { ...state, loading: false, error: action.error };
207
- default:
208
- return state;
209
- }
210
- }
148
+ Configure global behavior:
211
149
 
212
- fetchUserProfile = async ()_ => {
213
- this.emit({ ...this.state, loading: true }); // Set loading true before fetch
214
- try {
215
- // Simulate an API call
216
- await new Promise(resolve => setTimeout(resolve, 1000));
217
- const mockUserData = { id: this.userId, name: `User ${this.userId}`, bio: 'Loves Blac states!' };
218
- // Dispatch an action or directly emit a new state
219
- this.add({ type: 'dataLoaded', data: mockUserData });
220
- } catch (e:any) {
221
- this.add({ type: 'error', error: e.message || 'Failed to fetch user profile' });
222
- }
223
- }
224
- }
150
+ ```typescript
151
+ import { configureBlac } from '@blac/core';
152
+
153
+ configureBlac({
154
+ devMode: import.meta.env.DEV,
155
+ });
225
156
  ```
226
157
 
227
158
  ## API Reference
228
159
 
229
- ### Core Classes
160
+ ### State Containers
230
161
 
231
- - `BlocBase<S, P>`: Base class for state containers
232
- - `Cubit<S, P>`: Simple state container with `emit()` and `patch()`
233
- - `Bloc<S, A, P>`: Action-based state container with a reducer pattern
234
- - `Blac`: Singleton manager for all Bloc instances
162
+ | Class | Description |
163
+ | ------------- | ----------------------------------------------------------- |
164
+ | `Cubit<S, P>` | Simple state container with `emit()`, `update()`, `patch()` |
235
165
 
236
- ### React Hooks
166
+ ### Registry Functions
237
167
 
238
- - `useBloc<B>(BlocClass, options?)`: Connect a component to a Bloc
168
+ | Function | Description |
169
+ | -------------------------------- | ------------------------------------------- |
170
+ | `acquire(Class, key?, options?)` | Get or create instance, increment ref count |
171
+ | `release(Class, key?)` | Decrement ref count, dispose when 0 |
172
+ | `borrow(Class, key?)` | Get instance without affecting ref count |
173
+ | `borrowSafe(Class, key?)` | Borrow or return undefined |
174
+ | `ensure(Class, key?, options?)` | Acquire without incrementing ref count |
175
+ | `hasInstance(Class, key?)` | Check if instance exists |
176
+ | `getRefCount(Class, key?)` | Get current reference count |
177
+ | `clear(Class)` | Remove all instances of a class |
178
+ | `clearAll()` | Remove all instances |
239
179
 
240
- ### Lifecycle Events
180
+ ### Exports
241
181
 
242
- - `BLOC_CREATED`: When a new Bloc is instantiated
243
- - `BLOC_DISPOSED`: When a Bloc is disposed
244
- - `LISTENER_ADDED`: When a state listener is added
245
- - `LISTENER_REMOVED`: When a state listener is removed
246
- - `STATE_CHANGED`: When state is updated
247
- - `BLOC_CONSUMER_ADDED`: When a new consumer starts using a Bloc
248
- - `BLOC_CONSUMER_REMOVED`: When a consumer stops using a Bloc
182
+ ```typescript
183
+ // Core classes
184
+ export { Cubit } from '@blac/core';
185
+
186
+ // Registry
187
+ export {
188
+ acquire,
189
+ release,
190
+ borrow,
191
+ ensure,
192
+ hasInstance,
193
+ clear,
194
+ clearAll,
195
+ } from '@blac/core';
196
+
197
+ // Utilities
198
+ export { waitUntil, watch, instance } from '@blac/core';
199
+
200
+ // Decorators
201
+ export { blac } from '@blac/core';
202
+
203
+ // Plugin system
204
+ export { getPluginManager, type BlacPlugin } from '@blac/core';
205
+
206
+ // Configuration
207
+ export { configureBlac, getBlacConfig, isDevMode } from '@blac/core';
208
+ ```
249
209
 
250
210
  ## License
251
211
 
252
- This project is licensed under the MIT License - see the [LICENSE](../../LICENSE) file for details.
212
+ MIT
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StateContainerRegistry.cjs","names":["BLAC_STATIC_PROPS","BLAC_ERROR_PREFIX","getGetterExecutionContext","BLAC_DEFAULTS"],"sources":["../src/plugin/PluginManager.ts","../src/utils/static-props.ts","../src/core/StateContainerRegistry.ts"],"sourcesContent":["import type { StateContainer } from '../core/StateContainer';\nimport type { StateContainerRegistry } from '../core/StateContainerRegistry';\nimport type {\n BlacPlugin,\n PluginContext,\n PluginConfig,\n InstanceMetadata,\n} from './BlacPlugin';\n\n/**\n * Internal structure for tracking installed plugins\n * @internal\n */\ninterface InstalledPlugin {\n plugin: BlacPlugin;\n config: PluginConfig;\n context: PluginContext;\n}\n\n/**\n * Manages plugin lifecycle for the BlaC state management system.\n * Plugins receive notifications about state container lifecycle events.\n *\n * @example\n * ```ts\n * const manager = createPluginManager(registry);\n * manager.install(myPlugin, { environment: 'development' });\n * ```\n */\nexport class PluginManager {\n private plugins = new Map<string, InstalledPlugin>();\n private registry: StateContainerRegistry;\n\n /**\n * Create a new PluginManager\n * @param registry - The StateContainerRegistry to monitor for lifecycle events\n */\n constructor(registry: StateContainerRegistry) {\n this.registry = registry;\n this.setupLifecycleHooks();\n }\n\n /**\n * Install a plugin with optional configuration\n * @param plugin - The plugin to install\n * @param config - Optional plugin configuration\n * @throws Error if plugin is already installed\n */\n install(plugin: BlacPlugin, config: PluginConfig = {}): void {\n const effectiveConfig: PluginConfig = {\n enabled: true,\n environment: 'all',\n ...config,\n };\n\n if (!this.shouldEnablePlugin(effectiveConfig)) {\n console.log(\n `[BlaC] Plugin \"${plugin.name}\" skipped (environment mismatch)`,\n );\n return;\n }\n\n if (this.plugins.has(plugin.name)) {\n throw new Error(`Plugin \"${plugin.name}\" is already installed`);\n }\n\n const context = this.createPluginContext();\n\n this.plugins.set(plugin.name, {\n plugin,\n config: effectiveConfig,\n context,\n });\n\n if (plugin.onInstall) {\n try {\n plugin.onInstall(context);\n } catch (error) {\n console.error(\n `[BlaC] Error installing plugin \"${plugin.name}\":`,\n error,\n );\n this.plugins.delete(plugin.name);\n throw error;\n }\n }\n\n console.log(`[BlaC] Plugin \"${plugin.name}\" v${plugin.version} installed`);\n }\n\n /**\n * Uninstall a plugin by name\n * @param pluginName - The name of the plugin to uninstall\n * @throws Error if plugin is not installed\n */\n uninstall(pluginName: string): void {\n const installed = this.plugins.get(pluginName);\n if (!installed) {\n throw new Error(`Plugin \"${pluginName}\" is not installed`);\n }\n\n if (installed.plugin.onUninstall) {\n try {\n installed.plugin.onUninstall();\n } catch (error) {\n console.error(\n `[BlaC] Error uninstalling plugin \"${pluginName}\":`,\n error,\n );\n }\n }\n\n this.plugins.delete(pluginName);\n console.log(`[BlaC] Plugin \"${pluginName}\" uninstalled`);\n }\n\n /**\n * Get an installed plugin by name\n * @param pluginName - The name of the plugin to retrieve\n * @returns The plugin instance or undefined if not found\n */\n getPlugin(pluginName: string): BlacPlugin | undefined {\n return this.plugins.get(pluginName)?.plugin;\n }\n\n /**\n * Get all installed plugins\n * @returns Array of all installed plugins\n */\n getAllPlugins(): BlacPlugin[] {\n return Array.from(this.plugins.values()).map((p) => p.plugin);\n }\n\n /**\n * Check if a plugin is installed\n * @param pluginName - The name of the plugin to check\n * @returns true if the plugin is installed\n */\n hasPlugin(pluginName: string): boolean {\n return this.plugins.has(pluginName);\n }\n\n /**\n * Uninstall all plugins\n */\n clear(): void {\n for (const name of this.plugins.keys()) {\n this.uninstall(name);\n }\n }\n\n /**\n * Setup lifecycle hooks to notify plugins\n */\n private setupLifecycleHooks(): void {\n // Instance created\n this.registry.on('created', (instance) => {\n this.notifyPlugins('onInstanceCreated', instance);\n });\n\n // State changed\n this.registry.on(\n 'stateChanged',\n (instance, previousState, currentState, callstack) => {\n this.notifyPlugins(\n 'onStateChanged',\n instance,\n previousState,\n currentState,\n callstack,\n );\n },\n );\n\n // Instance disposed\n this.registry.on('disposed', (instance) => {\n this.notifyPlugins('onInstanceDisposed', instance);\n });\n }\n\n /**\n * Notify all plugins of a lifecycle event\n */\n private notifyPlugins(hookName: keyof BlacPlugin, ...args: any[]): void {\n for (const { plugin, config, context } of this.plugins.values()) {\n if (!config.enabled) continue;\n\n const hook = plugin[hookName];\n if (typeof hook === 'function') {\n try {\n (hook as any).apply(plugin, [...args, context]);\n } catch (error) {\n console.error(\n `[BlaC] Error in plugin \"${plugin.name}\" ${hookName}:`,\n error,\n );\n }\n }\n }\n }\n\n /**\n * Create plugin context with safe API access\n */\n private createPluginContext(): PluginContext {\n return {\n getInstanceMetadata: (\n instance: StateContainer<any>,\n ): InstanceMetadata => {\n // const TypeClass = instance.constructor as any;\n\n // if (TypeClass.instances) {\n // for (const [key, entry] of TypeClass.instances) {\n // if (entry.instance === instance) {\n // break;\n // }\n // }\n // }\n\n return {\n id: instance.instanceId,\n className: instance.constructor.name,\n isDisposed: instance.isDisposed,\n name: instance.name,\n lastStateChangeTimestamp: instance.lastUpdateTimestamp,\n createdAt: instance.createdAt,\n state: instance.state,\n isIsolated: instance.instanceId.startsWith('isolated-'),\n };\n },\n\n getState: <S extends object = any>(instance: StateContainer<S>): S => {\n return instance.state;\n },\n\n queryInstances: <T extends StateContainer<any>>(\n typeClass: new (...args: any[]) => T,\n ): T[] => {\n return this.registry.getAll(typeClass as any);\n },\n\n getAllTypes: () => {\n return this.registry.getTypes();\n },\n\n getStats: () => {\n return this.registry.getStats();\n },\n };\n }\n\n /**\n * Check if plugin should be enabled based on environment\n */\n private shouldEnablePlugin(config: PluginConfig): boolean {\n if (!config.enabled) return false;\n if (config.environment === 'all') return true;\n\n const currentEnv = this.getCurrentEnvironment();\n return currentEnv === config.environment;\n }\n\n /**\n * Get current environment\n */\n private getCurrentEnvironment(): 'development' | 'production' | 'test' {\n if (typeof process !== 'undefined') {\n if (process.env.NODE_ENV === 'test') return 'test';\n if (process.env.NODE_ENV === 'production') return 'production';\n return 'development';\n }\n return 'development';\n }\n}\n\n/**\n * Create a plugin manager instance\n * @param registry - The StateContainerRegistry to monitor for lifecycle events\n * @returns A new PluginManager instance\n */\nexport function createPluginManager(\n registry: StateContainerRegistry,\n): PluginManager {\n return new PluginManager(registry);\n}\n","/**\n * Utility functions for accessing static properties on StateContainer classes\n */\n\nimport { BLAC_STATIC_PROPS } from '../constants';\nimport { StateContainerConstructor } from '../types/utilities';\n\n/**\n * Get a static property from a class constructor\n * Type-safe helper that avoids (Type as any) casts\n *\n * @param Type - The class constructor\n * @param propName - The property name to access\n * @param defaultValue - Optional default value if property is undefined\n * @returns The property value or default\n */\nexport function getStaticProp<\n V,\n T extends StateContainerConstructor = StateContainerConstructor,\n>(Type: T, propName: string, defaultValue?: V): V | undefined {\n return (Type as any)[propName] ?? defaultValue;\n}\n\n/**\n * Check if a class is marked as isolated.\n * Isolated classes create separate instances per component.\n * @param Type - The class constructor to check\n * @returns true if the class has `static isolated = true`\n */\nexport function isIsolatedClass<T extends StateContainerConstructor>(\n Type: T,\n): boolean {\n return getStaticProp<boolean>(Type, BLAC_STATIC_PROPS.ISOLATED) === true;\n}\n\n/**\n * Check if a class is marked as keepAlive.\n * KeepAlive classes are never auto-disposed when ref count reaches 0.\n * @param Type - The class constructor to check\n * @returns true if the class has `static keepAlive = true`\n */\nexport function isKeepAliveClass<T extends StateContainerConstructor>(\n Type: T,\n): boolean {\n return getStaticProp<boolean>(Type, BLAC_STATIC_PROPS.KEEP_ALIVE) === true;\n}\n\n/**\n * Check if a class should be excluded from DevTools.\n * Used to prevent infinite loops when DevTools tracks itself.\n * @param Type - The class constructor to check\n * @returns true if the class has `static __excludeFromDevTools = true`\n */\nexport function isExcludedFromDevTools<T extends StateContainerConstructor>(\n Type: T,\n): boolean {\n return (\n getStaticProp<boolean>(Type, BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS) ===\n true\n );\n}\n","import type { StateContainer, StateContainerConfig } from './StateContainer';\nimport { createPluginManager } from '../plugin/PluginManager';\nimport { getGetterExecutionContext } from '../tracking/tracking-proxy';\nimport { BLAC_DEFAULTS, BLAC_ERROR_PREFIX } from '../constants';\nimport { isIsolatedClass, isKeepAliveClass } from '../utils/static-props';\nimport {\n InstanceReadonlyState,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Internal configuration for registered types\n * @internal\n */\ninterface TypeConfig {\n isolated: boolean;\n}\n\n/**\n * Entry in the instance registry, tracking the instance and its reference count\n * @template T - Instance type\n */\nexport interface InstanceEntry<T = any> {\n /** The state container instance */\n instance: T;\n /** Number of active references to this instance */\n refCount: number;\n}\n\n/**\n * Lifecycle events emitted by the registry\n */\nexport type LifecycleEvent = 'created' | 'stateChanged' | 'disposed';\n\n/**\n * Listener function type for each lifecycle event\n * @template E - The lifecycle event type\n */\nexport type LifecycleListener<E extends LifecycleEvent> = E extends 'created'\n ? (container: StateContainer<any>) => void\n : E extends 'stateChanged'\n ? (\n container: StateContainer<any>,\n previousState: any,\n currentState: any,\n callstack?: string,\n ) => void\n : E extends 'disposed'\n ? (container: StateContainer<any>) => void\n : never;\n\n/**\n * Central registry for managing StateContainer instances.\n * Handles instance lifecycle, ref counting, and lifecycle event emission.\n *\n * @example\n * ```ts\n * const registry = new StateContainerRegistry();\n * const instance = registry.acquire(MyBloc); // ownership, must release\n * const other = registry.ensure(OtherBloc); // no ownership, bloc-to-bloc\n * registry.on('stateChanged', (container, prev, next) => {\n * console.log('State changed:', prev, '->', next);\n * });\n * ```\n */\nexport class StateContainerRegistry {\n private readonly instancesByConstructor = new WeakMap<\n StateContainerConstructor,\n Map<string, InstanceEntry>\n >();\n\n private readonly types = new Set<StateContainerConstructor>();\n\n private readonly typeConfigs = new Map<string, TypeConfig>();\n\n private readonly listeners = new Map<\n LifecycleEvent,\n Set<(...args: any[]) => void>\n >();\n\n /**\n * Register a type for lifecycle event tracking\n * @param constructor - The StateContainer class constructor\n */\n registerType<T extends StateContainerConstructor>(constructor: T): void {\n this.types.add(constructor);\n }\n\n /**\n * Register a StateContainer class with configuration\n * @param constructor - The StateContainer class constructor\n * @param isolated - Whether instances should be isolated (component-scoped)\n * @throws Error if type is already registered\n */\n register<T extends StateContainerConstructor>(\n constructor: T,\n isolated = false,\n ): void {\n const className = constructor.name;\n\n if (!isolated && isIsolatedClass(constructor)) {\n isolated = true;\n }\n\n if (this.typeConfigs.has(className)) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} Type \"${className}\" is already registered`,\n );\n }\n\n this.typeConfigs.set(className, { isolated });\n this.registerType(constructor);\n }\n\n private ensureInstancesMap<T extends StateContainerConstructor>(\n Type: T,\n ): Map<string, InstanceEntry> {\n let instances = this.instancesByConstructor.get(Type);\n if (!instances) {\n instances = new Map<string, InstanceEntry>();\n this.instancesByConstructor.set(Type, instances);\n }\n return instances;\n }\n\n /**\n * Get the instances Map for a specific class (public API for stats/debugging)\n */\n getInstancesMap<T extends StateContainerConstructor>(\n Type: T,\n ): Map<string, InstanceEntry> {\n return this.instancesByConstructor.get(Type) || new Map();\n }\n\n private trackExecutionContext(instance: StateContainer<any>): void {\n // Track cross-bloc dependency if we're inside a getter execution\n const context = getGetterExecutionContext();\n if (\n context.tracker &&\n context.currentBloc &&\n context.currentBloc !== instance\n ) {\n // Add this bloc as an external dependency\n context.tracker.externalDependencies.add(instance);\n }\n }\n\n /**\n * Acquire an instance with ref counting (ownership semantics).\n * Creates a new instance if one doesn't exist, or returns existing and increments ref count.\n * You must call `release()` when done to decrement the ref count.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @param options - Acquisition options\n * @param options.canCreate - Whether to create new instance if not found (default: true)\n * @param options.countRef - Whether to increment ref count (default: true)\n * @param options.trackExecutionContext - Whether to track cross-bloc dependency (default: false)\n * @returns The state container instance\n */\n acquire<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n options: {\n canCreate?: boolean;\n countRef?: boolean;\n trackExecutionContext?: boolean;\n } = {},\n ): InstanceType<T> {\n const {\n canCreate = true,\n countRef = true,\n trackExecutionContext = false,\n } = options;\n // Check if this is an isolated type\n const registryConfig = this.typeConfigs.get(Type.name);\n const isolated = isIsolatedClass(Type) || registryConfig?.isolated === true;\n\n const config: StateContainerConfig = {\n instanceId: instanceKey,\n };\n\n if (isolated && !canCreate) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} Cannot get isolated instance \"${instanceKey}\" of ${Type.name} when creation is disabled.`,\n );\n }\n\n // Isolated: always create new instance (not tracked)\n if (isolated) {\n const instance = new Type() as InstanceType<T>;\n instance.initConfig(config);\n // Register type for lifecycle coordination\n this.registerType(Type);\n if (trackExecutionContext) {\n this.trackExecutionContext(instance);\n }\n return instance;\n }\n\n // Shared: singleton pattern with ref counting\n const instances = this.ensureInstancesMap(Type);\n const entry = instances.get(instanceKey);\n\n // Increment ref count if found, only if counting is enabled or refCount is 0\n if (entry && (countRef || entry.refCount === 0)) {\n entry.refCount++;\n }\n\n if (entry) {\n if (trackExecutionContext) {\n this.trackExecutionContext(entry.instance);\n }\n return entry.instance;\n }\n\n if (!canCreate) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} ${Type.name} instance \"${instanceKey}\" not found and creation is disabled.`,\n );\n }\n\n // Create new shared instance\n const instance = new Type() as InstanceType<T>;\n instance.initConfig(config);\n instances.set(instanceKey, { instance, refCount: 1 });\n\n // Register type for lifecycle coordination\n this.registerType(Type);\n\n if (trackExecutionContext) {\n this.trackExecutionContext(instance);\n }\n return instance;\n }\n\n /**\n * Borrow an existing instance without incrementing ref count (borrowing semantics).\n * Tracks cross-bloc dependency for reactive updates.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns The state container instance\n * @throws Error if instance doesn't exist\n */\n borrow<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ): InstanceType<T> {\n return this.acquire(Type, instanceKey, {\n canCreate: false,\n trackExecutionContext: true,\n });\n }\n\n /**\n * Safely borrow an existing instance (borrowing semantics with error handling).\n * Returns discriminated union for type-safe conditional access.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns Discriminated union with either the instance or an error\n */\n borrowSafe<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ):\n | { error: Error; instance: null }\n | { error: null; instance: InstanceType<T> } {\n try {\n const instance = this.borrow(Type, instanceKey);\n return { error: null, instance };\n } catch (error: any) {\n return { error, instance: null };\n }\n }\n\n /**\n * Ensure an instance exists without taking ownership (for bloc-to-bloc communication).\n * Gets existing instance OR creates it if it doesn't exist, without incrementing ref count.\n * Tracks cross-bloc dependency for reactive updates.\n *\n * Use this in bloc-to-bloc communication when you need to ensure an instance exists\n * but don't want to claim ownership (no ref count increment).\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns The state container instance\n */\n ensure<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ): InstanceType<T> {\n return this.acquire(Type, instanceKey, {\n canCreate: true,\n countRef: false,\n trackExecutionContext: true,\n });\n }\n\n /**\n * Release a reference to an instance.\n * Decrements ref count and disposes when it reaches 0 (unless keepAlive).\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @param forceDispose - Force immediate disposal regardless of ref count\n */\n release<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n forceDispose = false,\n ): void {\n const instances = this.ensureInstancesMap(Type);\n const entry = instances.get(instanceKey);\n\n if (!entry) return;\n\n // Force dispose immediately\n if (forceDispose) {\n if (!entry.instance.isDisposed) {\n entry.instance.dispose();\n }\n instances.delete(instanceKey);\n return;\n }\n\n // Decrement ref count\n entry.refCount--;\n\n // Check static keepAlive property\n const keepAlive = isKeepAliveClass(Type);\n\n // Auto-dispose when ref count reaches 0 (unless keepAlive)\n if (entry.refCount <= 0 && !keepAlive) {\n if (!entry.instance.isDisposed) {\n entry.instance.dispose();\n }\n instances.delete(instanceKey);\n }\n }\n\n /**\n * Get all instances of a specific type.\n * @param Type - The StateContainer class constructor\n * @returns Array of all instances\n */\n getAll<T extends StateContainerConstructor>(\n Type: T,\n ): InstanceReadonlyState<T>[] {\n const instances = this.ensureInstancesMap(Type);\n const result: InstanceReadonlyState<T>[] = [];\n for (const entry of instances.values()) {\n result.push(entry.instance);\n }\n return result;\n }\n\n /**\n * Safely iterate over all instances of a type.\n * Skips disposed instances and catches callback errors.\n * @param Type - The StateContainer class constructor\n * @param callback - Function to call for each instance\n */\n forEach<T extends StateContainerConstructor>(\n Type: T,\n callback: (instance: InstanceReadonlyState<T>) => void,\n ): void {\n const instances = this.ensureInstancesMap(Type);\n for (const entry of instances.values()) {\n const instance = entry.instance;\n if (!instance.isDisposed) {\n try {\n callback(instance);\n } catch (error) {\n console.error(\n `${BLAC_ERROR_PREFIX} forEach callback error for ${Type.name}:`,\n error,\n );\n }\n }\n }\n }\n\n /**\n * Clear all instances of a specific type (disposes them).\n * @param Type - The StateContainer class constructor\n */\n clear<T extends StateContainerConstructor>(Type: T): void {\n const instances = this.ensureInstancesMap(Type);\n // Dispose all instances\n for (const entry of instances.values()) {\n if (!entry.instance.isDisposed) {\n entry.instance.dispose();\n }\n }\n // Clear the Map\n instances.clear();\n }\n\n /**\n * Get reference count for an instance.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns Current ref count (0 if instance doesn't exist)\n */\n getRefCount<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ): number {\n const instances = this.ensureInstancesMap(Type);\n const entry = instances.get(instanceKey);\n return entry?.refCount ?? 0;\n }\n\n /**\n * Check if an instance exists.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns true if instance exists\n */\n hasInstance<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ): boolean {\n const instances = this.ensureInstancesMap(Type);\n return instances.has(instanceKey);\n }\n\n /**\n * Clear all instances from all types (for testing)\n *\n * Iterates all registered types and clears their instances.\n * Also clears type tracking to reset the registry state.\n */\n clearAll(): void {\n // Step 1: Clear instances from each type (while we still have the types list)\n for (const Type of this.types) {\n this.clear(Type);\n }\n // Step 2: Now clear type tracking (resets registry state for tests)\n this.types.clear();\n this.typeConfigs.clear();\n }\n\n /**\n * Get registry statistics for debugging.\n * @returns Object with registeredTypes, totalInstances, and typeBreakdown\n */\n getStats(): {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n } {\n const typeBreakdown: Record<string, number> = {};\n let totalInstances = 0;\n\n // Collect stats from each registered type\n for (const Type of this.types) {\n const typeName = Type.name;\n const instances = this.getInstancesMap(Type);\n const count = instances.size;\n\n typeBreakdown[typeName] = count;\n totalInstances += count;\n }\n\n return {\n registeredTypes: this.types.size,\n totalInstances,\n typeBreakdown,\n };\n }\n\n /**\n * Get all registered types (for plugin system).\n * @returns Array of all registered StateContainer class constructors\n */\n getTypes(): StateContainerConstructor[] {\n return Array.from(this.types);\n }\n\n /**\n * Subscribe to lifecycle events\n * @param event - The lifecycle event to listen for\n * @param listener - The listener function to call when the event occurs\n * @returns Unsubscribe function\n */\n on<E extends LifecycleEvent>(\n event: E,\n listener: LifecycleListener<E>,\n ): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n const instance = this.listeners.get(event);\n if (!instance) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} Failed to register listener for event '${event}'`,\n );\n }\n\n instance.add(listener as (...args: any[]) => void);\n\n // Return unsubscribe function\n return () => {\n this.listeners.get(event)?.delete(listener as (...args: any[]) => void);\n };\n }\n\n /**\n * Emit lifecycle event to all listeners\n * @internal - Called by StateContainer lifecycle methods\n */\n emit(event: LifecycleEvent, ...args: any[]): void {\n const listeners = this.listeners.get(event);\n if (!listeners || listeners.size === 0) return; // Zero overhead when no listeners\n\n for (const listener of listeners) {\n try {\n listener(...args);\n } catch (error) {\n console.error(\n `${BLAC_ERROR_PREFIX} Listener error for '${event}':`,\n error,\n );\n }\n }\n }\n}\n\n/**\n * Global default registry instance\n */\nexport const globalRegistry = new StateContainerRegistry();\n\n/**\n * Global plugin manager (initialized lazily)\n */\nlet _globalPluginManager: any = null;\n\n/**\n * Get the global plugin manager\n */\nexport function getPluginManager(): any {\n if (!_globalPluginManager) {\n _globalPluginManager = createPluginManager(globalRegistry);\n }\n return _globalPluginManager;\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StateContainerRegistry.js","names":[],"sources":["../src/plugin/PluginManager.ts","../src/utils/static-props.ts","../src/core/StateContainerRegistry.ts"],"sourcesContent":["import type { StateContainer } from '../core/StateContainer';\nimport type { StateContainerRegistry } from '../core/StateContainerRegistry';\nimport type {\n BlacPlugin,\n PluginContext,\n PluginConfig,\n InstanceMetadata,\n} from './BlacPlugin';\n\n/**\n * Internal structure for tracking installed plugins\n * @internal\n */\ninterface InstalledPlugin {\n plugin: BlacPlugin;\n config: PluginConfig;\n context: PluginContext;\n}\n\n/**\n * Manages plugin lifecycle for the BlaC state management system.\n * Plugins receive notifications about state container lifecycle events.\n *\n * @example\n * ```ts\n * const manager = createPluginManager(registry);\n * manager.install(myPlugin, { environment: 'development' });\n * ```\n */\nexport class PluginManager {\n private plugins = new Map<string, InstalledPlugin>();\n private registry: StateContainerRegistry;\n\n /**\n * Create a new PluginManager\n * @param registry - The StateContainerRegistry to monitor for lifecycle events\n */\n constructor(registry: StateContainerRegistry) {\n this.registry = registry;\n this.setupLifecycleHooks();\n }\n\n /**\n * Install a plugin with optional configuration\n * @param plugin - The plugin to install\n * @param config - Optional plugin configuration\n * @throws Error if plugin is already installed\n */\n install(plugin: BlacPlugin, config: PluginConfig = {}): void {\n const effectiveConfig: PluginConfig = {\n enabled: true,\n environment: 'all',\n ...config,\n };\n\n if (!this.shouldEnablePlugin(effectiveConfig)) {\n console.log(\n `[BlaC] Plugin \"${plugin.name}\" skipped (environment mismatch)`,\n );\n return;\n }\n\n if (this.plugins.has(plugin.name)) {\n throw new Error(`Plugin \"${plugin.name}\" is already installed`);\n }\n\n const context = this.createPluginContext();\n\n this.plugins.set(plugin.name, {\n plugin,\n config: effectiveConfig,\n context,\n });\n\n if (plugin.onInstall) {\n try {\n plugin.onInstall(context);\n } catch (error) {\n console.error(\n `[BlaC] Error installing plugin \"${plugin.name}\":`,\n error,\n );\n this.plugins.delete(plugin.name);\n throw error;\n }\n }\n\n console.log(`[BlaC] Plugin \"${plugin.name}\" v${plugin.version} installed`);\n }\n\n /**\n * Uninstall a plugin by name\n * @param pluginName - The name of the plugin to uninstall\n * @throws Error if plugin is not installed\n */\n uninstall(pluginName: string): void {\n const installed = this.plugins.get(pluginName);\n if (!installed) {\n throw new Error(`Plugin \"${pluginName}\" is not installed`);\n }\n\n if (installed.plugin.onUninstall) {\n try {\n installed.plugin.onUninstall();\n } catch (error) {\n console.error(\n `[BlaC] Error uninstalling plugin \"${pluginName}\":`,\n error,\n );\n }\n }\n\n this.plugins.delete(pluginName);\n console.log(`[BlaC] Plugin \"${pluginName}\" uninstalled`);\n }\n\n /**\n * Get an installed plugin by name\n * @param pluginName - The name of the plugin to retrieve\n * @returns The plugin instance or undefined if not found\n */\n getPlugin(pluginName: string): BlacPlugin | undefined {\n return this.plugins.get(pluginName)?.plugin;\n }\n\n /**\n * Get all installed plugins\n * @returns Array of all installed plugins\n */\n getAllPlugins(): BlacPlugin[] {\n return Array.from(this.plugins.values()).map((p) => p.plugin);\n }\n\n /**\n * Check if a plugin is installed\n * @param pluginName - The name of the plugin to check\n * @returns true if the plugin is installed\n */\n hasPlugin(pluginName: string): boolean {\n return this.plugins.has(pluginName);\n }\n\n /**\n * Uninstall all plugins\n */\n clear(): void {\n for (const name of this.plugins.keys()) {\n this.uninstall(name);\n }\n }\n\n /**\n * Setup lifecycle hooks to notify plugins\n */\n private setupLifecycleHooks(): void {\n // Instance created\n this.registry.on('created', (instance) => {\n this.notifyPlugins('onInstanceCreated', instance);\n });\n\n // State changed\n this.registry.on(\n 'stateChanged',\n (instance, previousState, currentState, callstack) => {\n this.notifyPlugins(\n 'onStateChanged',\n instance,\n previousState,\n currentState,\n callstack,\n );\n },\n );\n\n // Instance disposed\n this.registry.on('disposed', (instance) => {\n this.notifyPlugins('onInstanceDisposed', instance);\n });\n }\n\n /**\n * Notify all plugins of a lifecycle event\n */\n private notifyPlugins(hookName: keyof BlacPlugin, ...args: any[]): void {\n for (const { plugin, config, context } of this.plugins.values()) {\n if (!config.enabled) continue;\n\n const hook = plugin[hookName];\n if (typeof hook === 'function') {\n try {\n (hook as any).apply(plugin, [...args, context]);\n } catch (error) {\n console.error(\n `[BlaC] Error in plugin \"${plugin.name}\" ${hookName}:`,\n error,\n );\n }\n }\n }\n }\n\n /**\n * Create plugin context with safe API access\n */\n private createPluginContext(): PluginContext {\n return {\n getInstanceMetadata: (\n instance: StateContainer<any>,\n ): InstanceMetadata => {\n // const TypeClass = instance.constructor as any;\n\n // if (TypeClass.instances) {\n // for (const [key, entry] of TypeClass.instances) {\n // if (entry.instance === instance) {\n // break;\n // }\n // }\n // }\n\n return {\n id: instance.instanceId,\n className: instance.constructor.name,\n isDisposed: instance.isDisposed,\n name: instance.name,\n lastStateChangeTimestamp: instance.lastUpdateTimestamp,\n createdAt: instance.createdAt,\n state: instance.state,\n isIsolated: instance.instanceId.startsWith('isolated-'),\n };\n },\n\n getState: <S extends object = any>(instance: StateContainer<S>): S => {\n return instance.state;\n },\n\n queryInstances: <T extends StateContainer<any>>(\n typeClass: new (...args: any[]) => T,\n ): T[] => {\n return this.registry.getAll(typeClass as any);\n },\n\n getAllTypes: () => {\n return this.registry.getTypes();\n },\n\n getStats: () => {\n return this.registry.getStats();\n },\n };\n }\n\n /**\n * Check if plugin should be enabled based on environment\n */\n private shouldEnablePlugin(config: PluginConfig): boolean {\n if (!config.enabled) return false;\n if (config.environment === 'all') return true;\n\n const currentEnv = this.getCurrentEnvironment();\n return currentEnv === config.environment;\n }\n\n /**\n * Get current environment\n */\n private getCurrentEnvironment(): 'development' | 'production' | 'test' {\n if (typeof process !== 'undefined') {\n if (process.env.NODE_ENV === 'test') return 'test';\n if (process.env.NODE_ENV === 'production') return 'production';\n return 'development';\n }\n return 'development';\n }\n}\n\n/**\n * Create a plugin manager instance\n * @param registry - The StateContainerRegistry to monitor for lifecycle events\n * @returns A new PluginManager instance\n */\nexport function createPluginManager(\n registry: StateContainerRegistry,\n): PluginManager {\n return new PluginManager(registry);\n}\n","/**\n * Utility functions for accessing static properties on StateContainer classes\n */\n\nimport { BLAC_STATIC_PROPS } from '../constants';\nimport { StateContainerConstructor } from '../types/utilities';\n\n/**\n * Get a static property from a class constructor\n * Type-safe helper that avoids (Type as any) casts\n *\n * @param Type - The class constructor\n * @param propName - The property name to access\n * @param defaultValue - Optional default value if property is undefined\n * @returns The property value or default\n */\nexport function getStaticProp<\n V,\n T extends StateContainerConstructor = StateContainerConstructor,\n>(Type: T, propName: string, defaultValue?: V): V | undefined {\n return (Type as any)[propName] ?? defaultValue;\n}\n\n/**\n * Check if a class is marked as isolated.\n * Isolated classes create separate instances per component.\n * @param Type - The class constructor to check\n * @returns true if the class has `static isolated = true`\n */\nexport function isIsolatedClass<T extends StateContainerConstructor>(\n Type: T,\n): boolean {\n return getStaticProp<boolean>(Type, BLAC_STATIC_PROPS.ISOLATED) === true;\n}\n\n/**\n * Check if a class is marked as keepAlive.\n * KeepAlive classes are never auto-disposed when ref count reaches 0.\n * @param Type - The class constructor to check\n * @returns true if the class has `static keepAlive = true`\n */\nexport function isKeepAliveClass<T extends StateContainerConstructor>(\n Type: T,\n): boolean {\n return getStaticProp<boolean>(Type, BLAC_STATIC_PROPS.KEEP_ALIVE) === true;\n}\n\n/**\n * Check if a class should be excluded from DevTools.\n * Used to prevent infinite loops when DevTools tracks itself.\n * @param Type - The class constructor to check\n * @returns true if the class has `static __excludeFromDevTools = true`\n */\nexport function isExcludedFromDevTools<T extends StateContainerConstructor>(\n Type: T,\n): boolean {\n return (\n getStaticProp<boolean>(Type, BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS) ===\n true\n );\n}\n","import type { StateContainer, StateContainerConfig } from './StateContainer';\nimport { createPluginManager } from '../plugin/PluginManager';\nimport { getGetterExecutionContext } from '../tracking/tracking-proxy';\nimport { BLAC_DEFAULTS, BLAC_ERROR_PREFIX } from '../constants';\nimport { isIsolatedClass, isKeepAliveClass } from '../utils/static-props';\nimport {\n InstanceReadonlyState,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Internal configuration for registered types\n * @internal\n */\ninterface TypeConfig {\n isolated: boolean;\n}\n\n/**\n * Entry in the instance registry, tracking the instance and its reference count\n * @template T - Instance type\n */\nexport interface InstanceEntry<T = any> {\n /** The state container instance */\n instance: T;\n /** Number of active references to this instance */\n refCount: number;\n}\n\n/**\n * Lifecycle events emitted by the registry\n */\nexport type LifecycleEvent = 'created' | 'stateChanged' | 'disposed';\n\n/**\n * Listener function type for each lifecycle event\n * @template E - The lifecycle event type\n */\nexport type LifecycleListener<E extends LifecycleEvent> = E extends 'created'\n ? (container: StateContainer<any>) => void\n : E extends 'stateChanged'\n ? (\n container: StateContainer<any>,\n previousState: any,\n currentState: any,\n callstack?: string,\n ) => void\n : E extends 'disposed'\n ? (container: StateContainer<any>) => void\n : never;\n\n/**\n * Central registry for managing StateContainer instances.\n * Handles instance lifecycle, ref counting, and lifecycle event emission.\n *\n * @example\n * ```ts\n * const registry = new StateContainerRegistry();\n * const instance = registry.acquire(MyBloc); // ownership, must release\n * const other = registry.ensure(OtherBloc); // no ownership, bloc-to-bloc\n * registry.on('stateChanged', (container, prev, next) => {\n * console.log('State changed:', prev, '->', next);\n * });\n * ```\n */\nexport class StateContainerRegistry {\n private readonly instancesByConstructor = new WeakMap<\n StateContainerConstructor,\n Map<string, InstanceEntry>\n >();\n\n private readonly types = new Set<StateContainerConstructor>();\n\n private readonly typeConfigs = new Map<string, TypeConfig>();\n\n private readonly listeners = new Map<\n LifecycleEvent,\n Set<(...args: any[]) => void>\n >();\n\n /**\n * Register a type for lifecycle event tracking\n * @param constructor - The StateContainer class constructor\n */\n registerType<T extends StateContainerConstructor>(constructor: T): void {\n this.types.add(constructor);\n }\n\n /**\n * Register a StateContainer class with configuration\n * @param constructor - The StateContainer class constructor\n * @param isolated - Whether instances should be isolated (component-scoped)\n * @throws Error if type is already registered\n */\n register<T extends StateContainerConstructor>(\n constructor: T,\n isolated = false,\n ): void {\n const className = constructor.name;\n\n if (!isolated && isIsolatedClass(constructor)) {\n isolated = true;\n }\n\n if (this.typeConfigs.has(className)) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} Type \"${className}\" is already registered`,\n );\n }\n\n this.typeConfigs.set(className, { isolated });\n this.registerType(constructor);\n }\n\n private ensureInstancesMap<T extends StateContainerConstructor>(\n Type: T,\n ): Map<string, InstanceEntry> {\n let instances = this.instancesByConstructor.get(Type);\n if (!instances) {\n instances = new Map<string, InstanceEntry>();\n this.instancesByConstructor.set(Type, instances);\n }\n return instances;\n }\n\n /**\n * Get the instances Map for a specific class (public API for stats/debugging)\n */\n getInstancesMap<T extends StateContainerConstructor>(\n Type: T,\n ): Map<string, InstanceEntry> {\n return this.instancesByConstructor.get(Type) || new Map();\n }\n\n private trackExecutionContext(instance: StateContainer<any>): void {\n // Track cross-bloc dependency if we're inside a getter execution\n const context = getGetterExecutionContext();\n if (\n context.tracker &&\n context.currentBloc &&\n context.currentBloc !== instance\n ) {\n // Add this bloc as an external dependency\n context.tracker.externalDependencies.add(instance);\n }\n }\n\n /**\n * Acquire an instance with ref counting (ownership semantics).\n * Creates a new instance if one doesn't exist, or returns existing and increments ref count.\n * You must call `release()` when done to decrement the ref count.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @param options - Acquisition options\n * @param options.canCreate - Whether to create new instance if not found (default: true)\n * @param options.countRef - Whether to increment ref count (default: true)\n * @param options.trackExecutionContext - Whether to track cross-bloc dependency (default: false)\n * @returns The state container instance\n */\n acquire<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n options: {\n canCreate?: boolean;\n countRef?: boolean;\n trackExecutionContext?: boolean;\n } = {},\n ): InstanceType<T> {\n const {\n canCreate = true,\n countRef = true,\n trackExecutionContext = false,\n } = options;\n // Check if this is an isolated type\n const registryConfig = this.typeConfigs.get(Type.name);\n const isolated = isIsolatedClass(Type) || registryConfig?.isolated === true;\n\n const config: StateContainerConfig = {\n instanceId: instanceKey,\n };\n\n if (isolated && !canCreate) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} Cannot get isolated instance \"${instanceKey}\" of ${Type.name} when creation is disabled.`,\n );\n }\n\n // Isolated: always create new instance (not tracked)\n if (isolated) {\n const instance = new Type() as InstanceType<T>;\n instance.initConfig(config);\n // Register type for lifecycle coordination\n this.registerType(Type);\n if (trackExecutionContext) {\n this.trackExecutionContext(instance);\n }\n return instance;\n }\n\n // Shared: singleton pattern with ref counting\n const instances = this.ensureInstancesMap(Type);\n const entry = instances.get(instanceKey);\n\n // Increment ref count if found, only if counting is enabled or refCount is 0\n if (entry && (countRef || entry.refCount === 0)) {\n entry.refCount++;\n }\n\n if (entry) {\n if (trackExecutionContext) {\n this.trackExecutionContext(entry.instance);\n }\n return entry.instance;\n }\n\n if (!canCreate) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} ${Type.name} instance \"${instanceKey}\" not found and creation is disabled.`,\n );\n }\n\n // Create new shared instance\n const instance = new Type() as InstanceType<T>;\n instance.initConfig(config);\n instances.set(instanceKey, { instance, refCount: 1 });\n\n // Register type for lifecycle coordination\n this.registerType(Type);\n\n if (trackExecutionContext) {\n this.trackExecutionContext(instance);\n }\n return instance;\n }\n\n /**\n * Borrow an existing instance without incrementing ref count (borrowing semantics).\n * Tracks cross-bloc dependency for reactive updates.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns The state container instance\n * @throws Error if instance doesn't exist\n */\n borrow<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ): InstanceType<T> {\n return this.acquire(Type, instanceKey, {\n canCreate: false,\n trackExecutionContext: true,\n });\n }\n\n /**\n * Safely borrow an existing instance (borrowing semantics with error handling).\n * Returns discriminated union for type-safe conditional access.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns Discriminated union with either the instance or an error\n */\n borrowSafe<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ):\n | { error: Error; instance: null }\n | { error: null; instance: InstanceType<T> } {\n try {\n const instance = this.borrow(Type, instanceKey);\n return { error: null, instance };\n } catch (error: any) {\n return { error, instance: null };\n }\n }\n\n /**\n * Ensure an instance exists without taking ownership (for bloc-to-bloc communication).\n * Gets existing instance OR creates it if it doesn't exist, without incrementing ref count.\n * Tracks cross-bloc dependency for reactive updates.\n *\n * Use this in bloc-to-bloc communication when you need to ensure an instance exists\n * but don't want to claim ownership (no ref count increment).\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns The state container instance\n */\n ensure<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ): InstanceType<T> {\n return this.acquire(Type, instanceKey, {\n canCreate: true,\n countRef: false,\n trackExecutionContext: true,\n });\n }\n\n /**\n * Release a reference to an instance.\n * Decrements ref count and disposes when it reaches 0 (unless keepAlive).\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @param forceDispose - Force immediate disposal regardless of ref count\n */\n release<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n forceDispose = false,\n ): void {\n const instances = this.ensureInstancesMap(Type);\n const entry = instances.get(instanceKey);\n\n if (!entry) return;\n\n // Force dispose immediately\n if (forceDispose) {\n if (!entry.instance.isDisposed) {\n entry.instance.dispose();\n }\n instances.delete(instanceKey);\n return;\n }\n\n // Decrement ref count\n entry.refCount--;\n\n // Check static keepAlive property\n const keepAlive = isKeepAliveClass(Type);\n\n // Auto-dispose when ref count reaches 0 (unless keepAlive)\n if (entry.refCount <= 0 && !keepAlive) {\n if (!entry.instance.isDisposed) {\n entry.instance.dispose();\n }\n instances.delete(instanceKey);\n }\n }\n\n /**\n * Get all instances of a specific type.\n * @param Type - The StateContainer class constructor\n * @returns Array of all instances\n */\n getAll<T extends StateContainerConstructor>(\n Type: T,\n ): InstanceReadonlyState<T>[] {\n const instances = this.ensureInstancesMap(Type);\n const result: InstanceReadonlyState<T>[] = [];\n for (const entry of instances.values()) {\n result.push(entry.instance);\n }\n return result;\n }\n\n /**\n * Safely iterate over all instances of a type.\n * Skips disposed instances and catches callback errors.\n * @param Type - The StateContainer class constructor\n * @param callback - Function to call for each instance\n */\n forEach<T extends StateContainerConstructor>(\n Type: T,\n callback: (instance: InstanceReadonlyState<T>) => void,\n ): void {\n const instances = this.ensureInstancesMap(Type);\n for (const entry of instances.values()) {\n const instance = entry.instance;\n if (!instance.isDisposed) {\n try {\n callback(instance);\n } catch (error) {\n console.error(\n `${BLAC_ERROR_PREFIX} forEach callback error for ${Type.name}:`,\n error,\n );\n }\n }\n }\n }\n\n /**\n * Clear all instances of a specific type (disposes them).\n * @param Type - The StateContainer class constructor\n */\n clear<T extends StateContainerConstructor>(Type: T): void {\n const instances = this.ensureInstancesMap(Type);\n // Dispose all instances\n for (const entry of instances.values()) {\n if (!entry.instance.isDisposed) {\n entry.instance.dispose();\n }\n }\n // Clear the Map\n instances.clear();\n }\n\n /**\n * Get reference count for an instance.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns Current ref count (0 if instance doesn't exist)\n */\n getRefCount<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ): number {\n const instances = this.ensureInstancesMap(Type);\n const entry = instances.get(instanceKey);\n return entry?.refCount ?? 0;\n }\n\n /**\n * Check if an instance exists.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Instance key (defaults to 'default')\n * @returns true if instance exists\n */\n hasInstance<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY,\n ): boolean {\n const instances = this.ensureInstancesMap(Type);\n return instances.has(instanceKey);\n }\n\n /**\n * Clear all instances from all types (for testing)\n *\n * Iterates all registered types and clears their instances.\n * Also clears type tracking to reset the registry state.\n */\n clearAll(): void {\n // Step 1: Clear instances from each type (while we still have the types list)\n for (const Type of this.types) {\n this.clear(Type);\n }\n // Step 2: Now clear type tracking (resets registry state for tests)\n this.types.clear();\n this.typeConfigs.clear();\n }\n\n /**\n * Get registry statistics for debugging.\n * @returns Object with registeredTypes, totalInstances, and typeBreakdown\n */\n getStats(): {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n } {\n const typeBreakdown: Record<string, number> = {};\n let totalInstances = 0;\n\n // Collect stats from each registered type\n for (const Type of this.types) {\n const typeName = Type.name;\n const instances = this.getInstancesMap(Type);\n const count = instances.size;\n\n typeBreakdown[typeName] = count;\n totalInstances += count;\n }\n\n return {\n registeredTypes: this.types.size,\n totalInstances,\n typeBreakdown,\n };\n }\n\n /**\n * Get all registered types (for plugin system).\n * @returns Array of all registered StateContainer class constructors\n */\n getTypes(): StateContainerConstructor[] {\n return Array.from(this.types);\n }\n\n /**\n * Subscribe to lifecycle events\n * @param event - The lifecycle event to listen for\n * @param listener - The listener function to call when the event occurs\n * @returns Unsubscribe function\n */\n on<E extends LifecycleEvent>(\n event: E,\n listener: LifecycleListener<E>,\n ): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n const instance = this.listeners.get(event);\n if (!instance) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} Failed to register listener for event '${event}'`,\n );\n }\n\n instance.add(listener as (...args: any[]) => void);\n\n // Return unsubscribe function\n return () => {\n this.listeners.get(event)?.delete(listener as (...args: any[]) => void);\n };\n }\n\n /**\n * Emit lifecycle event to all listeners\n * @internal - Called by StateContainer lifecycle methods\n */\n emit(event: LifecycleEvent, ...args: any[]): void {\n const listeners = this.listeners.get(event);\n if (!listeners || listeners.size === 0) return; // Zero overhead when no listeners\n\n for (const listener of listeners) {\n try {\n listener(...args);\n } catch (error) {\n console.error(\n `${BLAC_ERROR_PREFIX} Listener error for '${event}':`,\n error,\n );\n }\n }\n }\n}\n\n/**\n * Global default registry instance\n */\nexport const globalRegistry = new StateContainerRegistry();\n\n/**\n * Global plugin manager (initialized lazily)\n */\nlet _globalPluginManager: any = null;\n\n/**\n * Get the global plugin manager\n */\nexport function getPluginManager(): any {\n if (!_globalPluginManager) {\n _globalPluginManager = createPluginManager(globalRegistry);\n }\n return _globalPluginManager;\n}\n"],"mappings":"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"}
package/dist/debug.cjs ADDED
@@ -0,0 +1,27 @@
1
+ const require_StateContainerRegistry = require('./StateContainerRegistry.cjs');
2
+ const require_management = require('./management.cjs');
3
+
4
+ //#region src/registry/config.ts
5
+ let _registry = require_StateContainerRegistry.globalRegistry;
6
+ function getRegistry() {
7
+ return _registry;
8
+ }
9
+ function setRegistry(registry) {
10
+ _registry.clearAll();
11
+ _registry = registry;
12
+ }
13
+ function getStats() {
14
+ return _registry.getStats();
15
+ }
16
+
17
+ //#endregion
18
+ exports.forEach = require_management.forEach;
19
+ exports.getAll = require_management.getAll;
20
+ exports.getRefCount = require_management.getRefCount;
21
+ exports.getRegistry = getRegistry;
22
+ exports.getStats = getStats;
23
+ exports.globalRegistry = require_StateContainerRegistry.globalRegistry;
24
+ exports.hasInstance = require_management.hasInstance;
25
+ exports.register = require_management.register;
26
+ exports.setRegistry = setRegistry;
27
+ //# sourceMappingURL=debug.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.cjs","names":["globalRegistry"],"sources":["../src/registry/config.ts"],"sourcesContent":["import {\n globalRegistry,\n StateContainerRegistry,\n} from '../core/StateContainerRegistry';\n\nlet _registry = globalRegistry;\n\nexport function getRegistry(): StateContainerRegistry {\n return _registry;\n}\n\nexport function setRegistry(registry: StateContainerRegistry): void {\n _registry.clearAll();\n _registry = registry;\n}\n\nexport function getStats(): {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n} {\n return _registry.getStats();\n}\n"],"mappings":";;;;AAKA,IAAI,YAAYA;AAEhB,SAAgB,cAAsC;AACpD,QAAO;;AAGT,SAAgB,YAAY,UAAwC;AAClE,WAAU,UAAU;AACpB,aAAY;;AAGd,SAAgB,WAId;AACA,QAAO,UAAU,UAAU"}
package/dist/debug.js ADDED
@@ -0,0 +1,19 @@
1
+ import { n as globalRegistry } from "./StateContainerRegistry.js";
2
+ import { a as getAll, i as forEach, o as getRefCount, r as register, s as hasInstance } from "./management.js";
3
+
4
+ //#region src/registry/config.ts
5
+ let _registry = globalRegistry;
6
+ function getRegistry() {
7
+ return _registry;
8
+ }
9
+ function setRegistry(registry) {
10
+ _registry.clearAll();
11
+ _registry = registry;
12
+ }
13
+ function getStats() {
14
+ return _registry.getStats();
15
+ }
16
+
17
+ //#endregion
18
+ export { forEach, getAll, getRefCount, getRegistry, getStats, globalRegistry, hasInstance, register, setRegistry };
19
+ //# sourceMappingURL=debug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.js","names":[],"sources":["../src/registry/config.ts"],"sourcesContent":["import {\n globalRegistry,\n StateContainerRegistry,\n} from '../core/StateContainerRegistry';\n\nlet _registry = globalRegistry;\n\nexport function getRegistry(): StateContainerRegistry {\n return _registry;\n}\n\nexport function setRegistry(registry: StateContainerRegistry): void {\n _registry.clearAll();\n _registry = registry;\n}\n\nexport function getStats(): {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n} {\n return _registry.getStats();\n}\n"],"mappings":";;;;AAKA,IAAI,YAAY;AAEhB,SAAgB,cAAsC;AACpD,QAAO;;AAGT,SAAgB,YAAY,UAAwC;AAClE,WAAU,UAAU;AACpB,aAAY;;AAGd,SAAgB,WAId;AACA,QAAO,UAAU,UAAU"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-manager.cjs","names":[],"sources":["../src/tracking/dependency-manager.ts"],"sourcesContent":["import type { StateContainerInstance } from '../types/utilities';\n\n/**\n * Manages subscriptions to state container dependencies.\n * Provides efficient sync mechanism to add/remove subscriptions\n * as dependencies change between callback invocations.\n */\nexport class DependencyManager {\n private subscriptions = new Map<StateContainerInstance, () => void>();\n private currentDeps = new Set<StateContainerInstance>();\n\n /**\n * Sync subscriptions with a new set of dependencies.\n * Adds subscriptions for new deps, removes subscriptions for stale deps.\n *\n * @param newDeps - The new set of dependencies to subscribe to\n * @param onChange - Callback to invoke when any dependency changes\n * @param exclude - Optional instance to exclude from subscriptions (e.g., primary bloc)\n * @returns true if the dependency set changed, false if unchanged\n */\n sync(\n newDeps: Set<StateContainerInstance>,\n onChange: () => void,\n exclude?: StateContainerInstance,\n ): boolean {\n const filteredNewDeps = new Set<StateContainerInstance>();\n for (const dep of newDeps) {\n if (dep !== exclude && !dep.isDisposed) {\n filteredNewDeps.add(dep);\n }\n }\n\n if (this.areSetsEqual(this.currentDeps, filteredNewDeps)) {\n return false;\n }\n\n for (const dep of this.currentDeps) {\n if (!filteredNewDeps.has(dep)) {\n const unsub = this.subscriptions.get(dep);\n if (unsub) {\n unsub();\n this.subscriptions.delete(dep);\n }\n }\n }\n\n for (const dep of filteredNewDeps) {\n if (!this.currentDeps.has(dep) && !this.subscriptions.has(dep)) {\n const unsub = dep.subscribe(onChange);\n this.subscriptions.set(dep, unsub);\n }\n }\n\n this.currentDeps = filteredNewDeps;\n return true;\n }\n\n /**\n * Add a single dependency subscription.\n */\n add(dep: StateContainerInstance, onChange: () => void): void {\n if (this.subscriptions.has(dep) || dep.isDisposed) {\n return;\n }\n const unsub = dep.subscribe(onChange);\n this.subscriptions.set(dep, unsub);\n this.currentDeps.add(dep);\n }\n\n /**\n * Check if a dependency is currently subscribed.\n */\n has(dep: StateContainerInstance): boolean {\n return this.currentDeps.has(dep);\n }\n\n /**\n * Get the current set of dependencies.\n */\n getDependencies(): Set<StateContainerInstance> {\n return new Set(this.currentDeps);\n }\n\n /**\n * Clean up all active subscriptions.\n */\n cleanup(): void {\n for (const unsub of this.subscriptions.values()) {\n unsub();\n }\n this.subscriptions.clear();\n this.currentDeps.clear();\n }\n\n private areSetsEqual(\n a: Set<StateContainerInstance>,\n b: Set<StateContainerInstance>,\n ): boolean {\n if (a.size !== b.size) return false;\n for (const item of a) {\n if (!b.has(item)) return false;\n }\n return true;\n }\n}\n"],"mappings":";;;;;;;AAOA,IAAa,oBAAb,MAA+B;;uCACL,IAAI,KAAyC;qCAC/C,IAAI,KAA6B;;;;;;;;;;;CAWvD,KACE,SACA,UACA,SACS;EACT,MAAM,kCAAkB,IAAI,KAA6B;AACzD,OAAK,MAAM,OAAO,QAChB,KAAI,QAAQ,WAAW,CAAC,IAAI,WAC1B,iBAAgB,IAAI,IAAI;AAI5B,MAAI,KAAK,aAAa,KAAK,aAAa,gBAAgB,CACtD,QAAO;AAGT,OAAK,MAAM,OAAO,KAAK,YACrB,KAAI,CAAC,gBAAgB,IAAI,IAAI,EAAE;GAC7B,MAAM,QAAQ,KAAK,cAAc,IAAI,IAAI;AACzC,OAAI,OAAO;AACT,WAAO;AACP,SAAK,cAAc,OAAO,IAAI;;;AAKpC,OAAK,MAAM,OAAO,gBAChB,KAAI,CAAC,KAAK,YAAY,IAAI,IAAI,IAAI,CAAC,KAAK,cAAc,IAAI,IAAI,EAAE;GAC9D,MAAM,QAAQ,IAAI,UAAU,SAAS;AACrC,QAAK,cAAc,IAAI,KAAK,MAAM;;AAItC,OAAK,cAAc;AACnB,SAAO;;;;;CAMT,IAAI,KAA6B,UAA4B;AAC3D,MAAI,KAAK,cAAc,IAAI,IAAI,IAAI,IAAI,WACrC;EAEF,MAAM,QAAQ,IAAI,UAAU,SAAS;AACrC,OAAK,cAAc,IAAI,KAAK,MAAM;AAClC,OAAK,YAAY,IAAI,IAAI;;;;;CAM3B,IAAI,KAAsC;AACxC,SAAO,KAAK,YAAY,IAAI,IAAI;;;;;CAMlC,kBAA+C;AAC7C,SAAO,IAAI,IAAI,KAAK,YAAY;;;;;CAMlC,UAAgB;AACd,OAAK,MAAM,SAAS,KAAK,cAAc,QAAQ,CAC7C,QAAO;AAET,OAAK,cAAc,OAAO;AAC1B,OAAK,YAAY,OAAO;;CAG1B,AAAQ,aACN,GACA,GACS;AACT,MAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,OAAK,MAAM,QAAQ,EACjB,KAAI,CAAC,EAAE,IAAI,KAAK,CAAE,QAAO;AAE3B,SAAO"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-manager.js","names":[],"sources":["../src/tracking/dependency-manager.ts"],"sourcesContent":["import type { StateContainerInstance } from '../types/utilities';\n\n/**\n * Manages subscriptions to state container dependencies.\n * Provides efficient sync mechanism to add/remove subscriptions\n * as dependencies change between callback invocations.\n */\nexport class DependencyManager {\n private subscriptions = new Map<StateContainerInstance, () => void>();\n private currentDeps = new Set<StateContainerInstance>();\n\n /**\n * Sync subscriptions with a new set of dependencies.\n * Adds subscriptions for new deps, removes subscriptions for stale deps.\n *\n * @param newDeps - The new set of dependencies to subscribe to\n * @param onChange - Callback to invoke when any dependency changes\n * @param exclude - Optional instance to exclude from subscriptions (e.g., primary bloc)\n * @returns true if the dependency set changed, false if unchanged\n */\n sync(\n newDeps: Set<StateContainerInstance>,\n onChange: () => void,\n exclude?: StateContainerInstance,\n ): boolean {\n const filteredNewDeps = new Set<StateContainerInstance>();\n for (const dep of newDeps) {\n if (dep !== exclude && !dep.isDisposed) {\n filteredNewDeps.add(dep);\n }\n }\n\n if (this.areSetsEqual(this.currentDeps, filteredNewDeps)) {\n return false;\n }\n\n for (const dep of this.currentDeps) {\n if (!filteredNewDeps.has(dep)) {\n const unsub = this.subscriptions.get(dep);\n if (unsub) {\n unsub();\n this.subscriptions.delete(dep);\n }\n }\n }\n\n for (const dep of filteredNewDeps) {\n if (!this.currentDeps.has(dep) && !this.subscriptions.has(dep)) {\n const unsub = dep.subscribe(onChange);\n this.subscriptions.set(dep, unsub);\n }\n }\n\n this.currentDeps = filteredNewDeps;\n return true;\n }\n\n /**\n * Add a single dependency subscription.\n */\n add(dep: StateContainerInstance, onChange: () => void): void {\n if (this.subscriptions.has(dep) || dep.isDisposed) {\n return;\n }\n const unsub = dep.subscribe(onChange);\n this.subscriptions.set(dep, unsub);\n this.currentDeps.add(dep);\n }\n\n /**\n * Check if a dependency is currently subscribed.\n */\n has(dep: StateContainerInstance): boolean {\n return this.currentDeps.has(dep);\n }\n\n /**\n * Get the current set of dependencies.\n */\n getDependencies(): Set<StateContainerInstance> {\n return new Set(this.currentDeps);\n }\n\n /**\n * Clean up all active subscriptions.\n */\n cleanup(): void {\n for (const unsub of this.subscriptions.values()) {\n unsub();\n }\n this.subscriptions.clear();\n this.currentDeps.clear();\n }\n\n private areSetsEqual(\n a: Set<StateContainerInstance>,\n b: Set<StateContainerInstance>,\n ): boolean {\n if (a.size !== b.size) return false;\n for (const item of a) {\n if (!b.has(item)) return false;\n }\n return true;\n }\n}\n"],"mappings":";;;;;;AAOA,IAAa,oBAAb,MAA+B;;uCACL,IAAI,KAAyC;qCAC/C,IAAI,KAA6B;;;;;;;;;;;CAWvD,KACE,SACA,UACA,SACS;EACT,MAAM,kCAAkB,IAAI,KAA6B;AACzD,OAAK,MAAM,OAAO,QAChB,KAAI,QAAQ,WAAW,CAAC,IAAI,WAC1B,iBAAgB,IAAI,IAAI;AAI5B,MAAI,KAAK,aAAa,KAAK,aAAa,gBAAgB,CACtD,QAAO;AAGT,OAAK,MAAM,OAAO,KAAK,YACrB,KAAI,CAAC,gBAAgB,IAAI,IAAI,EAAE;GAC7B,MAAM,QAAQ,KAAK,cAAc,IAAI,IAAI;AACzC,OAAI,OAAO;AACT,WAAO;AACP,SAAK,cAAc,OAAO,IAAI;;;AAKpC,OAAK,MAAM,OAAO,gBAChB,KAAI,CAAC,KAAK,YAAY,IAAI,IAAI,IAAI,CAAC,KAAK,cAAc,IAAI,IAAI,EAAE;GAC9D,MAAM,QAAQ,IAAI,UAAU,SAAS;AACrC,QAAK,cAAc,IAAI,KAAK,MAAM;;AAItC,OAAK,cAAc;AACnB,SAAO;;;;;CAMT,IAAI,KAA6B,UAA4B;AAC3D,MAAI,KAAK,cAAc,IAAI,IAAI,IAAI,IAAI,WACrC;EAEF,MAAM,QAAQ,IAAI,UAAU,SAAS;AACrC,OAAK,cAAc,IAAI,KAAK,MAAM;AAClC,OAAK,YAAY,IAAI,IAAI;;;;;CAM3B,IAAI,KAAsC;AACxC,SAAO,KAAK,YAAY,IAAI,IAAI;;;;;CAMlC,kBAA+C;AAC7C,SAAO,IAAI,IAAI,KAAK,YAAY;;;;;CAMlC,UAAgB;AACd,OAAK,MAAM,SAAS,KAAK,cAAc,QAAQ,CAC7C,QAAO;AAET,OAAK,cAAc,OAAO;AAC1B,OAAK,YAAY,OAAO;;CAG1B,AAAQ,aACN,GACA,GACS;AACT,MAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,OAAK,MAAM,QAAQ,EACjB,KAAI,CAAC,EAAE,IAAI,KAAK,CAAE,QAAO;AAE3B,SAAO"}