Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

@blac/core

Package Overview
Dependencies
Maintainers
1
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@blac/core - npm Package Compare versions

Comparing version
2.0.4
to
2.0.5
+81
dist/constants.d.ts
/**
* Default configuration constants for BlaC
*
* Centralized location for all magic numbers and default values.
*/
/**
* Default configuration constants for BlaC
*/
export declare const BLAC_DEFAULTS: {
/**
* Default instance key for shared instances
*/
readonly DEFAULT_INSTANCE_KEY: "default";
/**
* Maximum getter nesting depth (prevents infinite recursion)
*/
readonly MAX_GETTER_DEPTH: 10;
/**
* Default cleanup interval for subscriptions (30 seconds)
*/
readonly CLEANUP_INTERVAL_MS: 30000;
/**
* Cleanup interval for weak reference stage (10 seconds)
*/
readonly WEAKREF_CLEANUP_INTERVAL_MS: 10000;
/**
* Default maximum subscriptions per container
*/
readonly MAX_SUBSCRIPTIONS: 1000;
/**
* Maximum subscriptions for high-performance mode
*/
readonly MAX_SUBSCRIPTIONS_HIGH_PERF: 10000;
/**
* Default timeout for pipeline execution (5 seconds)
*/
readonly PIPELINE_TIMEOUT_MS: 5000;
/**
* Cleanup interval for high-performance mode (5 seconds)
*/
readonly CLEANUP_INTERVAL_HIGH_PERF_MS: 5000;
/**
* Maximum number of stages in a pipeline
*/
readonly MAX_PIPELINE_STAGES: 30;
};
/**
* Static property names for StateContainer classes
* Used for feature flags and configuration on bloc classes
*/
export declare const BLAC_STATIC_PROPS: {
/**
* Mark a bloc as isolated (each component gets its own instance)
*/
readonly ISOLATED: "isolated";
/**
* Mark a bloc to never be auto-disposed (kept alive permanently)
*/
readonly KEEP_ALIVE: "keepAlive";
/**
* Exclude a bloc from DevTools reporting (prevents infinite loops)
*/
readonly EXCLUDE_FROM_DEVTOOLS: "__excludeFromDevTools";
};
/**
* ID generation patterns and constants
*/
export declare const BLAC_ID_PATTERNS: {
/**
* Prefix for isolated instance keys
*/
readonly ISOLATED_PREFIX: "isolated-";
/**
* Length of generated ID portion (9 characters from base36)
*/
readonly ID_LENGTH: 9;
};
/**
* Standard error message prefix
*/
export declare const BLAC_ERROR_PREFIX: "[BlaC]";
import { StateContainer } from './StateContainer';
/**
* Simple state container with direct state emission.
* Extends StateContainer with public methods for emitting and updating state.
*
* @template S - State type
*/
export declare abstract class Cubit<S extends object = any> extends StateContainer<S> {
constructor(initialState: S);
/**
* Replace state with a new value and notify all listeners
* @param newState - The new state value
*/
emit(newState: S): void;
/**
* Transform current state using an updater function and emit the new state
* @param updater - Function that receives current state and returns new state
*/
update(updater: (current: S) => S): void;
/**
* Merge partial state changes into current state (only for object states)
*/
patch: S extends object ? (partial: Partial<S>) => void : never;
}
import type { StateContainerConstructor } from '../types/utilities';
/**
* Configuration options for initializing a StateContainer instance
*/
export interface StateContainerConfig {
/** Display name for the instance (defaults to class name) */
name?: string;
/** Enable debug logging for this instance */
debug?: boolean;
/** Custom instance identifier */
instanceId?: string;
}
/**
* Listener function for state changes
* @internal
*/
type StateListener<S> = (state: S) => void;
/**
* System events emitted by StateContainer lifecycle
*/
export type SystemEvent = 'stateChanged' | 'dispose';
/**
* Payload types for each system event
* @template S - State type
*/
export interface SystemEventPayloads<S> {
/** Emitted when state changes via emit() or update() */
stateChanged: {
state: S;
previousState: S;
};
/** Emitted when the instance is disposed */
dispose: void;
}
/**
* Handler function for system events
* @internal
*/
type SystemEventHandler<S, E extends SystemEvent> = (payload: SystemEventPayloads<S>[E]) => void;
/**
* Abstract base class for all state containers in BlaC.
* Provides lifecycle management, subscription handling, ref counting,
* and integration with the global registry.
*
* @template S - State type managed by this container
*
* @example
* ```ts
* class CounterBloc extends StateContainer<{ count: number }> {
* constructor() {
* super({ count: 0 });
* }
* increment() {
* this.emit({ count: this.state.count + 1 });
* }
* }
* ```
*/
export declare abstract class StateContainer<S extends object = any> {
static __excludeFromDevTools: boolean;
static enableStackTrace: boolean;
private _state;
private readonly listeners;
private _disposed;
private config;
private readonly systemEventHandlers;
/** Display name for this instance */
name: string;
/** Whether debug logging is enabled */
debug: boolean;
/** Unique identifier for this instance */
instanceId: string;
/** Timestamp when this instance was created */
createdAt: number;
private _dependencies;
get dependencies(): ReadonlyMap<StateContainerConstructor, string>;
protected depend<T extends StateContainerConstructor>(Type: T, instanceKey?: string): () => InstanceType<T>;
constructor(initialState: S);
/**
* Initialize configuration for this instance.
* Called by the registry after construction.
* @param config - Configuration options
*/
initConfig(config: StateContainerConfig): void;
/** Current state value */
get state(): Readonly<S>;
/** Whether this instance has been disposed */
get isDisposed(): boolean;
/**
* Subscribe to state changes
* @param listener - Function called when state changes
* @returns Unsubscribe function
*/
subscribe(listener: StateListener<S>): () => void;
/**
* Dispose this instance and clean up resources.
* Clears all listeners and emits the 'dispose' system event.
*/
dispose(): void;
/**
* Emit a new state value and notify all listeners.
* @param newState - The new state value
* @protected
*/
protected emit(newState: S): void;
private captureStackTrace;
private formatStackLine;
private cleanFilePath;
/** Timestamp of the last state update */
lastUpdateTimestamp: number;
/**
* Update state using a transform function.
* @param updater - Function that receives current state and returns new state
* @protected
*/
protected update(updater: (current: S) => S): void;
/**
* Subscribe to system lifecycle events.
* @param event - The event type to listen for
* @param handler - Handler function called when event occurs
* @returns Unsubscribe function
* @protected
*/
protected onSystemEvent: <E extends SystemEvent>(event: E, handler: SystemEventHandler<S, E>) => (() => void);
private emitSystemEvent;
}
export {};
import type { StateContainer } from './StateContainer';
import { InstanceReadonlyState, StateContainerConstructor } from '../types/utilities';
/**
* Entry in the instance registry, tracking the instance and its reference count
* @template T - Instance type
*/
export interface InstanceEntry<T = any> {
/** The state container instance */
instance: T;
/** Number of active references to this instance */
refCount: number;
}
/**
* Lifecycle events emitted by the registry
*/
export type LifecycleEvent = 'created' | 'stateChanged' | 'disposed';
/**
* Listener function type for each lifecycle event
* @template E - The lifecycle event type
*/
export type LifecycleListener<E extends LifecycleEvent> = E extends 'created' ? (container: StateContainer<any>) => void : E extends 'stateChanged' ? (container: StateContainer<any>, previousState: any, currentState: any, callstack?: string) => void : E extends 'disposed' ? (container: StateContainer<any>) => void : never;
/**
* Central registry for managing StateContainer instances.
* Handles instance lifecycle, ref counting, and lifecycle event emission.
*
* @example
* ```ts
* const registry = new StateContainerRegistry();
* const instance = registry.acquire(MyBloc); // ownership, must release
* const other = registry.ensure(OtherBloc); // no ownership, bloc-to-bloc
* registry.on('stateChanged', (container, prev, next) => {
* console.log('State changed:', prev, '->', next);
* });
* ```
*/
export declare class StateContainerRegistry {
private readonly instancesByConstructor;
private readonly types;
private readonly typeConfigs;
private readonly listeners;
/**
* Register a type for lifecycle event tracking
* @param constructor - The StateContainer class constructor
*/
registerType<T extends StateContainerConstructor>(constructor: T): void;
/**
* Register a StateContainer class with configuration
* @param constructor - The StateContainer class constructor
* @param isolated - Whether instances should be isolated (component-scoped)
* @throws Error if type is already registered
*/
register<T extends StateContainerConstructor>(constructor: T, isolated?: boolean): void;
private ensureInstancesMap;
/**
* Get the instances Map for a specific class (public API for stats/debugging)
*/
getInstancesMap<T extends StateContainerConstructor>(Type: T): Map<string, InstanceEntry>;
/**
* Acquire an instance with ref counting (ownership semantics).
* Creates a new instance if one doesn't exist, or returns existing and increments ref count.
* You must call `release()` when done to decrement the ref count.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param options - Acquisition options
* @param options.canCreate - Whether to create new instance if not found (default: true)
* @param options.countRef - Whether to increment ref count (default: true)
* @returns The state container instance
*/
acquire<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string, options?: {
canCreate?: boolean;
countRef?: boolean;
}): InstanceType<T>;
/**
* Borrow an existing instance without incrementing ref count (borrowing semantics).
* Tracks cross-bloc dependency for reactive updates.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
* @throws Error if instance doesn't exist
*/
borrow<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): InstanceType<T>;
/**
* Safely borrow an existing instance (borrowing semantics with error handling).
* Returns discriminated union for type-safe conditional access.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Discriminated union with either the instance or an error
*/
borrowSafe<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): {
error: Error;
instance: null;
} | {
error: null;
instance: InstanceType<T>;
};
/**
* Ensure an instance exists without taking ownership (for bloc-to-bloc communication).
* Gets existing instance OR creates it if it doesn't exist, without incrementing ref count.
* Tracks cross-bloc dependency for reactive updates.
*
* Use this in bloc-to-bloc communication when you need to ensure an instance exists
* but don't want to claim ownership (no ref count increment).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
*/
ensure<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): InstanceType<T>;
/**
* Release a reference to an instance.
* Decrements ref count and disposes when it reaches 0 (unless keepAlive).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param forceDispose - Force immediate disposal regardless of ref count
*/
release<T extends StateContainerConstructor>(Type: T, instanceKey?: string, forceDispose?: boolean): void;
/**
* Get all instances of a specific type.
* @param Type - The StateContainer class constructor
* @returns Array of all instances
*/
getAll<T extends StateContainerConstructor>(Type: T): InstanceReadonlyState<T>[];
/**
* Safely iterate over all instances of a type.
* Skips disposed instances and catches callback errors.
* @param Type - The StateContainer class constructor
* @param callback - Function to call for each instance
*/
forEach<T extends StateContainerConstructor>(Type: T, callback: (instance: InstanceReadonlyState<T>) => void): void;
/**
* Clear all instances of a specific type (disposes them).
* @param Type - The StateContainer class constructor
*/
clear<T extends StateContainerConstructor>(Type: T): void;
/**
* Get reference count for an instance.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Current ref count (0 if instance doesn't exist)
*/
getRefCount<T extends StateContainerConstructor>(Type: T, instanceKey?: string): number;
/**
* Check if an instance exists.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns true if instance exists
*/
hasInstance<T extends StateContainerConstructor>(Type: T, instanceKey?: string): boolean;
/**
* Clear all instances from all types (for testing)
*
* Iterates all registered types and clears their instances.
* Also clears type tracking to reset the registry state.
*/
clearAll(): void;
/**
* Get registry statistics for debugging.
* @returns Object with registeredTypes, totalInstances, and typeBreakdown
*/
getStats(): {
registeredTypes: number;
totalInstances: number;
typeBreakdown: Record<string, number>;
};
/**
* Get all registered types (for plugin system).
* @returns Array of all registered StateContainer class constructors
*/
getTypes(): StateContainerConstructor[];
/**
* Subscribe to lifecycle events
* @param event - The lifecycle event to listen for
* @param listener - The listener function to call when the event occurs
* @returns Unsubscribe function
*/
on<E extends LifecycleEvent>(event: E, listener: LifecycleListener<E>): () => void;
/**
* Emit lifecycle event to all listeners
* @internal - Called by StateContainer lifecycle methods
*/
emit(event: LifecycleEvent, ...args: any[]): void;
}
/**
* Global default registry instance
*/
export declare const globalRegistry: StateContainerRegistry;
/**
* Get the global plugin manager
*/
export declare function getPluginManager(): any;
/**
* Debug/Advanced Subpath Export
*
* Advanced registry introspection and debugging utilities.
* Import from '@blac/core/debug'
*
* These utilities are intended for debugging, testing, and advanced use cases.
* Most applications don't need these - use the main '@blac/core' exports instead.
*
* @example
* ```typescript
* import { getStats, globalRegistry, hasInstance } from '@blac/core/debug';
*
* // Get registry statistics
* const stats = getStats();
* console.log(`Total instances: ${stats.totalInstances}`);
*
* // Check if an instance exists
* if (hasInstance(UserBloc)) {
* console.log('UserBloc is registered');
* }
*
* // Iterate over all instances of a type
* forEach(UserBloc, (instance) => {
* console.log(instance.state);
* });
* ```
*
* @packageDocumentation
*/
export { hasInstance, getRefCount, getAll, forEach } from './registry/queries';
export { register } from './registry/management';
export { getRegistry, setRegistry, getStats } from './registry/config';
export { globalRegistry } from './core/StateContainerRegistry';
export type { LifecycleEvent, LifecycleListener, InstanceEntry, } from './core/StateContainerRegistry';
/**
* Configuration options for the @blac decorator.
* Only one option can be specified at a time (union type).
*/
export type BlacOptions =
/** Mark bloc as isolated (each component gets its own instance) */
{
isolated: true;
}
/** Mark bloc to never be auto-disposed when ref count reaches 0 */
| {
keepAlive: true;
}
/** Exclude bloc from DevTools tracking (prevents infinite loops) */
| {
excludeFromDevTools: true;
};
/**
* Decorator to configure StateContainer classes.
*
* @example Decorator syntax (requires experimentalDecorators or TC39 decorators)
* ```ts
* @blac({ isolated: true })
* class FormBloc extends Cubit<FormState> {}
*
* @blac({ keepAlive: true })
* class AuthBloc extends Cubit<AuthState> {}
*
* @blac({ excludeFromDevTools: true })
* class InternalBloc extends Cubit<InternalState> {}
* ```
*
* @example Function syntax (no decorator support needed)
* ```ts
* const FormBloc = blac({ isolated: true })(
* class extends Cubit<FormState> {}
* );
* ```
*/
export declare function blac(options: BlacOptions): <T extends new (...args: any[]) => any>(target: T, _context?: ClassDecoratorContext) => T;
export { blac, type BlacOptions } from './blac';
import type { StateContainer } from '../core/StateContainer';
/**
* Metadata information about a state container instance for debugging and inspection
*/
export interface InstanceMetadata {
/** Unique instance identifier */
id: string;
/** Name of the state container class */
className: string;
/** Whether the instance has been disposed */
isDisposed: boolean;
/** Display name for the instance */
name: string;
/** When state last changed (milliseconds) */
lastStateChangeTimestamp: number;
/** Current state value */
state: any;
/** Timestamp when instance was created (milliseconds) */
createdAt: number;
/** Whether this is an isolated (component-scoped) instance */
isIsolated: boolean;
/** Stack trace from when instance was created (for debugging) */
callstack?: string;
/** Previous state value */
previousState?: any;
/** Current state value */
currentState?: any;
}
/**
* Safe context API provided to plugins for accessing registry data
*/
export interface PluginContext {
/**
* Get metadata for a specific instance
*/
getInstanceMetadata(instance: StateContainer<any>): InstanceMetadata;
/**
* Get current state from a container
*/
getState<S extends object = any>(instance: StateContainer<S>): S;
/**
* Get all instances of a specific type
*/
queryInstances<T extends StateContainer<any>>(typeClass: new (...args: any[]) => T): T[];
/**
* Get all registered state container types
*/
getAllTypes(): Array<new (...args: any[]) => StateContainer<any>>;
/**
* Get registry statistics
*/
getStats(): {
registeredTypes: number;
totalInstances: number;
typeBreakdown: Record<string, number>;
};
}
/**
* Interface for plugins that extend BlaC functionality
*/
export interface BlacPlugin {
/** Unique plugin identifier */
readonly name: string;
/** Plugin version identifier */
readonly version: string;
/**
* Called when the plugin is installed (optional)
*/
onInstall?(context: PluginContext): void;
/**
* Called when the plugin is uninstalled
*/
onUninstall?(): void;
/**
* Called when a state container instance is created
*/
onInstanceCreated?(instance: StateContainer<any>, context: PluginContext): void;
/**
* Called when state changes in a container instance
*/
onStateChanged?<S extends object = any>(instance: StateContainer<S>, previousState: S, currentState: S, callstack: string | undefined, context: PluginContext): void;
/**
* Called when a state container instance is disposed
*/
onInstanceDisposed?(instance: StateContainer<any>, context: PluginContext): void;
}
/**
* Plugin interface variant that requires mandatory onInstall hook
*/
export interface BlacPluginWithInit extends BlacPlugin {
/**
* Required initialization hook called when plugin is installed
*/
onInstall(context: PluginContext): void;
}
/**
* Configuration options for plugin installation
*/
export interface PluginConfig {
/** Enable or disable the plugin */
enabled?: boolean;
/** Environments where plugin runs */
environment?: 'development' | 'production' | 'test' | 'all';
}
/**
* Type guard to check if a plugin has a required onInstall hook
* @param plugin - The plugin to check
* @returns true if the plugin implements BlacPluginWithInit
*/
export declare function hasInitHook(plugin: BlacPlugin): plugin is BlacPluginWithInit;
import type { StateContainerRegistry } from '../core/StateContainerRegistry';
import type { BlacPlugin, PluginConfig } from './BlacPlugin';
/**
* Manages plugin lifecycle for the BlaC state management system.
* Plugins receive notifications about state container lifecycle events.
*
* @example
* ```ts
* const manager = createPluginManager(registry);
* manager.install(myPlugin, { environment: 'development' });
* ```
*/
export declare class PluginManager {
private plugins;
private registry;
/**
* Create a new PluginManager
* @param registry - The StateContainerRegistry to monitor for lifecycle events
*/
constructor(registry: StateContainerRegistry);
/**
* Install a plugin with optional configuration
* @param plugin - The plugin to install
* @param config - Optional plugin configuration
* @throws Error if plugin is already installed
*/
install(plugin: BlacPlugin, config?: PluginConfig): void;
/**
* Uninstall a plugin by name
* @param pluginName - The name of the plugin to uninstall
* @throws Error if plugin is not installed
*/
uninstall(pluginName: string): void;
/**
* Get an installed plugin by name
* @param pluginName - The name of the plugin to retrieve
* @returns The plugin instance or undefined if not found
*/
getPlugin(pluginName: string): BlacPlugin | undefined;
/**
* Get all installed plugins
* @returns Array of all installed plugins
*/
getAllPlugins(): BlacPlugin[];
/**
* Check if a plugin is installed
* @param pluginName - The name of the plugin to check
* @returns true if the plugin is installed
*/
hasPlugin(pluginName: string): boolean;
/**
* Uninstall all plugins
*/
clear(): void;
/**
* Setup lifecycle hooks to notify plugins
*/
private setupLifecycleHooks;
/**
* Notify all plugins of a lifecycle event
*/
private notifyPlugins;
/**
* Create plugin context with safe API access
*/
private createPluginContext;
/**
* Check if plugin should be enabled based on environment
*/
private shouldEnablePlugin;
/**
* Get current environment
*/
private getCurrentEnvironment;
}
/**
* Create a plugin manager instance
* @param registry - The StateContainerRegistry to monitor for lifecycle events
* @returns A new PluginManager instance
*/
export declare function createPluginManager(registry: StateContainerRegistry): PluginManager;
/**
* Plugins Subpath Export
*
* Plugin system utilities for extending BlaC functionality.
* Import from '@blac/core/plugins'
*
* @example
* ```typescript
* import { PluginManager, getPluginManager, type BlacPlugin } from '@blac/core/plugins';
*
* const myPlugin: BlacPlugin = {
* name: 'my-plugin',
* onInstanceCreated(context) {
* console.log('Instance created:', context.instance);
* },
* };
*
* getPluginManager().register(myPlugin);
* ```
*
* @packageDocumentation
*/
export { PluginManager } from './plugin/PluginManager';
export type { BlacPlugin, BlacPluginWithInit, PluginContext, PluginConfig, InstanceMetadata, } from './plugin/BlacPlugin';
export { getPluginManager } from './core/StateContainerRegistry';
import type { StateContainerConstructor } from '../types/utilities';
export declare function acquire<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): InstanceType<T>;
import type { StateContainerConstructor } from '../types/utilities';
export declare function borrow<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): InstanceType<T>;
export declare function borrowSafe<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): {
error: Error;
instance: null;
} | {
error: null;
instance: InstanceType<T>;
};
import { StateContainerRegistry } from '../core/StateContainerRegistry';
export declare function getRegistry(): StateContainerRegistry;
export declare function setRegistry(registry: StateContainerRegistry): void;
export declare function getStats(): {
registeredTypes: number;
totalInstances: number;
typeBreakdown: Record<string, number>;
};
import type { StateContainerConstructor } from '../types/utilities';
export declare function ensure<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): InstanceType<T>;
export { acquire } from './acquire';
export { borrow, borrowSafe } from './borrow';
export { ensure } from './ensure';
export { release } from './release';
export { hasInstance, getRefCount, getAll, forEach } from './queries';
export { clear, clearAll, register } from './management';
export { getRegistry, setRegistry, getStats } from './config';
import type { StateContainerConstructor } from '../types/utilities';
export declare function clear<T extends StateContainerConstructor>(BlocClass: T): void;
export declare function clearAll(): void;
export declare function register<T extends StateContainerConstructor>(BlocClass: T, isolated?: boolean): void;
import type { StateContainerConstructor, InstanceReadonlyState } from '../types/utilities';
export declare function hasInstance<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): boolean;
export declare function getRefCount<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): number;
export declare function getAll<T extends StateContainerConstructor>(BlocClass: T): InstanceReadonlyState<T>[];
export declare function forEach<T extends StateContainerConstructor>(BlocClass: T, callback: (instance: InstanceReadonlyState<T>) => void): void;
import type { StateContainerConstructor } from '../types/utilities';
export declare function release<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string, forceDispose?: boolean): void;
declare const brand: unique symbol;
/**
* Utility type for creating branded/nominal types.
* Prevents accidental type confusion between similar primitive types.
* @template T - The base type
* @template B - The brand identifier
*/
export type Brand<T, B> = T & {
[brand]: B;
};
/**
* Branded string type for type-safe IDs.
* @template B - The brand identifier
*/
export type BrandedId<B> = Brand<string, B>;
/**
* Branded string type for state container instance IDs
*/
export type InstanceId = Brand<string, 'InstanceId'>;
/**
* Create a branded InstanceId from a string
* @param id - The string ID to brand
* @returns Branded InstanceId
*/
export declare function instanceId(id: string): InstanceId;
export {};
import type { StateContainer } from '../core/StateContainer';
/**
* Extract the state type from a StateContainer
* @template T - The StateContainer type
*/
export type ExtractState<T> = T extends StateContainerConstructor<infer S> ? Readonly<S> : never;
export type ExtractStateMutable<T> = T extends StateContainerConstructor<infer S> ? S : never;
/**
* Constructor type for StateContainer classes
* @template S - State type managed by the container
*/
export type StateContainerConstructor<S extends object = any> = new (...args: any[]) => StateContainer<S>;
export type InstanceReadonlyState<T extends StateContainerConstructor = any> = Omit<InstanceType<T>, 'state'> & {
state: ExtractState<T>;
};
export type InstanceState<T extends StateContainerConstructor = any> = Omit<InstanceType<T>, 'state'> & {
state: ExtractStateMutable<T>;
};
export type StateContainerInstance<S extends object = any> = Omit<StateContainer<S>, 'state'> & {
state: Readonly<S>;
};
/**
* Extract constructor argument types from a class
* @template T - The class type
*/
export type ExtractConstructorArgs<T> = T extends new (...args: infer P) => any ? P : never[];
/**
* Extract instance type from an abstract class constructor
* @template T - The abstract class constructor type
*/
export type BlocInstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
/**
* Constructor type for StateContainer classes with static registry methods.
* Used for type-safe hook parameters.
* @template TBloc - The StateContainer instance type
*/
export type BlocConstructor<S extends object = any, T extends new (...args: any[]) => StateContainer<S> = new (...args: any[]) => StateContainer<S>> = (new (...args: any[]) => InstanceType<T>) & {
acquire(instanceKey?: string, ...args: any[]): InstanceType<T>;
borrow(instanceKey?: string, ...args: any[]): InstanceType<T> | null;
borrowSafe(instanceKey?: string, ...args: any[]): {
error: Error;
instance: null;
} | {
error: null;
instance: InstanceType<T>;
};
ensure(instanceKey?: string): InstanceType<T>;
release(instanceKey?: string): void;
isolated?: boolean;
keepAlive?: boolean;
};
/**
* Centralized ID Generation
*
* Provides consistent, collision-resistant ID generation for all BlaC subsystems.
* Uses timestamp + counter + random suffix for uniqueness.
*/
/**
* Creates an ID generator with isolated counter state
*
* @param prefix - Prefix for generated IDs
* @returns Object with next(), nextSimple(), and reset() methods
*
* @example
* ```ts
* const generator = createIdGenerator('sub');
* const id1 = generator.next(); // "sub:1698765432100_1_a3k9d7f2q"
* const id2 = generator.next(); // "sub:1698765432101_2_b4n8e9g3r"
* ```
*/
export declare function createIdGenerator(prefix: string): {
next: () => string;
nextSimple: () => string;
reset: () => void;
};
/**
* Generate ID with timestamp, counter, and random suffix (tree-shakeable)
*
* Format: `${prefix}:${timestamp}_${counter}_${random}`
*
* @param prefix - Prefix for the ID (e.g., 'sub', 'consumer', 'stage')
* @returns Branded ID string
*
* @example
* const id = generateId('sub');
* // Returns: "sub:1698765432100_1_a3k9d7f2q"
*/
export declare function generateId(prefix: string): string;
/**
* Generate simple ID with timestamp and random (no counter tracking)
*
* Format: `${prefix}:${timestamp}_${random}`
*
* @param prefix - Prefix for the ID
* @returns Branded ID string
*
* @example
* ```ts
* const id = generateSimpleId('CounterBloc');
* // Returns: "CounterBloc:1698765432100_a3k9d7f2q"
* ```
*/
export declare function generateSimpleId(prefix: string, affix?: string): string;
/**
* Reset all counters for testing purposes
* @internal
*/
export declare function __resetIdCounters(): void;
/**
* Generate a unique isolated instance key
* Uses base36 encoding for compact, URL-safe identifiers
*
* Format: "isolated-{9-char-random-string}"
* Example: "isolated-k7x2m9p4q"
*
* @returns A unique isolated instance key
*/
export declare function generateIsolatedKey(): string;
/**
* Check if a key is an isolated instance key
* @param key - The instance key to check
* @returns true if the key is an isolated instance key
*/
export declare function isIsolatedKey(key: string): boolean;
/**
* Utility functions for accessing static properties on StateContainer classes
*/
import { StateContainerConstructor } from '../types/utilities';
/**
* Get a static property from a class constructor
* Type-safe helper that avoids (Type as any) casts
*
* @param Type - The class constructor
* @param propName - The property name to access
* @param defaultValue - Optional default value if property is undefined
* @returns The property value or default
*/
export declare function getStaticProp<V, T extends StateContainerConstructor = StateContainerConstructor>(Type: T, propName: string, defaultValue?: V): V | undefined;
/**
* Check if a class is marked as isolated.
* Isolated classes create separate instances per component.
* @param Type - The class constructor to check
* @returns true if the class has `static isolated = true`
*/
export declare function isIsolatedClass<T extends StateContainerConstructor>(Type: T): boolean;
/**
* Check if a class is marked as keepAlive.
* KeepAlive classes are never auto-disposed when ref count reaches 0.
* @param Type - The class constructor to check
* @returns true if the class has `static keepAlive = true`
*/
export declare function isKeepAliveClass<T extends StateContainerConstructor>(Type: T): boolean;
/**
* Check if a class should be excluded from DevTools.
* Used to prevent infinite loops when DevTools tracks itself.
* @param Type - The class constructor to check
* @returns true if the class has `static __excludeFromDevTools = true`
*/
export declare function isExcludedFromDevTools<T extends StateContainerConstructor>(Type: T): boolean;
/**
* Watch Subpath Export
*
* Reactive subscription utilities for watching bloc state changes.
* Import from '@blac/core/watch'
*
* @example
* ```typescript
* import { watch, instance } from '@blac/core/watch';
*
* // Watch a bloc with automatic dependency tracking
* const unwatch = watch(UserBloc, (userBloc) => {
* console.log(userBloc.state.name);
* console.log(userBloc.fullName); // getter also tracked
* });
*
* // Watch a specific instance
* const unwatch = watch(instance(UserBloc, 'user-123'), (userBloc) => {
* console.log(userBloc.state.name);
* });
* ```
*
* @packageDocumentation
*/
export { watch, instance, type WatchFn, type BlocRef } from './watch';
export { tracked, createTrackedContext, TrackedContext, type TrackedResult, type TrackedOptions, } from './tracking/tracked';
export { watch, instance } from './watch';
export type { WatchFn, BlocRef } from './watch';
import type { StateContainerConstructor } from '../types/utilities';
declare const STOP: unique symbol;
declare const BLOC_REF_MARKER: unique symbol;
/**
* Reference to a specific bloc instance by class and instance ID.
*/
export interface BlocRef<T extends StateContainerConstructor> {
[BLOC_REF_MARKER]: true;
blocClass: T;
instanceId: string;
}
/**
* Create a reference to a specific bloc instance.
*
* @example
* ```ts
* watch(instance(UserBloc, 'user-123'), (userBloc) => {
* console.log(userBloc.state.name);
* });
* ```
*/
export declare function instance<T extends StateContainerConstructor>(BlocClass: T, instanceId: string): BlocRef<T>;
type BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;
type ExtractInstance<T> = T extends BlocRef<infer C> ? InstanceType<C> : T extends StateContainerConstructor ? InstanceType<T> : never;
type ExtractInstances<T extends readonly BlocInput[]> = {
[K in keyof T]: ExtractInstance<T[K]>;
};
type StopSymbol = typeof STOP;
/**
* Watch function signature for single bloc.
*/
export interface WatchSingleFn {
<T extends StateContainerConstructor>(bloc: T | BlocRef<T>, callback: (bloc: InstanceType<T>) => void | StopSymbol): () => void;
STOP: StopSymbol;
}
/**
* Watch function signature for multiple blocs.
*/
export interface WatchMultipleFn {
<T extends readonly BlocInput[]>(blocs: T, callback: (blocs: ExtractInstances<T>) => void | StopSymbol): () => void;
STOP: StopSymbol;
}
/**
* Combined watch function type.
*/
export interface WatchFn extends WatchSingleFn {
<T extends readonly BlocInput[]>(blocs: T, callback: (blocs: ExtractInstances<T>) => void | StopSymbol): () => void;
}
export declare const watch: WatchFn;
export {};
+1501
-48

@@ -1,6 +0,1 @@

const require_StateContainerRegistry = require('./StateContainerRegistry.cjs');
const require_management = require('./management.cjs');
const require_watch = require('./watch.cjs');
const require_resolve_dependencies = require('./resolve-dependencies.cjs');
require('./tracking.cjs');

@@ -40,2 +35,569 @@ //#region src/utils/idGenerator.ts

//#endregion
//#region src/constants.ts
/**
* Default configuration constants for BlaC
*
* Centralized location for all magic numbers and default values.
*/
/**
* Default configuration constants for BlaC
*/
const BLAC_DEFAULTS = {
DEFAULT_INSTANCE_KEY: "default",
MAX_GETTER_DEPTH: 10,
CLEANUP_INTERVAL_MS: 3e4,
WEAKREF_CLEANUP_INTERVAL_MS: 1e4,
MAX_SUBSCRIPTIONS: 1e3,
MAX_SUBSCRIPTIONS_HIGH_PERF: 1e4,
PIPELINE_TIMEOUT_MS: 5e3,
CLEANUP_INTERVAL_HIGH_PERF_MS: 5e3,
MAX_PIPELINE_STAGES: 30
};
/**
* Static property names for StateContainer classes
* Used for feature flags and configuration on bloc classes
*/
const BLAC_STATIC_PROPS = {
ISOLATED: "isolated",
KEEP_ALIVE: "keepAlive",
EXCLUDE_FROM_DEVTOOLS: "__excludeFromDevTools"
};
/**
* Standard error message prefix
*/
const BLAC_ERROR_PREFIX = "[BlaC]";
//#endregion
//#region src/plugin/PluginManager.ts
/**
* Manages plugin lifecycle for the BlaC state management system.
* Plugins receive notifications about state container lifecycle events.
*
* @example
* ```ts
* const manager = createPluginManager(registry);
* manager.install(myPlugin, { environment: 'development' });
* ```
*/
var PluginManager = class {
/**
* Create a new PluginManager
* @param registry - The StateContainerRegistry to monitor for lifecycle events
*/
constructor(registry) {
this.plugins = /* @__PURE__ */ new Map();
this.registry = registry;
this.setupLifecycleHooks();
}
/**
* Install a plugin with optional configuration
* @param plugin - The plugin to install
* @param config - Optional plugin configuration
* @throws Error if plugin is already installed
*/
install(plugin, config = {}) {
const effectiveConfig = {
enabled: true,
environment: "all",
...config
};
if (!this.shouldEnablePlugin(effectiveConfig)) {
console.log(`[BlaC] Plugin "${plugin.name}" skipped (environment mismatch)`);
return;
}
if (this.plugins.has(plugin.name)) throw new Error(`Plugin "${plugin.name}" is already installed`);
const context = this.createPluginContext();
this.plugins.set(plugin.name, {
plugin,
config: effectiveConfig,
context
});
if (plugin.onInstall) try {
plugin.onInstall(context);
} catch (error) {
console.error(`[BlaC] Error installing plugin "${plugin.name}":`, error);
this.plugins.delete(plugin.name);
throw error;
}
console.log(`[BlaC] Plugin "${plugin.name}" v${plugin.version} installed`);
}
/**
* Uninstall a plugin by name
* @param pluginName - The name of the plugin to uninstall
* @throws Error if plugin is not installed
*/
uninstall(pluginName) {
const installed = this.plugins.get(pluginName);
if (!installed) throw new Error(`Plugin "${pluginName}" is not installed`);
if (installed.plugin.onUninstall) try {
installed.plugin.onUninstall();
} catch (error) {
console.error(`[BlaC] Error uninstalling plugin "${pluginName}":`, error);
}
this.plugins.delete(pluginName);
console.log(`[BlaC] Plugin "${pluginName}" uninstalled`);
}
/**
* Get an installed plugin by name
* @param pluginName - The name of the plugin to retrieve
* @returns The plugin instance or undefined if not found
*/
getPlugin(pluginName) {
return this.plugins.get(pluginName)?.plugin;
}
/**
* Get all installed plugins
* @returns Array of all installed plugins
*/
getAllPlugins() {
return Array.from(this.plugins.values()).map((p) => p.plugin);
}
/**
* Check if a plugin is installed
* @param pluginName - The name of the plugin to check
* @returns true if the plugin is installed
*/
hasPlugin(pluginName) {
return this.plugins.has(pluginName);
}
/**
* Uninstall all plugins
*/
clear() {
for (const name of this.plugins.keys()) this.uninstall(name);
}
/**
* Setup lifecycle hooks to notify plugins
*/
setupLifecycleHooks() {
this.registry.on("created", (instance) => {
this.notifyPlugins("onInstanceCreated", instance);
});
this.registry.on("stateChanged", (instance, previousState, currentState, callstack) => {
this.notifyPlugins("onStateChanged", instance, previousState, currentState, callstack);
});
this.registry.on("disposed", (instance) => {
this.notifyPlugins("onInstanceDisposed", instance);
});
}
/**
* Notify all plugins of a lifecycle event
*/
notifyPlugins(hookName, ...args) {
for (const { plugin, config, context } of this.plugins.values()) {
if (!config.enabled) continue;
const hook = plugin[hookName];
if (typeof hook === "function") try {
hook.apply(plugin, [...args, context]);
} catch (error) {
console.error(`[BlaC] Error in plugin "${plugin.name}" ${hookName}:`, error);
}
}
}
/**
* Create plugin context with safe API access
*/
createPluginContext() {
return {
getInstanceMetadata: (instance) => {
return {
id: instance.instanceId,
className: instance.constructor.name,
isDisposed: instance.isDisposed,
name: instance.name,
lastStateChangeTimestamp: instance.lastUpdateTimestamp,
createdAt: instance.createdAt,
state: instance.state,
isIsolated: instance.instanceId.startsWith("isolated-")
};
},
getState: (instance) => {
return instance.state;
},
queryInstances: (typeClass) => {
return this.registry.getAll(typeClass);
},
getAllTypes: () => {
return this.registry.getTypes();
},
getStats: () => {
return this.registry.getStats();
}
};
}
/**
* Check if plugin should be enabled based on environment
*/
shouldEnablePlugin(config) {
if (!config.enabled) return false;
if (config.environment === "all") return true;
return this.getCurrentEnvironment() === config.environment;
}
/**
* Get current environment
*/
getCurrentEnvironment() {
if (typeof process !== "undefined") {
if (process.env.NODE_ENV === "test") return "test";
if (process.env.NODE_ENV === "production") return "production";
return "development";
}
return "development";
}
};
/**
* Create a plugin manager instance
* @param registry - The StateContainerRegistry to monitor for lifecycle events
* @returns A new PluginManager instance
*/
function createPluginManager(registry) {
return new PluginManager(registry);
}
//#endregion
//#region src/utils/static-props.ts
/**
* Utility functions for accessing static properties on StateContainer classes
*/
/**
* Get a static property from a class constructor
* Type-safe helper that avoids (Type as any) casts
*
* @param Type - The class constructor
* @param propName - The property name to access
* @param defaultValue - Optional default value if property is undefined
* @returns The property value or default
*/
function getStaticProp(Type, propName, defaultValue) {
return Type[propName] ?? defaultValue;
}
/**
* Check if a class is marked as isolated.
* Isolated classes create separate instances per component.
* @param Type - The class constructor to check
* @returns true if the class has `static isolated = true`
*/
function isIsolatedClass(Type) {
return getStaticProp(Type, BLAC_STATIC_PROPS.ISOLATED) === true;
}
/**
* Check if a class is marked as keepAlive.
* KeepAlive classes are never auto-disposed when ref count reaches 0.
* @param Type - The class constructor to check
* @returns true if the class has `static keepAlive = true`
*/
function isKeepAliveClass(Type) {
return getStaticProp(Type, BLAC_STATIC_PROPS.KEEP_ALIVE) === true;
}
//#endregion
//#region src/core/StateContainerRegistry.ts
/**
* Central registry for managing StateContainer instances.
* Handles instance lifecycle, ref counting, and lifecycle event emission.
*
* @example
* ```ts
* const registry = new StateContainerRegistry();
* const instance = registry.acquire(MyBloc); // ownership, must release
* const other = registry.ensure(OtherBloc); // no ownership, bloc-to-bloc
* registry.on('stateChanged', (container, prev, next) => {
* console.log('State changed:', prev, '->', next);
* });
* ```
*/
var StateContainerRegistry = class {
constructor() {
this.instancesByConstructor = /* @__PURE__ */ new WeakMap();
this.types = /* @__PURE__ */ new Set();
this.typeConfigs = /* @__PURE__ */ new Map();
this.listeners = /* @__PURE__ */ new Map();
}
/**
* Register a type for lifecycle event tracking
* @param constructor - The StateContainer class constructor
*/
registerType(constructor) {
this.types.add(constructor);
}
/**
* Register a StateContainer class with configuration
* @param constructor - The StateContainer class constructor
* @param isolated - Whether instances should be isolated (component-scoped)
* @throws Error if type is already registered
*/
register(constructor, isolated = false) {
const className = constructor.name;
if (!isolated && isIsolatedClass(constructor)) isolated = true;
if (this.typeConfigs.has(className)) throw new Error(`${BLAC_ERROR_PREFIX} Type "${className}" is already registered`);
this.typeConfigs.set(className, { isolated });
this.registerType(constructor);
}
ensureInstancesMap(Type) {
let instances = this.instancesByConstructor.get(Type);
if (!instances) {
instances = /* @__PURE__ */ new Map();
this.instancesByConstructor.set(Type, instances);
}
return instances;
}
/**
* Get the instances Map for a specific class (public API for stats/debugging)
*/
getInstancesMap(Type) {
return this.instancesByConstructor.get(Type) || /* @__PURE__ */ new Map();
}
/**
* Acquire an instance with ref counting (ownership semantics).
* Creates a new instance if one doesn't exist, or returns existing and increments ref count.
* You must call `release()` when done to decrement the ref count.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param options - Acquisition options
* @param options.canCreate - Whether to create new instance if not found (default: true)
* @param options.countRef - Whether to increment ref count (default: true)
* @returns The state container instance
*/
acquire(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, options = {}) {
const { canCreate = true, countRef = true } = options;
const registryConfig = this.typeConfigs.get(Type.name);
const isolated = isIsolatedClass(Type) || registryConfig?.isolated === true;
const config = { instanceId: instanceKey };
if (isolated && !canCreate) throw new Error(`${BLAC_ERROR_PREFIX} Cannot get isolated instance "${instanceKey}" of ${Type.name} when creation is disabled.`);
if (isolated) {
const instance = new Type();
instance.initConfig(config);
this.registerType(Type);
return instance;
}
const instances = this.ensureInstancesMap(Type);
let entry = instances.get(instanceKey);
if (entry?.instance.isDisposed) {
instances.delete(instanceKey);
entry = void 0;
}
if (entry && countRef) entry.refCount++;
if (entry) return entry.instance;
if (!canCreate) throw new Error(`${BLAC_ERROR_PREFIX} ${Type.name} instance "${instanceKey}" not found and creation is disabled.`);
const instance = new Type();
instance.initConfig(config);
instances.set(instanceKey, {
instance,
refCount: 1
});
this.registerType(Type);
return instance;
}
/**
* Borrow an existing instance without incrementing ref count (borrowing semantics).
* Tracks cross-bloc dependency for reactive updates.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
* @throws Error if instance doesn't exist
*/
borrow(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
return this.acquire(Type, instanceKey, {
canCreate: false,
countRef: false
});
}
/**
* Safely borrow an existing instance (borrowing semantics with error handling).
* Returns discriminated union for type-safe conditional access.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Discriminated union with either the instance or an error
*/
borrowSafe(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
try {
return {
error: null,
instance: this.borrow(Type, instanceKey)
};
} catch (error) {
return {
error,
instance: null
};
}
}
/**
* Ensure an instance exists without taking ownership (for bloc-to-bloc communication).
* Gets existing instance OR creates it if it doesn't exist, without incrementing ref count.
* Tracks cross-bloc dependency for reactive updates.
*
* Use this in bloc-to-bloc communication when you need to ensure an instance exists
* but don't want to claim ownership (no ref count increment).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
*/
ensure(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
return this.acquire(Type, instanceKey, {
canCreate: true,
countRef: false
});
}
/**
* Release a reference to an instance.
* Decrements ref count and disposes when it reaches 0 (unless keepAlive).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param forceDispose - Force immediate disposal regardless of ref count
*/
release(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, forceDispose = false) {
const instances = this.ensureInstancesMap(Type);
const entry = instances.get(instanceKey);
if (!entry) return;
if (forceDispose) {
if (!entry.instance.isDisposed) entry.instance.dispose();
instances.delete(instanceKey);
return;
}
entry.refCount--;
const keepAlive = isKeepAliveClass(Type);
if (entry.refCount <= 0 && !keepAlive) {
if (!entry.instance.isDisposed) entry.instance.dispose();
instances.delete(instanceKey);
}
}
/**
* Get all instances of a specific type.
* @param Type - The StateContainer class constructor
* @returns Array of all instances
*/
getAll(Type) {
const instances = this.ensureInstancesMap(Type);
const result = [];
for (const entry of instances.values()) result.push(entry.instance);
return result;
}
/**
* Safely iterate over all instances of a type.
* Skips disposed instances and catches callback errors.
* @param Type - The StateContainer class constructor
* @param callback - Function to call for each instance
*/
forEach(Type, callback) {
const instances = this.ensureInstancesMap(Type);
for (const entry of instances.values()) {
const instance = entry.instance;
if (!instance.isDisposed) try {
callback(instance);
} catch (error) {
console.error(`${BLAC_ERROR_PREFIX} forEach callback error for ${Type.name}:`, error);
}
}
}
/**
* Clear all instances of a specific type (disposes them).
* @param Type - The StateContainer class constructor
*/
clear(Type) {
const instances = this.ensureInstancesMap(Type);
for (const entry of instances.values()) if (!entry.instance.isDisposed) entry.instance.dispose();
instances.clear();
}
/**
* Get reference count for an instance.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Current ref count (0 if instance doesn't exist)
*/
getRefCount(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
return this.ensureInstancesMap(Type).get(instanceKey)?.refCount ?? 0;
}
/**
* Check if an instance exists.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns true if instance exists
*/
hasInstance(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
return this.ensureInstancesMap(Type).has(instanceKey);
}
/**
* Clear all instances from all types (for testing)
*
* Iterates all registered types and clears their instances.
* Also clears type tracking to reset the registry state.
*/
clearAll() {
for (const Type of this.types) this.clear(Type);
this.types.clear();
this.typeConfigs.clear();
}
/**
* Get registry statistics for debugging.
* @returns Object with registeredTypes, totalInstances, and typeBreakdown
*/
getStats() {
const typeBreakdown = {};
let totalInstances = 0;
for (const Type of this.types) {
const typeName = Type.name;
const count = this.getInstancesMap(Type).size;
typeBreakdown[typeName] = count;
totalInstances += count;
}
return {
registeredTypes: this.types.size,
totalInstances,
typeBreakdown
};
}
/**
* Get all registered types (for plugin system).
* @returns Array of all registered StateContainer class constructors
*/
getTypes() {
return Array.from(this.types);
}
/**
* Subscribe to lifecycle events
* @param event - The lifecycle event to listen for
* @param listener - The listener function to call when the event occurs
* @returns Unsubscribe function
*/
on(event, listener) {
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
const instance = this.listeners.get(event);
if (!instance) throw new Error(`${BLAC_ERROR_PREFIX} Failed to register listener for event '${event}'`);
instance.add(listener);
return () => {
this.listeners.get(event)?.delete(listener);
};
}
/**
* Emit lifecycle event to all listeners
* @internal - Called by StateContainer lifecycle methods
*/
emit(event, ...args) {
const listeners = this.listeners.get(event);
if (!listeners || listeners.size === 0) return;
for (const listener of listeners) try {
listener(...args);
} catch (error) {
console.error(`${BLAC_ERROR_PREFIX} Listener error for '${event}':`, error);
}
}
};
/**
* Global default registry instance
*/
const globalRegistry = new StateContainerRegistry();
/**
* Global plugin manager (initialized lazily)
*/
let _globalPluginManager = null;
/**
* Get the global plugin manager
*/
function getPluginManager() {
if (!_globalPluginManager) _globalPluginManager = createPluginManager(globalRegistry);
return _globalPluginManager;
}
//#endregion
//#region src/core/StateContainer.ts

@@ -74,4 +636,4 @@ const EMPTY_DEPS = /* @__PURE__ */ new Map();

if (!this._dependencies) this._dependencies = /* @__PURE__ */ new Map();
this._dependencies.set(Type, instanceKey ?? require_StateContainerRegistry.BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY);
return () => require_StateContainerRegistry.globalRegistry.ensure(Type, instanceKey);
this._dependencies.set(Type, instanceKey ?? BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY);
return () => globalRegistry.ensure(Type, instanceKey);
}

@@ -112,3 +674,3 @@ constructor(initialState) {

this.instanceId = generateSimpleId(this.constructor.name, this.config.instanceId);
require_StateContainerRegistry.globalRegistry.emit("created", this);
globalRegistry.emit("created", this);
}

@@ -144,3 +706,3 @@ /** Current state value */

this.systemEventHandlers.clear();
require_StateContainerRegistry.globalRegistry.emit("disposed", this);
globalRegistry.emit("disposed", this);
if (this.debug) console.log(`[${this.name}] Disposed successfully`);

@@ -168,3 +730,3 @@ }

const stackTrace = this.captureStackTrace();
require_StateContainerRegistry.globalRegistry.emit("stateChanged", this, previousState, newState, stackTrace);
globalRegistry.emit("stateChanged", this, previousState, newState, stackTrace);
this.lastUpdateTimestamp = Date.now();

@@ -243,4 +805,10 @@ }

if (typeof this.state !== "object" || this.state === null) throw new Error("patch() is only available for object state types");
this.update((current) => ({
...current,
const current = this.state;
let hasChanges = false;
for (const key in partial) if (!Object.is(current[key], partial[key])) {
hasChanges = true;
break;
}
if (hasChanges) this.update((c) => ({
...c,
...partial

@@ -269,3 +837,3 @@ }));

function acquire(BlocClass, instanceKey) {
return require_StateContainerRegistry.globalRegistry.acquire(BlocClass, instanceKey, {
return globalRegistry.acquire(BlocClass, instanceKey, {
canCreate: true,

@@ -279,15 +847,62 @@ countRef: true

function borrow(BlocClass, instanceKey) {
return require_StateContainerRegistry.globalRegistry.borrow(BlocClass, instanceKey);
return globalRegistry.borrow(BlocClass, instanceKey);
}
function borrowSafe(BlocClass, instanceKey) {
return require_StateContainerRegistry.globalRegistry.borrowSafe(BlocClass, instanceKey);
return globalRegistry.borrowSafe(BlocClass, instanceKey);
}
//#endregion
//#region src/registry/ensure.ts
function ensure(BlocClass, instanceKey) {
return globalRegistry.ensure(BlocClass, instanceKey);
}
//#endregion
//#region src/registry/release.ts
function release(BlocClass, instanceKey, forceDispose = false) {
require_StateContainerRegistry.globalRegistry.release(BlocClass, instanceKey, forceDispose);
globalRegistry.release(BlocClass, instanceKey, forceDispose);
}
//#endregion
//#region src/registry/queries.ts
function hasInstance(BlocClass, instanceKey) {
return globalRegistry.hasInstance(BlocClass, instanceKey);
}
function getRefCount(BlocClass, instanceKey) {
return globalRegistry.getRefCount(BlocClass, instanceKey);
}
function getAll(BlocClass) {
return globalRegistry.getAll(BlocClass);
}
function forEach(BlocClass, callback) {
globalRegistry.forEach(BlocClass, callback);
}
//#endregion
//#region src/registry/management.ts
function clear(BlocClass) {
globalRegistry.clear(BlocClass);
}
function clearAll() {
globalRegistry.clearAll();
}
function register(BlocClass, isolated = false) {
globalRegistry.register(BlocClass, isolated);
}
//#endregion
//#region src/registry/config.ts
let _registry = globalRegistry;
function getRegistry() {
return _registry;
}
function setRegistry(registry) {
_registry.clearAll();
_registry = registry;
}
function getStats() {
return _registry.getStats();
}
//#endregion
//#region src/decorators/blac.ts

@@ -318,5 +933,5 @@ /**

return function(target, _context) {
if ("isolated" in options && options.isolated) target[require_StateContainerRegistry.BLAC_STATIC_PROPS.ISOLATED] = true;
if ("keepAlive" in options && options.keepAlive) target[require_StateContainerRegistry.BLAC_STATIC_PROPS.KEEP_ALIVE] = true;
if ("excludeFromDevTools" in options && options.excludeFromDevTools) target[require_StateContainerRegistry.BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS] = true;
if ("isolated" in options && options.isolated) target[BLAC_STATIC_PROPS.ISOLATED] = true;
if ("keepAlive" in options && options.keepAlive) target[BLAC_STATIC_PROPS.KEEP_ALIVE] = true;
if ("excludeFromDevTools" in options && options.excludeFromDevTools) target[BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS] = true;
return target;

@@ -327,6 +942,837 @@ };

//#endregion
//#region src/tracking/path-utils.ts
/**
* Path utilities for dependency tracking
*
* Provides utilities for parsing property paths and extracting values
* from nested objects using path strings.
*
* @internal
*/
/**
* Parse a property path string into an array of segments
*
* @internal
*
* Handles both dot notation (a.b.c) and bracket notation (a[0].b)
*
* @example
* ```ts
* parsePath('user.name') // ['user', 'name']
* parsePath('items[0].name') // ['items', '0', 'name']
* parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']
* ```
*/
function parsePath(path) {
const segments = [];
let current = "";
let i = 0;
while (i < path.length) {
const char = path[i];
if (char === ".") {
if (current) segments.push(current);
current = "";
} else if (char === "[") {
if (current) segments.push(current);
current = "";
i++;
while (i < path.length && path[i] !== "]") current += path[i++];
if (current) segments.push(current);
current = "";
} else current += char;
i++;
}
if (current) segments.push(current);
return segments;
}
/**
* Get a value from an object using a path of segments
*
* @example
* ```ts
* const obj = { user: { name: 'Alice', age: 30 } }
* getValueAtPath(obj, ['user', 'name']) // 'Alice'
* getValueAtPath(obj, ['user', 'age']) // 30
* getValueAtPath(obj, ['user', 'missing']) // undefined
* ```
*
* @internal
*/
function getValueAtPath(obj, segments) {
if (obj == null) return void 0;
let current = obj;
for (let i = 0; i < segments.length; i++) {
current = current[segments[i]];
if (current == null) return void 0;
}
return current;
}
/**
* Shallow equality comparison for arrays
*
* Compares two arrays element-by-element using Object.is
*
* @example
* ```ts
* shallowEqual([1, 2, 3], [1, 2, 3]) // true
* shallowEqual([1, 2, 3], [1, 2, 4]) // false
* shallowEqual([1, 2], [1, 2, 3]) // false
* ```
*
* @internal
*/
function shallowEqual(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
for (let i = 0; i < arr1.length; i++) if (!Object.is(arr1[i], arr2[i])) return false;
return true;
}
//#endregion
//#region src/tracking/tracking-proxy.ts
/**
* Consolidated Tracking System
*
* This module provides all dependency and getter tracking functionality:
* - Proxy creation for automatic property access tracking
* - Dependency path tracking and change detection
* - Getter execution tracking for computed properties
* - Combined tracking proxy for watch/waitUntil use cases
*/
/**
* Check if a value can be proxied
* Returns true for plain objects and arrays only.
* @internal
*/
function isProxyable(value) {
if (typeof value !== "object" || value === null) return false;
const proto = Object.getPrototypeOf(value);
return proto === Object.prototype || proto === Array.prototype;
}
/**
* Create a new proxy tracker state
* @internal
*/
function createProxyState() {
return {
trackedPaths: /* @__PURE__ */ new Set(),
isTracking: false,
proxyCache: /* @__PURE__ */ new WeakMap(),
boundFunctionsCache: null,
lastProxiedState: null,
lastProxy: null,
maxDepth: 10
};
}
/**
* Start tracking property accesses
* @internal
*/
function startProxy(state) {
state.isTracking = true;
state.trackedPaths.clear();
}
/**
* Stop tracking and return the tracked paths
* @internal
*/
function stopProxy(state) {
state.isTracking = false;
return new Set(state.trackedPaths);
}
/**
* Create a proxy for an array with property access tracking
* @internal
*/
function createArrayProxy(state, target, path, depth = 0) {
const proxy = new Proxy(target, { get: (arr, prop) => {
if (typeof prop === "symbol") return Reflect.get(arr, prop);
const value = Reflect.get(arr, prop);
if (typeof value === "function") {
if (!state.boundFunctionsCache) state.boundFunctionsCache = /* @__PURE__ */ new WeakMap();
const cached = state.boundFunctionsCache.get(value);
if (cached) return cached;
const bound = value.bind(arr);
state.boundFunctionsCache.set(value, bound);
return bound;
}
if (prop === "length") {
if (state.isTracking) {
const fullPath = path ? `${path}.length` : "length";
state.trackedPaths.add(fullPath);
}
return value;
}
let fullPath;
if (typeof prop === "string") {
const index = Number(prop);
if (!isNaN(index) && index >= 0) fullPath = path ? `${path}[${index}]` : `[${index}]`;
else fullPath = path ? `${path}.${prop}` : prop;
} else return value;
if (isProxyable(value)) return createInternal(state, value, fullPath, depth + 1);
if (state.isTracking) state.trackedPaths.add(fullPath);
return value;
} });
state.proxyCache.set(target, proxy);
return proxy;
}
/**
* Create a proxy for an object with property access tracking
* @internal
*/
function createInternal(state, target, path = "", depth = 0) {
if (!state.isTracking || !isProxyable(target)) return target;
if (depth >= state.maxDepth) return target;
if (state.proxyCache.has(target)) return state.proxyCache.get(target);
if (Array.isArray(target)) return createArrayProxy(state, target, path, depth);
const proxy = new Proxy(target, {
get: (obj, prop) => {
if (typeof prop === "symbol") return Reflect.get(obj, prop);
const value = Reflect.get(obj, prop);
if (typeof value === "function") {
if (!state.boundFunctionsCache) state.boundFunctionsCache = /* @__PURE__ */ new WeakMap();
const cached = state.boundFunctionsCache.get(value);
if (cached) return cached;
const bound = value.bind(obj);
state.boundFunctionsCache.set(value, bound);
return bound;
}
const fullPath = path ? `${path}.${String(prop)}` : String(prop);
if (typeof prop === "string" && state.isTracking) {
if (!prop.startsWith("_") && !prop.startsWith("$$")) state.trackedPaths.add(fullPath);
}
if (isProxyable(value)) return createInternal(state, value, fullPath, depth + 1);
return value;
},
has: (obj, prop) => {
if (typeof prop === "string" && state.isTracking) {
const fullPath = path ? `${path}.${prop}` : prop;
state.trackedPaths.add(fullPath);
}
return Reflect.has(obj, prop);
},
ownKeys: (obj) => {
if (state.isTracking && path) state.trackedPaths.add(path);
return Reflect.ownKeys(obj);
}
});
state.proxyCache.set(target, proxy);
return proxy;
}
/**
* Create a proxy for a target with caching
* @internal
*/
function createForTarget(state, target) {
if (state.lastProxiedState === target && state.lastProxy) return state.lastProxy;
state.proxyCache = /* @__PURE__ */ new WeakMap();
state.boundFunctionsCache = null;
const proxy = createInternal(state, target, "", 0);
state.lastProxiedState = target;
state.lastProxy = proxy;
return proxy;
}
function isChildPath(child, parent) {
if (child === parent) return false;
return child.startsWith(parent + ".") || child.startsWith(parent + "[");
}
function getArrayParentPath(path) {
if (path.endsWith(".length")) return path.slice(0, -7);
const arrayIndexMatch = path.match(/^(.+?)\[\d+\]/);
if (arrayIndexMatch) return arrayIndexMatch[1];
return null;
}
/**
* @internal
*/
function optimizeTrackedPaths(paths) {
if (paths.size === 0) return /* @__PURE__ */ new Set();
if (paths.size === 1) return new Set(paths);
const sortedPaths = Array.from(paths).sort((a, b) => b.length - a.length);
const optimized = /* @__PURE__ */ new Set();
for (const path of sortedPaths) {
let hasMoreSpecificChild = false;
for (const optimizedPath of optimized) if (isChildPath(optimizedPath, path)) {
hasMoreSpecificChild = true;
break;
}
if (!hasMoreSpecificChild) optimized.add(path);
}
const arrayParents = /* @__PURE__ */ new Set();
for (const path of optimized) {
const arrayParent = getArrayParentPath(path);
if (arrayParent) arrayParents.add(arrayParent);
}
for (const arrayParent of arrayParents) optimized.add(arrayParent);
return optimized;
}
/**
* @internal
*/
function createDependencyState() {
return {
proxyState: createProxyState(),
previousRenderPaths: /* @__PURE__ */ new Set(),
currentRenderPaths: /* @__PURE__ */ new Set(),
pathCache: /* @__PURE__ */ new Map(),
lastCheckedState: null,
lastCheckedValues: /* @__PURE__ */ new Map()
};
}
/**
* @internal
*/
function startDependency(tracker) {
startProxy(tracker.proxyState);
}
/**
* @internal
*/
function createDependencyProxy(tracker, state) {
return createForTarget(tracker.proxyState, state);
}
/**
* @internal
*/
function capturePaths(tracker, state) {
tracker.previousRenderPaths = tracker.currentRenderPaths;
tracker.currentRenderPaths = optimizeTrackedPaths(stopProxy(tracker.proxyState));
if (tracker.previousRenderPaths.size === 0 && tracker.currentRenderPaths.size === 0) return;
const trackedPathsUnion = new Set(tracker.previousRenderPaths);
for (const path of tracker.currentRenderPaths) trackedPathsUnion.add(path);
const canReuseCache = tracker.lastCheckedState === state;
for (const path of trackedPathsUnion) if (!tracker.pathCache.has(path)) {
const segments = parsePath(path);
const value = canReuseCache && tracker.lastCheckedValues.has(path) ? tracker.lastCheckedValues.get(path) : getValueAtPath(state, segments);
tracker.pathCache.set(path, {
segments,
value
});
} else {
const info = tracker.pathCache.get(path);
info.value = canReuseCache && tracker.lastCheckedValues.has(path) ? tracker.lastCheckedValues.get(path) : getValueAtPath(state, info.segments);
}
tracker.lastCheckedValues.clear();
}
/**
* @internal
*/
function hasDependencyChanges(tracker, state) {
if (tracker.pathCache.size === 0) return true;
tracker.lastCheckedValues.clear();
for (const [path, info] of tracker.pathCache.entries()) {
const currentValue = getValueAtPath(state, info.segments);
tracker.lastCheckedValues.set(path, currentValue);
if (!Object.is(currentValue, info.value)) {
tracker.lastCheckedState = state;
return true;
}
}
tracker.lastCheckedState = state;
return false;
}
/**
* @internal
*/
function hasTrackedData(tracker) {
return tracker.proxyState.trackedPaths.size > 0 || tracker.pathCache.size > 0 || tracker.previousRenderPaths.size > 0;
}
const descriptorCache = /* @__PURE__ */ new WeakMap();
const blocProxyCache = /* @__PURE__ */ new WeakMap();
const activeTrackerMap = /* @__PURE__ */ new WeakMap();
const MAX_GETTER_DEPTH = BLAC_DEFAULTS.MAX_GETTER_DEPTH;
/**
* @internal
*/
function getDescriptor(obj, prop) {
const constructor = obj.constructor;
let constructorCache = descriptorCache.get(constructor);
if (constructorCache?.has(prop)) return constructorCache.get(prop);
let current = obj;
let descriptor;
while (current && current !== Object.prototype) {
descriptor = Object.getOwnPropertyDescriptor(current, prop);
if (descriptor) break;
current = Object.getPrototypeOf(current);
}
if (!constructorCache) {
constructorCache = /* @__PURE__ */ new Map();
descriptorCache.set(constructor, constructorCache);
}
constructorCache.set(prop, descriptor);
return descriptor;
}
/**
* @internal
*/
function isGetter(obj, prop) {
return getDescriptor(obj, prop)?.get !== void 0;
}
/**
* @internal
*/
function createGetterState() {
return {
trackedValues: /* @__PURE__ */ new Map(),
currentlyAccessing: /* @__PURE__ */ new Set(),
trackedGetters: /* @__PURE__ */ new Set(),
isTracking: false,
renderCache: /* @__PURE__ */ new Map(),
cacheValid: false,
depth: 0,
visitedBlocs: /* @__PURE__ */ new Set()
};
}
/**
* @internal
*/
function setActiveTracker(bloc, tracker) {
activeTrackerMap.set(bloc, tracker);
}
/**
* @internal
*/
function clearActiveTracker(bloc) {
activeTrackerMap.delete(bloc);
}
/**
* @internal
*/
function commitTrackedGetters(tracker) {
if (tracker.currentlyAccessing.size > 0) tracker.trackedGetters = new Set(tracker.currentlyAccessing);
tracker.currentlyAccessing.clear();
}
/**
* Execute a tracked getter with depth/circular dependency checks and context management.
* @internal
*/
function executeTrackedGetter(target, prop, tracker) {
tracker.currentlyAccessing.add(prop);
if (tracker.cacheValid && tracker.renderCache.has(prop)) {
const cachedValue = tracker.renderCache.get(prop);
tracker.trackedValues.set(prop, cachedValue);
return cachedValue;
}
if (tracker.depth >= MAX_GETTER_DEPTH) {
console.warn(`${BLAC_ERROR_PREFIX} Maximum getter depth (${MAX_GETTER_DEPTH}) exceeded. Possible circular dependency in getter "${String(prop)}" on ${target.constructor.name}.`);
return;
}
if (tracker.visitedBlocs.has(target)) {
console.warn(`${BLAC_ERROR_PREFIX} Circular dependency detected: getter "${String(prop)}" on ${target.constructor.name}.`);
return;
}
const prevDepth = tracker.depth;
const prevVisited = new Set(tracker.visitedBlocs);
tracker.depth++;
tracker.visitedBlocs.add(target);
try {
const value = getDescriptor(target, prop).get.call(target);
tracker.trackedValues.set(prop, value);
return value;
} catch (error) {
tracker.currentlyAccessing.delete(prop);
throw error;
} finally {
tracker.depth = prevDepth;
tracker.visitedBlocs = prevVisited;
}
}
/**
* @internal
*/
function createBlocProxy(bloc) {
const cached = blocProxyCache.get(bloc);
if (cached) return cached;
const proxy = new Proxy(bloc, { get(target, prop, receiver) {
const tracker = activeTrackerMap.get(target);
if (tracker?.isTracking && isGetter(target, prop)) return executeTrackedGetter(target, prop, tracker);
return Reflect.get(target, prop, receiver);
} });
blocProxyCache.set(bloc, proxy);
return proxy;
}
/**
* @internal
*/
function hasGetterChanges(bloc, tracker) {
if (!tracker || tracker.trackedGetters.size === 0) return false;
tracker.renderCache.clear();
let hasAnyChange = false;
for (const prop of tracker.trackedGetters) try {
const descriptor = getDescriptor(bloc, prop);
if (!descriptor?.get) continue;
const newValue = descriptor.get.call(bloc);
const oldValue = tracker.trackedValues.get(prop);
tracker.renderCache.set(prop, newValue);
tracker.trackedValues.set(prop, newValue);
if (!Object.is(newValue, oldValue)) hasAnyChange = true;
} catch (error) {
console.warn(`${BLAC_ERROR_PREFIX} Getter "${String(prop)}" threw error during change detection. Stopping tracking for this getter.`, error);
tracker.trackedGetters.delete(prop);
tracker.trackedValues.delete(prop);
tracker.cacheValid = false;
return true;
}
tracker.cacheValid = true;
return hasAnyChange;
}
/**
* @internal
*/
function invalidateRenderCache(tracker) {
tracker.cacheValid = false;
}
/**
* Create a new tracking proxy state.
*/
function createState() {
return {
dependencyState: createDependencyState(),
getterState: createGetterState(),
dependencies: /* @__PURE__ */ new Set(),
isTracking: false
};
}
/**
* Start tracking on a tracking proxy.
*/
function startTracking(tracker) {
tracker.isTracking = true;
tracker.dependencies.clear();
tracker.getterState.isTracking = true;
startDependency(tracker.dependencyState);
}
/**
* Stop tracking and collect all dependencies.
*/
function stopTracking(tracker, bloc) {
tracker.isTracking = false;
tracker.getterState.isTracking = false;
capturePaths(tracker.dependencyState, bloc.state);
commitTrackedGetters(tracker.getterState);
return new Set(tracker.dependencies);
}
/**
* Check if tracked state or getters have changed.
*/
function hasChanges(tracker, bloc) {
invalidateRenderCache(tracker.getterState);
const stateChanged = hasDependencyChanges(tracker.dependencyState, bloc.state);
const getterChanged = hasGetterChanges(bloc, tracker.getterState);
return stateChanged || getterChanged;
}
/**
* Create a tracking proxy for a bloc instance.
* Tracks both state property access and getter access.
*/
function createTrackingProxy(bloc, tracker) {
tracker.dependencies.add(bloc);
const stateProxyCache = /* @__PURE__ */ new WeakMap();
return new Proxy(bloc, { get(target, prop, receiver) {
if (prop === "state") {
if (!tracker.isTracking) return target.state;
const rawState = target.state;
if (rawState === null || typeof rawState !== "object") return rawState;
if (stateProxyCache.has(rawState)) return stateProxyCache.get(rawState);
const stateProxy = createDependencyProxy(tracker.dependencyState, rawState);
stateProxyCache.set(rawState, stateProxy);
return stateProxy;
}
if (typeof prop === "symbol") return Reflect.get(target, prop, receiver);
const value = Reflect.get(target, prop, receiver);
if (typeof value === "function") return value.bind(target);
if (tracker.isTracking && isGetter(target, prop)) return executeTrackedGetter(target, prop, tracker.getterState);
return value;
} });
}
//#endregion
//#region src/tracking/dependency-manager.ts
/**
* Manages subscriptions to state container dependencies.
* Provides efficient sync mechanism to add/remove subscriptions
* as dependencies change between callback invocations.
*/
var DependencyManager = class {
constructor() {
this.subscriptions = /* @__PURE__ */ new Map();
this.currentDeps = /* @__PURE__ */ new Set();
}
/**
* Sync subscriptions with a new set of dependencies.
* Adds subscriptions for new deps, removes subscriptions for stale deps.
*
* @param newDeps - The new set of dependencies to subscribe to
* @param onChange - Callback to invoke when any dependency changes
* @param exclude - Optional instance to exclude from subscriptions (e.g., primary bloc)
* @returns true if the dependency set changed, false if unchanged
*/
sync(newDeps, onChange, exclude) {
const filteredNewDeps = /* @__PURE__ */ new Set();
for (const dep of newDeps) if (dep !== exclude && !dep.isDisposed) filteredNewDeps.add(dep);
if (this.areSetsEqual(this.currentDeps, filteredNewDeps)) return false;
for (const dep of this.currentDeps) if (!filteredNewDeps.has(dep)) {
const unsub = this.subscriptions.get(dep);
if (unsub) {
unsub();
this.subscriptions.delete(dep);
}
}
for (const dep of filteredNewDeps) if (!this.currentDeps.has(dep) && !this.subscriptions.has(dep)) {
const unsub = dep.subscribe(onChange);
this.subscriptions.set(dep, unsub);
}
this.currentDeps = filteredNewDeps;
return true;
}
/**
* Add a single dependency subscription.
*/
add(dep, onChange) {
if (this.subscriptions.has(dep) || dep.isDisposed) return;
const unsub = dep.subscribe(onChange);
this.subscriptions.set(dep, unsub);
this.currentDeps.add(dep);
}
/**
* Check if a dependency is currently subscribed.
*/
has(dep) {
return this.currentDeps.has(dep);
}
/**
* Get the current set of dependencies.
*/
getDependencies() {
return new Set(this.currentDeps);
}
/**
* Clean up all active subscriptions.
*/
cleanup() {
for (const unsub of this.subscriptions.values()) unsub();
this.subscriptions.clear();
this.currentDeps.clear();
}
areSetsEqual(a, b) {
if (a.size !== b.size) return false;
for (const item of a) if (!b.has(item)) return false;
return true;
}
};
//#endregion
//#region src/tracking/resolve-dependencies.ts
/**
* Resolve all transitive dependencies of a bloc via BFS over `dependencies` maps.
* Uses cycle detection to avoid infinite loops.
* @internal
*/
function resolveDependencies(bloc) {
const result = /* @__PURE__ */ new Set();
const visited = /* @__PURE__ */ new Set();
const queue = [bloc];
while (queue.length > 0) {
const current = queue.shift();
for (const [Type, key] of current.dependencies) {
if (visited.has(Type)) continue;
visited.add(Type);
const dep = globalRegistry.ensure(Type, key);
result.add(dep);
if (dep.dependencies.size > 0) queue.push(dep);
}
}
result.delete(bloc);
return result;
}
//#endregion
//#region src/watch/watch.ts
const STOP = Symbol("watch.STOP");
const BLOC_REF_MARKER = Symbol("BlocRef");
/**
* Create a reference to a specific bloc instance.
*
* @example
* ```ts
* watch(instance(UserBloc, 'user-123'), (userBloc) => {
* console.log(userBloc.state.name);
* });
* ```
*/
function instance(BlocClass, instanceId) {
return {
[BLOC_REF_MARKER]: true,
blocClass: BlocClass,
instanceId
};
}
function isBlocRef(input) {
return typeof input === "object" && input !== null && BLOC_REF_MARKER in input;
}
function resolveBloc(input) {
if (isBlocRef(input)) return ensure(input.blocClass, input.instanceId);
return ensure(input, BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY);
}
function isArray(input) {
return Array.isArray(input);
}
function watchImpl(blocsOrBloc, callback) {
const isSingle = !isArray(blocsOrBloc);
const instances = (isSingle ? [blocsOrBloc] : blocsOrBloc).map(resolveBloc);
const tracker = createState();
const proxiedInstances = instances.map((inst) => createTrackingProxy(inst, tracker));
const externalDepsManager = new DependencyManager();
let disposed = false;
const primarySubscriptions = [];
const cleanup = () => {
if (disposed) return;
disposed = true;
primarySubscriptions.forEach((unsub) => unsub());
externalDepsManager.cleanup();
};
const runCallback = () => {
if (disposed) return;
startTracking(tracker);
let result;
try {
result = callback(isSingle ? proxiedInstances[0] : proxiedInstances);
} finally {
const externalDeps = /* @__PURE__ */ new Set();
for (const inst of instances) {
const deps = stopTracking(tracker, inst);
for (const dep of deps) externalDeps.add(dep);
for (const dep of resolveDependencies(inst)) externalDeps.add(dep);
}
for (const inst of instances) externalDeps.delete(inst);
externalDepsManager.sync(externalDeps, runCallback);
}
if (result === STOP) cleanup();
};
const onChange = () => {
if (disposed) return;
runCallback();
};
for (const inst of instances) primarySubscriptions.push(inst.subscribe(onChange));
runCallback();
return cleanup;
}
const watch = Object.assign(watchImpl, { STOP });
//#endregion
//#region src/tracking/tracked.ts
/**
* Run a callback while tracking all bloc dependencies accessed.
* Returns both the result and the set of discovered dependencies.
*
* @example
* ```ts
* const { result, dependencies } = tracked(() => {
* const user = ensure(UserBloc);
* return user.fullName; // getter that may access other blocs
* });
* // dependencies contains UserBloc + any blocs accessed in fullName getter
* ```
*/
function tracked(callback, options) {
const tracker = createState();
startTracking(tracker);
let result;
try {
result = callback();
} finally {
stopTracking(tracker, { state: null });
}
const dependencies = new Set(tracker.dependencies);
if (options?.exclude) dependencies.delete(options.exclude);
return {
result,
dependencies
};
}
/**
* Context for running tracked callbacks with bloc proxies.
* Provides methods to create proxies and check for changes.
*/
var TrackedContext = class {
constructor() {
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
this.primaryBlocs = /* @__PURE__ */ new Set();
this.tracker = createState();
}
/**
* Get a tracking proxy for a bloc instance.
* The proxy will track state and getter accesses.
*/
proxy(bloc) {
const cached = this.proxiedBlocs.get(bloc);
if (cached) return cached;
const proxied = createTrackingProxy(bloc, this.tracker);
this.proxiedBlocs.set(bloc, proxied);
this.primaryBlocs.add(bloc);
return proxied;
}
/**
* Start tracking for a new callback execution.
*/
start() {
startTracking(this.tracker);
}
/**
* Stop tracking and get discovered dependencies.
* Excludes primary blocs (those explicitly proxied via proxy()).
*/
stop() {
const allDeps = /* @__PURE__ */ new Set();
for (const bloc of this.primaryBlocs) {
const deps = stopTracking(this.tracker, bloc);
for (const dep of deps) if (!this.primaryBlocs.has(dep)) allDeps.add(dep);
}
return allDeps;
}
/**
* Check if any tracked state or getters have changed.
*/
changed() {
for (const bloc of this.primaryBlocs) if (hasChanges(this.tracker, bloc)) return true;
return false;
}
/**
* Get all primary blocs (those explicitly proxied).
*/
getPrimaryBlocs() {
return new Set(this.primaryBlocs);
}
/**
* Reset the context for reuse.
*/
reset() {
this.tracker = createState();
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
this.primaryBlocs.clear();
}
};
/**
* Create a new tracked context for manual control over tracking.
*/
function createTrackedContext() {
return new TrackedContext();
}
//#endregion
//#region src/types/branded.ts
/**
* Create a branded InstanceId from a string
* @param id - The string ID to brand
* @returns Branded InstanceId
*/
function instanceId(id) {
return id;
}
//#endregion
exports.Cubit = Cubit;
exports.DependencyManager = require_resolve_dependencies.DependencyManager;
exports.PluginManager = require_StateContainerRegistry.PluginManager;
exports.DependencyManager = DependencyManager;
exports.PluginManager = PluginManager;
exports.StateContainer = StateContainer;
exports.TrackedContext = TrackedContext;
exports.acquire = acquire;

@@ -336,31 +1782,38 @@ exports.blac = blac;

exports.borrowSafe = borrowSafe;
exports.capturePaths = require_resolve_dependencies.capturePaths;
exports.clear = require_management.clear;
exports.clearActiveTracker = require_resolve_dependencies.clearActiveTracker;
exports.clearAll = require_management.clearAll;
exports.commitTrackedGetters = require_resolve_dependencies.commitTrackedGetters;
exports.createBlocProxy = require_resolve_dependencies.createBlocProxy;
exports.createDependencyProxy = require_resolve_dependencies.createDependencyProxy;
exports.createDependencyState = require_resolve_dependencies.createDependencyState;
exports.createGetterState = require_resolve_dependencies.createGetterState;
exports.ensure = require_watch.ensure;
exports.forEach = require_management.forEach;
exports.capturePaths = capturePaths;
exports.clear = clear;
exports.clearActiveTracker = clearActiveTracker;
exports.clearAll = clearAll;
exports.commitTrackedGetters = commitTrackedGetters;
exports.createBlocProxy = createBlocProxy;
exports.createDependencyProxy = createDependencyProxy;
exports.createDependencyState = createDependencyState;
exports.createGetterState = createGetterState;
exports.createTrackedContext = createTrackedContext;
exports.ensure = ensure;
exports.forEach = forEach;
exports.generateIsolatedKey = generateIsolatedKey;
exports.getAll = require_management.getAll;
exports.getPluginManager = require_StateContainerRegistry.getPluginManager;
exports.getRefCount = require_management.getRefCount;
exports.globalRegistry = require_StateContainerRegistry.globalRegistry;
exports.hasDependencyChanges = require_resolve_dependencies.hasDependencyChanges;
exports.hasGetterChanges = require_resolve_dependencies.hasGetterChanges;
exports.hasInstance = require_management.hasInstance;
exports.hasTrackedData = require_resolve_dependencies.hasTrackedData;
exports.instance = require_watch.instance;
exports.invalidateRenderCache = require_resolve_dependencies.invalidateRenderCache;
exports.isIsolatedClass = require_StateContainerRegistry.isIsolatedClass;
exports.getAll = getAll;
exports.getPluginManager = getPluginManager;
exports.getRefCount = getRefCount;
exports.getRegistry = getRegistry;
exports.getStats = getStats;
exports.globalRegistry = globalRegistry;
exports.hasDependencyChanges = hasDependencyChanges;
exports.hasGetterChanges = hasGetterChanges;
exports.hasInstance = hasInstance;
exports.hasTrackedData = hasTrackedData;
exports.instance = instance;
exports.instanceId = instanceId;
exports.invalidateRenderCache = invalidateRenderCache;
exports.isIsolatedClass = isIsolatedClass;
exports.register = register;
exports.release = release;
exports.resolveDependencies = require_resolve_dependencies.resolveDependencies;
exports.setActiveTracker = require_resolve_dependencies.setActiveTracker;
exports.shallowEqual = require_resolve_dependencies.shallowEqual;
exports.startDependency = require_resolve_dependencies.startDependency;
exports.watch = require_watch.watch;
exports.resolveDependencies = resolveDependencies;
exports.setActiveTracker = setActiveTracker;
exports.setRegistry = setRegistry;
exports.shallowEqual = shallowEqual;
exports.startDependency = startDependency;
exports.tracked = tracked;
exports.watch = watch;
//# sourceMappingURL=index.cjs.map
+18
-794

@@ -1,794 +0,18 @@

export declare function acquire<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): InstanceType<T>;
/**
* Decorator to configure StateContainer classes.
*
* @example Decorator syntax (requires experimentalDecorators or TC39 decorators)
* ```ts
* @blac({ isolated: true })
* class FormBloc extends Cubit<FormState> {}
*
* @blac({ keepAlive: true })
* class AuthBloc extends Cubit<AuthState> {}
*
* @blac({ excludeFromDevTools: true })
* class InternalBloc extends Cubit<InternalState> {}
* ```
*
* @example Function syntax (no decorator support needed)
* ```ts
* const FormBloc = blac({ isolated: true })(
* class extends Cubit<FormState> {}
* );
* ```
*/
export declare function blac(options: BlacOptions): <T extends new (...args: any[]) => any>(target: T, _context?: ClassDecoratorContext) => T;
/**
* Configuration options for the @blac decorator.
* Only one option can be specified at a time (union type).
*/
export declare type BlacOptions =
/** Mark bloc as isolated (each component gets its own instance) */
{
isolated: true;
}
/** Mark bloc to never be auto-disposed when ref count reaches 0 */
| {
keepAlive: true;
}
/** Exclude bloc from DevTools tracking (prevents infinite loops) */
| {
excludeFromDevTools: true;
};
/**
* Interface for plugins that extend BlaC functionality
*/
export declare interface BlacPlugin {
/** Unique plugin identifier */
readonly name: string;
/** Plugin version identifier */
readonly version: string;
/**
* Called when the plugin is installed (optional)
*/
onInstall?(context: PluginContext): void;
/**
* Called when the plugin is uninstalled
*/
onUninstall?(): void;
/**
* Called when a state container instance is created
*/
onInstanceCreated?(instance: StateContainer<any>, context: PluginContext): void;
/**
* Called when state changes in a container instance
*/
onStateChanged?<S extends object = any>(instance: StateContainer<S>, previousState: S, currentState: S, callstack: string | undefined, context: PluginContext): void;
/**
* Called when a state container instance is disposed
*/
onInstanceDisposed?(instance: StateContainer<any>, context: PluginContext): void;
}
/**
* Plugin interface variant that requires mandatory onInstall hook
*/
export declare interface BlacPluginWithInit extends BlacPlugin {
/**
* Required initialization hook called when plugin is installed
*/
onInstall(context: PluginContext): void;
}
declare const BLOC_REF_MARKER: unique symbol;
/**
* Constructor type for StateContainer classes with static registry methods.
* Used for type-safe hook parameters.
* @template TBloc - The StateContainer instance type
*/
export declare type BlocConstructor<S extends object = any, T extends new (...args: any[]) => StateContainer<S> = new (...args: any[]) => StateContainer<S>> = (new (...args: any[]) => InstanceType<T>) & {
acquire(instanceKey?: string, ...args: any[]): InstanceType<T>;
borrow(instanceKey?: string, ...args: any[]): InstanceType<T> | null;
borrowSafe(instanceKey?: string, ...args: any[]): {
error: Error;
instance: null;
} | {
error: null;
instance: InstanceType<T>;
};
ensure(instanceKey?: string): InstanceType<T>;
release(instanceKey?: string): void;
isolated?: boolean;
keepAlive?: boolean;
};
declare type BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;
/**
* Extract instance type from an abstract class constructor
* @template T - The abstract class constructor type
*/
export declare type BlocInstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
/**
* Reference to a specific bloc instance by class and instance ID.
*/
export declare interface BlocRef<T extends StateContainerConstructor> {
[BLOC_REF_MARKER]: true;
blocClass: T;
instanceId: string;
}
export declare function borrow<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): InstanceType<T>;
export declare function borrowSafe<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): {
error: Error;
instance: null;
} | {
error: null;
instance: InstanceType<T>;
};
/* Excluded from this release type: capturePaths */
export declare function clear<T extends StateContainerConstructor>(BlocClass: T): void;
/* Excluded from this release type: clearActiveTracker */
export declare function clearAll(): void;
/* Excluded from this release type: commitTrackedGetters */
/* Excluded from this release type: createBlocProxy */
/* Excluded from this release type: createDependencyProxy */
/* Excluded from this release type: createDependencyState */
/* Excluded from this release type: createGetterState */
/**
* Simple state container with direct state emission.
* Extends StateContainer with public methods for emitting and updating state.
*
* @template S - State type
*/
export declare abstract class Cubit<S extends object = any> extends StateContainer<S> {
constructor(initialState: S);
/**
* Replace state with a new value and notify all listeners
* @param newState - The new state value
*/
emit(newState: S): void;
/**
* Transform current state using an updater function and emit the new state
* @param updater - Function that receives current state and returns new state
*/
update(updater: (current: S) => S): void;
/**
* Merge partial state changes into current state (only for object states)
*/
patch: S extends object ? (partial: Partial<S>) => void : never;
}
/**
* Manages subscriptions to state container dependencies.
* Provides efficient sync mechanism to add/remove subscriptions
* as dependencies change between callback invocations.
*/
export declare class DependencyManager {
private subscriptions;
private currentDeps;
/**
* Sync subscriptions with a new set of dependencies.
* Adds subscriptions for new deps, removes subscriptions for stale deps.
*
* @param newDeps - The new set of dependencies to subscribe to
* @param onChange - Callback to invoke when any dependency changes
* @param exclude - Optional instance to exclude from subscriptions (e.g., primary bloc)
* @returns true if the dependency set changed, false if unchanged
*/
sync(newDeps: Set<StateContainerInstance>, onChange: () => void, exclude?: StateContainerInstance): boolean;
/**
* Add a single dependency subscription.
*/
add(dep: StateContainerInstance, onChange: () => void): void;
/**
* Check if a dependency is currently subscribed.
*/
has(dep: StateContainerInstance): boolean;
/**
* Get the current set of dependencies.
*/
getDependencies(): Set<StateContainerInstance>;
/**
* Clean up all active subscriptions.
*/
cleanup(): void;
private areSetsEqual;
}
/* Excluded from this release type: DependencyState */
export declare function ensure<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): InstanceType<T>;
/**
* Extract constructor argument types from a class
* @template T - The class type
*/
export declare type ExtractConstructorArgs<T> = T extends new (...args: infer P) => any ? P : never[];
declare type ExtractInstance<T> = T extends BlocRef<infer C> ? InstanceType<C> : T extends StateContainerConstructor ? InstanceType<T> : never;
declare type ExtractInstances<T extends readonly BlocInput[]> = {
[K in keyof T]: ExtractInstance<T[K]>;
};
/**
* Extract the state type from a StateContainer
* @template T - The StateContainer type
*/
export declare type ExtractState<T> = T extends StateContainerConstructor<infer S> ? Readonly<S> : never;
export declare type ExtractStateMutable<T> = T extends StateContainerConstructor<infer S> ? S : never;
export declare function forEach<T extends StateContainerConstructor>(BlocClass: T, callback: (instance: InstanceReadonlyState<T>) => void): void;
/**
* Generate a unique isolated instance key
* Uses base36 encoding for compact, URL-safe identifiers
*
* Format: "isolated-{9-char-random-string}"
* Example: "isolated-k7x2m9p4q"
*
* @returns A unique isolated instance key
*/
export declare function generateIsolatedKey(): string;
export declare function getAll<T extends StateContainerConstructor>(BlocClass: T): InstanceReadonlyState<T>[];
/**
* Get the global plugin manager
*/
export declare function getPluginManager(): any;
export declare function getRefCount<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): number;
/* Excluded from this release type: GetterState */
/**
* Global default registry instance
*/
export declare const globalRegistry: StateContainerRegistry;
/* Excluded from this release type: hasDependencyChanges */
/* Excluded from this release type: hasGetterChanges */
export declare function hasInstance<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): boolean;
/* Excluded from this release type: hasTrackedData */
/**
* Create a reference to a specific bloc instance.
*
* @example
* ```ts
* watch(instance(UserBloc, 'user-123'), (userBloc) => {
* console.log(userBloc.state.name);
* });
* ```
*/
export declare function instance<T extends StateContainerConstructor>(BlocClass: T, instanceId: string): BlocRef<T>;
/**
* Entry in the instance registry, tracking the instance and its reference count
* @template T - Instance type
*/
export declare interface InstanceEntry<T = any> {
/** The state container instance */
instance: T;
/** Number of active references to this instance */
refCount: number;
}
/**
* Metadata information about a state container instance for debugging and inspection
*/
export declare interface InstanceMetadata {
/** Unique instance identifier */
id: string;
/** Name of the state container class */
className: string;
/** Whether the instance has been disposed */
isDisposed: boolean;
/** Display name for the instance */
name: string;
/** When state last changed (milliseconds) */
lastStateChangeTimestamp: number;
/** Current state value */
state: any;
/** Timestamp when instance was created (milliseconds) */
createdAt: number;
/** Whether this is an isolated (component-scoped) instance */
isIsolated: boolean;
/** Stack trace from when instance was created (for debugging) */
callstack?: string;
/** Previous state value */
previousState?: any;
/** Current state value */
currentState?: any;
}
export declare type InstanceReadonlyState<T extends StateContainerConstructor = any> = Omit<InstanceType<T>, 'state'> & {
state: ExtractState<T>;
};
export declare type InstanceState<T extends StateContainerConstructor = any> = Omit<InstanceType<T>, 'state'> & {
state: ExtractStateMutable<T>;
};
/* Excluded from this release type: invalidateRenderCache */
/**
* Check if a class is marked as isolated.
* Isolated classes create separate instances per component.
* @param Type - The class constructor to check
* @returns true if the class has `static isolated = true`
*/
export declare function isIsolatedClass<T extends StateContainerConstructor>(Type: T): boolean;
/**
* Lifecycle events emitted by the registry
*/
export declare type LifecycleEvent = 'created' | 'stateChanged' | 'disposed';
/**
* Listener function type for each lifecycle event
* @template E - The lifecycle event type
*/
export declare type LifecycleListener<E extends LifecycleEvent> = E extends 'created' ? (container: StateContainer<any>) => void : E extends 'stateChanged' ? (container: StateContainer<any>, previousState: any, currentState: any, callstack?: string) => void : E extends 'disposed' ? (container: StateContainer<any>) => void : never;
/* Excluded from this release type: PathInfo */
/**
* Configuration options for plugin installation
*/
export declare interface PluginConfig {
/** Enable or disable the plugin */
enabled?: boolean;
/** Environments where plugin runs */
environment?: 'development' | 'production' | 'test' | 'all';
}
/**
* Safe context API provided to plugins for accessing registry data
*/
export declare interface PluginContext {
/**
* Get metadata for a specific instance
*/
getInstanceMetadata(instance: StateContainer<any>): InstanceMetadata;
/**
* Get current state from a container
*/
getState<S extends object = any>(instance: StateContainer<S>): S;
/**
* Get all instances of a specific type
*/
queryInstances<T extends StateContainer<any>>(typeClass: new (...args: any[]) => T): T[];
/**
* Get all registered state container types
*/
getAllTypes(): Array<new (...args: any[]) => StateContainer<any>>;
/**
* Get registry statistics
*/
getStats(): {
registeredTypes: number;
totalInstances: number;
typeBreakdown: Record<string, number>;
};
}
/**
* Manages plugin lifecycle for the BlaC state management system.
* Plugins receive notifications about state container lifecycle events.
*
* @example
* ```ts
* const manager = createPluginManager(registry);
* manager.install(myPlugin, { environment: 'development' });
* ```
*/
export declare class PluginManager {
private plugins;
private registry;
/**
* Create a new PluginManager
* @param registry - The StateContainerRegistry to monitor for lifecycle events
*/
constructor(registry: StateContainerRegistry);
/**
* Install a plugin with optional configuration
* @param plugin - The plugin to install
* @param config - Optional plugin configuration
* @throws Error if plugin is already installed
*/
install(plugin: BlacPlugin, config?: PluginConfig): void;
/**
* Uninstall a plugin by name
* @param pluginName - The name of the plugin to uninstall
* @throws Error if plugin is not installed
*/
uninstall(pluginName: string): void;
/**
* Get an installed plugin by name
* @param pluginName - The name of the plugin to retrieve
* @returns The plugin instance or undefined if not found
*/
getPlugin(pluginName: string): BlacPlugin | undefined;
/**
* Get all installed plugins
* @returns Array of all installed plugins
*/
getAllPlugins(): BlacPlugin[];
/**
* Check if a plugin is installed
* @param pluginName - The name of the plugin to check
* @returns true if the plugin is installed
*/
hasPlugin(pluginName: string): boolean;
/**
* Uninstall all plugins
*/
clear(): void;
/**
* Setup lifecycle hooks to notify plugins
*/
private setupLifecycleHooks;
/**
* Notify all plugins of a lifecycle event
*/
private notifyPlugins;
/**
* Create plugin context with safe API access
*/
private createPluginContext;
/**
* Check if plugin should be enabled based on environment
*/
private shouldEnablePlugin;
/**
* Get current environment
*/
private getCurrentEnvironment;
}
/* Excluded from this release type: ProxyState */
export declare function release<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string, forceDispose?: boolean): void;
/* Excluded from this release type: resolveDependencies */
/* Excluded from this release type: setActiveTracker */
/* Excluded from this release type: shallowEqual */
/* Excluded from this release type: startDependency */
/**
* Abstract base class for all state containers in BlaC.
* Provides lifecycle management, subscription handling, ref counting,
* and integration with the global registry.
*
* @template S - State type managed by this container
*
* @example
* ```ts
* class CounterBloc extends StateContainer<{ count: number }> {
* constructor() {
* super({ count: 0 });
* }
* increment() {
* this.emit({ count: this.state.count + 1 });
* }
* }
* ```
*/
export declare abstract class StateContainer<S extends object = any> {
static __excludeFromDevTools: boolean;
static enableStackTrace: boolean;
private _state;
private readonly listeners;
private _disposed;
private config;
private readonly systemEventHandlers;
/** Display name for this instance */
name: string;
/** Whether debug logging is enabled */
debug: boolean;
/** Unique identifier for this instance */
instanceId: string;
/** Timestamp when this instance was created */
createdAt: number;
private _dependencies;
get dependencies(): ReadonlyMap<StateContainerConstructor, string>;
protected depend<T extends StateContainerConstructor>(Type: T, instanceKey?: string): () => InstanceType<T>;
constructor(initialState: S);
/**
* Initialize configuration for this instance.
* Called by the registry after construction.
* @param config - Configuration options
*/
initConfig(config: StateContainerConfig): void;
/** Current state value */
get state(): Readonly<S>;
/** Whether this instance has been disposed */
get isDisposed(): boolean;
/**
* Subscribe to state changes
* @param listener - Function called when state changes
* @returns Unsubscribe function
*/
subscribe(listener: StateListener<S>): () => void;
/**
* Dispose this instance and clean up resources.
* Clears all listeners and emits the 'dispose' system event.
*/
dispose(): void;
/**
* Emit a new state value and notify all listeners.
* @param newState - The new state value
* @protected
*/
protected emit(newState: S): void;
private captureStackTrace;
private formatStackLine;
private cleanFilePath;
/** Timestamp of the last state update */
lastUpdateTimestamp: number;
/**
* Update state using a transform function.
* @param updater - Function that receives current state and returns new state
* @protected
*/
protected update(updater: (current: S) => S): void;
/**
* Subscribe to system lifecycle events.
* @param event - The event type to listen for
* @param handler - Handler function called when event occurs
* @returns Unsubscribe function
* @protected
*/
protected onSystemEvent: <E extends SystemEvent>(event: E, handler: SystemEventHandler<S, E>) => (() => void);
private emitSystemEvent;
}
/**
* Configuration options for initializing a StateContainer instance
*/
export declare interface StateContainerConfig {
/** Display name for the instance (defaults to class name) */
name?: string;
/** Enable debug logging for this instance */
debug?: boolean;
/** Custom instance identifier */
instanceId?: string;
}
/**
* Constructor type for StateContainer classes
* @template S - State type managed by the container
*/
export declare type StateContainerConstructor<S extends object = any> = new (...args: any[]) => StateContainer<S>;
export declare type StateContainerInstance<S extends object = any> = Omit<StateContainer<S>, 'state'> & {
state: Readonly<S>;
};
/**
* Central registry for managing StateContainer instances.
* Handles instance lifecycle, ref counting, and lifecycle event emission.
*
* @example
* ```ts
* const registry = new StateContainerRegistry();
* const instance = registry.acquire(MyBloc); // ownership, must release
* const other = registry.ensure(OtherBloc); // no ownership, bloc-to-bloc
* registry.on('stateChanged', (container, prev, next) => {
* console.log('State changed:', prev, '->', next);
* });
* ```
*/
declare class StateContainerRegistry {
private readonly instancesByConstructor;
private readonly types;
private readonly typeConfigs;
private readonly listeners;
/**
* Register a type for lifecycle event tracking
* @param constructor - The StateContainer class constructor
*/
registerType<T extends StateContainerConstructor>(constructor: T): void;
/**
* Register a StateContainer class with configuration
* @param constructor - The StateContainer class constructor
* @param isolated - Whether instances should be isolated (component-scoped)
* @throws Error if type is already registered
*/
register<T extends StateContainerConstructor>(constructor: T, isolated?: boolean): void;
private ensureInstancesMap;
/**
* Get the instances Map for a specific class (public API for stats/debugging)
*/
getInstancesMap<T extends StateContainerConstructor>(Type: T): Map<string, InstanceEntry>;
/**
* Acquire an instance with ref counting (ownership semantics).
* Creates a new instance if one doesn't exist, or returns existing and increments ref count.
* You must call `release()` when done to decrement the ref count.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param options - Acquisition options
* @param options.canCreate - Whether to create new instance if not found (default: true)
* @param options.countRef - Whether to increment ref count (default: true)
* @returns The state container instance
*/
acquire<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string, options?: {
canCreate?: boolean;
countRef?: boolean;
}): InstanceType<T>;
/**
* Borrow an existing instance without incrementing ref count (borrowing semantics).
* Tracks cross-bloc dependency for reactive updates.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
* @throws Error if instance doesn't exist
*/
borrow<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): InstanceType<T>;
/**
* Safely borrow an existing instance (borrowing semantics with error handling).
* Returns discriminated union for type-safe conditional access.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Discriminated union with either the instance or an error
*/
borrowSafe<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): {
error: Error;
instance: null;
} | {
error: null;
instance: InstanceType<T>;
};
/**
* Ensure an instance exists without taking ownership (for bloc-to-bloc communication).
* Gets existing instance OR creates it if it doesn't exist, without incrementing ref count.
* Tracks cross-bloc dependency for reactive updates.
*
* Use this in bloc-to-bloc communication when you need to ensure an instance exists
* but don't want to claim ownership (no ref count increment).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
*/
ensure<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): InstanceType<T>;
/**
* Release a reference to an instance.
* Decrements ref count and disposes when it reaches 0 (unless keepAlive).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param forceDispose - Force immediate disposal regardless of ref count
*/
release<T extends StateContainerConstructor>(Type: T, instanceKey?: string, forceDispose?: boolean): void;
/**
* Get all instances of a specific type.
* @param Type - The StateContainer class constructor
* @returns Array of all instances
*/
getAll<T extends StateContainerConstructor>(Type: T): InstanceReadonlyState<T>[];
/**
* Safely iterate over all instances of a type.
* Skips disposed instances and catches callback errors.
* @param Type - The StateContainer class constructor
* @param callback - Function to call for each instance
*/
forEach<T extends StateContainerConstructor>(Type: T, callback: (instance: InstanceReadonlyState<T>) => void): void;
/**
* Clear all instances of a specific type (disposes them).
* @param Type - The StateContainer class constructor
*/
clear<T extends StateContainerConstructor>(Type: T): void;
/**
* Get reference count for an instance.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Current ref count (0 if instance doesn't exist)
*/
getRefCount<T extends StateContainerConstructor>(Type: T, instanceKey?: string): number;
/**
* Check if an instance exists.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns true if instance exists
*/
hasInstance<T extends StateContainerConstructor>(Type: T, instanceKey?: string): boolean;
/**
* Clear all instances from all types (for testing)
*
* Iterates all registered types and clears their instances.
* Also clears type tracking to reset the registry state.
*/
clearAll(): void;
/**
* Get registry statistics for debugging.
* @returns Object with registeredTypes, totalInstances, and typeBreakdown
*/
getStats(): {
registeredTypes: number;
totalInstances: number;
typeBreakdown: Record<string, number>;
};
/**
* Get all registered types (for plugin system).
* @returns Array of all registered StateContainer class constructors
*/
getTypes(): StateContainerConstructor[];
/**
* Subscribe to lifecycle events
* @param event - The lifecycle event to listen for
* @param listener - The listener function to call when the event occurs
* @returns Unsubscribe function
*/
on<E extends LifecycleEvent>(event: E, listener: LifecycleListener<E>): () => void;
/* Excluded from this release type: emit */
}
/* Excluded from this release type: StateListener */
declare const STOP: unique symbol;
declare type StopSymbol = typeof STOP;
/**
* System events emitted by StateContainer lifecycle
*/
export declare type SystemEvent = 'stateChanged' | 'dispose';
/* Excluded from this release type: SystemEventHandler */
/**
* Payload types for each system event
* @template S - State type
*/
export declare interface SystemEventPayloads<S> {
/** Emitted when state changes via emit() or update() */
stateChanged: {
state: S;
previousState: S;
};
/** Emitted when the instance is disposed */
dispose: void;
}
export declare const watch: WatchFn;
/**
* Combined watch function type.
*/
export declare interface WatchFn extends WatchSingleFn {
<T extends readonly BlocInput[]>(blocs: T, callback: (blocs: ExtractInstances<T>) => void | StopSymbol): () => void;
}
/**
* Watch function signature for single bloc.
*/
declare interface WatchSingleFn {
<T extends StateContainerConstructor>(bloc: T | BlocRef<T>, callback: (bloc: InstanceType<T>) => void | StopSymbol): () => void;
STOP: StopSymbol;
}
export { }
export { StateContainer } from './core/StateContainer';
export type { StateContainerConfig, SystemEvent, SystemEventPayloads, } from './core/StateContainer';
export { Cubit } from './core/Cubit';
export { acquire, borrow, borrowSafe, ensure, release, clear, clearAll, register, hasInstance, getRefCount, getAll, forEach, getRegistry, setRegistry, getStats, } from './registry';
export { globalRegistry } from './core/StateContainerRegistry';
export type { LifecycleEvent, LifecycleListener, InstanceEntry, } from './core/StateContainerRegistry';
export { blac, type BlacOptions } from './decorators';
export { getPluginManager } from './core/StateContainerRegistry';
export type { BlacPlugin, BlacPluginWithInit, PluginContext, PluginConfig, InstanceMetadata, } from './plugin/BlacPlugin';
export { PluginManager } from './plugin/PluginManager';
export { watch, instance, type WatchFn, type BlocRef } from './watch';
export { tracked, createTrackedContext, TrackedContext, type TrackedResult, type TrackedOptions, } from './tracking/tracked';
export type { StateContainerConstructor, ExtractState, ExtractStateMutable, ExtractConstructorArgs, BlocInstanceType, BlocConstructor, InstanceReadonlyState, InstanceState, StateContainerInstance, } from './types/utilities';
export type { Brand, BrandedId, InstanceId } from './types/branded';
export { instanceId } from './types/branded';
export * from './tracking';
export { isIsolatedClass } from './utils/static-props';
export { generateIsolatedKey } from './utils/idGenerator';

@@ -1,794 +0,18 @@

export declare function acquire<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): InstanceType<T>;
/**
* Decorator to configure StateContainer classes.
*
* @example Decorator syntax (requires experimentalDecorators or TC39 decorators)
* ```ts
* @blac({ isolated: true })
* class FormBloc extends Cubit<FormState> {}
*
* @blac({ keepAlive: true })
* class AuthBloc extends Cubit<AuthState> {}
*
* @blac({ excludeFromDevTools: true })
* class InternalBloc extends Cubit<InternalState> {}
* ```
*
* @example Function syntax (no decorator support needed)
* ```ts
* const FormBloc = blac({ isolated: true })(
* class extends Cubit<FormState> {}
* );
* ```
*/
export declare function blac(options: BlacOptions): <T extends new (...args: any[]) => any>(target: T, _context?: ClassDecoratorContext) => T;
/**
* Configuration options for the @blac decorator.
* Only one option can be specified at a time (union type).
*/
export declare type BlacOptions =
/** Mark bloc as isolated (each component gets its own instance) */
{
isolated: true;
}
/** Mark bloc to never be auto-disposed when ref count reaches 0 */
| {
keepAlive: true;
}
/** Exclude bloc from DevTools tracking (prevents infinite loops) */
| {
excludeFromDevTools: true;
};
/**
* Interface for plugins that extend BlaC functionality
*/
export declare interface BlacPlugin {
/** Unique plugin identifier */
readonly name: string;
/** Plugin version identifier */
readonly version: string;
/**
* Called when the plugin is installed (optional)
*/
onInstall?(context: PluginContext): void;
/**
* Called when the plugin is uninstalled
*/
onUninstall?(): void;
/**
* Called when a state container instance is created
*/
onInstanceCreated?(instance: StateContainer<any>, context: PluginContext): void;
/**
* Called when state changes in a container instance
*/
onStateChanged?<S extends object = any>(instance: StateContainer<S>, previousState: S, currentState: S, callstack: string | undefined, context: PluginContext): void;
/**
* Called when a state container instance is disposed
*/
onInstanceDisposed?(instance: StateContainer<any>, context: PluginContext): void;
}
/**
* Plugin interface variant that requires mandatory onInstall hook
*/
export declare interface BlacPluginWithInit extends BlacPlugin {
/**
* Required initialization hook called when plugin is installed
*/
onInstall(context: PluginContext): void;
}
declare const BLOC_REF_MARKER: unique symbol;
/**
* Constructor type for StateContainer classes with static registry methods.
* Used for type-safe hook parameters.
* @template TBloc - The StateContainer instance type
*/
export declare type BlocConstructor<S extends object = any, T extends new (...args: any[]) => StateContainer<S> = new (...args: any[]) => StateContainer<S>> = (new (...args: any[]) => InstanceType<T>) & {
acquire(instanceKey?: string, ...args: any[]): InstanceType<T>;
borrow(instanceKey?: string, ...args: any[]): InstanceType<T> | null;
borrowSafe(instanceKey?: string, ...args: any[]): {
error: Error;
instance: null;
} | {
error: null;
instance: InstanceType<T>;
};
ensure(instanceKey?: string): InstanceType<T>;
release(instanceKey?: string): void;
isolated?: boolean;
keepAlive?: boolean;
};
declare type BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;
/**
* Extract instance type from an abstract class constructor
* @template T - The abstract class constructor type
*/
export declare type BlocInstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
/**
* Reference to a specific bloc instance by class and instance ID.
*/
export declare interface BlocRef<T extends StateContainerConstructor> {
[BLOC_REF_MARKER]: true;
blocClass: T;
instanceId: string;
}
export declare function borrow<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): InstanceType<T>;
export declare function borrowSafe<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): {
error: Error;
instance: null;
} | {
error: null;
instance: InstanceType<T>;
};
/* Excluded from this release type: capturePaths */
export declare function clear<T extends StateContainerConstructor>(BlocClass: T): void;
/* Excluded from this release type: clearActiveTracker */
export declare function clearAll(): void;
/* Excluded from this release type: commitTrackedGetters */
/* Excluded from this release type: createBlocProxy */
/* Excluded from this release type: createDependencyProxy */
/* Excluded from this release type: createDependencyState */
/* Excluded from this release type: createGetterState */
/**
* Simple state container with direct state emission.
* Extends StateContainer with public methods for emitting and updating state.
*
* @template S - State type
*/
export declare abstract class Cubit<S extends object = any> extends StateContainer<S> {
constructor(initialState: S);
/**
* Replace state with a new value and notify all listeners
* @param newState - The new state value
*/
emit(newState: S): void;
/**
* Transform current state using an updater function and emit the new state
* @param updater - Function that receives current state and returns new state
*/
update(updater: (current: S) => S): void;
/**
* Merge partial state changes into current state (only for object states)
*/
patch: S extends object ? (partial: Partial<S>) => void : never;
}
/**
* Manages subscriptions to state container dependencies.
* Provides efficient sync mechanism to add/remove subscriptions
* as dependencies change between callback invocations.
*/
export declare class DependencyManager {
private subscriptions;
private currentDeps;
/**
* Sync subscriptions with a new set of dependencies.
* Adds subscriptions for new deps, removes subscriptions for stale deps.
*
* @param newDeps - The new set of dependencies to subscribe to
* @param onChange - Callback to invoke when any dependency changes
* @param exclude - Optional instance to exclude from subscriptions (e.g., primary bloc)
* @returns true if the dependency set changed, false if unchanged
*/
sync(newDeps: Set<StateContainerInstance>, onChange: () => void, exclude?: StateContainerInstance): boolean;
/**
* Add a single dependency subscription.
*/
add(dep: StateContainerInstance, onChange: () => void): void;
/**
* Check if a dependency is currently subscribed.
*/
has(dep: StateContainerInstance): boolean;
/**
* Get the current set of dependencies.
*/
getDependencies(): Set<StateContainerInstance>;
/**
* Clean up all active subscriptions.
*/
cleanup(): void;
private areSetsEqual;
}
/* Excluded from this release type: DependencyState */
export declare function ensure<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): InstanceType<T>;
/**
* Extract constructor argument types from a class
* @template T - The class type
*/
export declare type ExtractConstructorArgs<T> = T extends new (...args: infer P) => any ? P : never[];
declare type ExtractInstance<T> = T extends BlocRef<infer C> ? InstanceType<C> : T extends StateContainerConstructor ? InstanceType<T> : never;
declare type ExtractInstances<T extends readonly BlocInput[]> = {
[K in keyof T]: ExtractInstance<T[K]>;
};
/**
* Extract the state type from a StateContainer
* @template T - The StateContainer type
*/
export declare type ExtractState<T> = T extends StateContainerConstructor<infer S> ? Readonly<S> : never;
export declare type ExtractStateMutable<T> = T extends StateContainerConstructor<infer S> ? S : never;
export declare function forEach<T extends StateContainerConstructor>(BlocClass: T, callback: (instance: InstanceReadonlyState<T>) => void): void;
/**
* Generate a unique isolated instance key
* Uses base36 encoding for compact, URL-safe identifiers
*
* Format: "isolated-{9-char-random-string}"
* Example: "isolated-k7x2m9p4q"
*
* @returns A unique isolated instance key
*/
export declare function generateIsolatedKey(): string;
export declare function getAll<T extends StateContainerConstructor>(BlocClass: T): InstanceReadonlyState<T>[];
/**
* Get the global plugin manager
*/
export declare function getPluginManager(): any;
export declare function getRefCount<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): number;
/* Excluded from this release type: GetterState */
/**
* Global default registry instance
*/
export declare const globalRegistry: StateContainerRegistry;
/* Excluded from this release type: hasDependencyChanges */
/* Excluded from this release type: hasGetterChanges */
export declare function hasInstance<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string): boolean;
/* Excluded from this release type: hasTrackedData */
/**
* Create a reference to a specific bloc instance.
*
* @example
* ```ts
* watch(instance(UserBloc, 'user-123'), (userBloc) => {
* console.log(userBloc.state.name);
* });
* ```
*/
export declare function instance<T extends StateContainerConstructor>(BlocClass: T, instanceId: string): BlocRef<T>;
/**
* Entry in the instance registry, tracking the instance and its reference count
* @template T - Instance type
*/
export declare interface InstanceEntry<T = any> {
/** The state container instance */
instance: T;
/** Number of active references to this instance */
refCount: number;
}
/**
* Metadata information about a state container instance for debugging and inspection
*/
export declare interface InstanceMetadata {
/** Unique instance identifier */
id: string;
/** Name of the state container class */
className: string;
/** Whether the instance has been disposed */
isDisposed: boolean;
/** Display name for the instance */
name: string;
/** When state last changed (milliseconds) */
lastStateChangeTimestamp: number;
/** Current state value */
state: any;
/** Timestamp when instance was created (milliseconds) */
createdAt: number;
/** Whether this is an isolated (component-scoped) instance */
isIsolated: boolean;
/** Stack trace from when instance was created (for debugging) */
callstack?: string;
/** Previous state value */
previousState?: any;
/** Current state value */
currentState?: any;
}
export declare type InstanceReadonlyState<T extends StateContainerConstructor = any> = Omit<InstanceType<T>, 'state'> & {
state: ExtractState<T>;
};
export declare type InstanceState<T extends StateContainerConstructor = any> = Omit<InstanceType<T>, 'state'> & {
state: ExtractStateMutable<T>;
};
/* Excluded from this release type: invalidateRenderCache */
/**
* Check if a class is marked as isolated.
* Isolated classes create separate instances per component.
* @param Type - The class constructor to check
* @returns true if the class has `static isolated = true`
*/
export declare function isIsolatedClass<T extends StateContainerConstructor>(Type: T): boolean;
/**
* Lifecycle events emitted by the registry
*/
export declare type LifecycleEvent = 'created' | 'stateChanged' | 'disposed';
/**
* Listener function type for each lifecycle event
* @template E - The lifecycle event type
*/
export declare type LifecycleListener<E extends LifecycleEvent> = E extends 'created' ? (container: StateContainer<any>) => void : E extends 'stateChanged' ? (container: StateContainer<any>, previousState: any, currentState: any, callstack?: string) => void : E extends 'disposed' ? (container: StateContainer<any>) => void : never;
/* Excluded from this release type: PathInfo */
/**
* Configuration options for plugin installation
*/
export declare interface PluginConfig {
/** Enable or disable the plugin */
enabled?: boolean;
/** Environments where plugin runs */
environment?: 'development' | 'production' | 'test' | 'all';
}
/**
* Safe context API provided to plugins for accessing registry data
*/
export declare interface PluginContext {
/**
* Get metadata for a specific instance
*/
getInstanceMetadata(instance: StateContainer<any>): InstanceMetadata;
/**
* Get current state from a container
*/
getState<S extends object = any>(instance: StateContainer<S>): S;
/**
* Get all instances of a specific type
*/
queryInstances<T extends StateContainer<any>>(typeClass: new (...args: any[]) => T): T[];
/**
* Get all registered state container types
*/
getAllTypes(): Array<new (...args: any[]) => StateContainer<any>>;
/**
* Get registry statistics
*/
getStats(): {
registeredTypes: number;
totalInstances: number;
typeBreakdown: Record<string, number>;
};
}
/**
* Manages plugin lifecycle for the BlaC state management system.
* Plugins receive notifications about state container lifecycle events.
*
* @example
* ```ts
* const manager = createPluginManager(registry);
* manager.install(myPlugin, { environment: 'development' });
* ```
*/
export declare class PluginManager {
private plugins;
private registry;
/**
* Create a new PluginManager
* @param registry - The StateContainerRegistry to monitor for lifecycle events
*/
constructor(registry: StateContainerRegistry);
/**
* Install a plugin with optional configuration
* @param plugin - The plugin to install
* @param config - Optional plugin configuration
* @throws Error if plugin is already installed
*/
install(plugin: BlacPlugin, config?: PluginConfig): void;
/**
* Uninstall a plugin by name
* @param pluginName - The name of the plugin to uninstall
* @throws Error if plugin is not installed
*/
uninstall(pluginName: string): void;
/**
* Get an installed plugin by name
* @param pluginName - The name of the plugin to retrieve
* @returns The plugin instance or undefined if not found
*/
getPlugin(pluginName: string): BlacPlugin | undefined;
/**
* Get all installed plugins
* @returns Array of all installed plugins
*/
getAllPlugins(): BlacPlugin[];
/**
* Check if a plugin is installed
* @param pluginName - The name of the plugin to check
* @returns true if the plugin is installed
*/
hasPlugin(pluginName: string): boolean;
/**
* Uninstall all plugins
*/
clear(): void;
/**
* Setup lifecycle hooks to notify plugins
*/
private setupLifecycleHooks;
/**
* Notify all plugins of a lifecycle event
*/
private notifyPlugins;
/**
* Create plugin context with safe API access
*/
private createPluginContext;
/**
* Check if plugin should be enabled based on environment
*/
private shouldEnablePlugin;
/**
* Get current environment
*/
private getCurrentEnvironment;
}
/* Excluded from this release type: ProxyState */
export declare function release<T extends StateContainerConstructor>(BlocClass: T, instanceKey?: string, forceDispose?: boolean): void;
/* Excluded from this release type: resolveDependencies */
/* Excluded from this release type: setActiveTracker */
/* Excluded from this release type: shallowEqual */
/* Excluded from this release type: startDependency */
/**
* Abstract base class for all state containers in BlaC.
* Provides lifecycle management, subscription handling, ref counting,
* and integration with the global registry.
*
* @template S - State type managed by this container
*
* @example
* ```ts
* class CounterBloc extends StateContainer<{ count: number }> {
* constructor() {
* super({ count: 0 });
* }
* increment() {
* this.emit({ count: this.state.count + 1 });
* }
* }
* ```
*/
export declare abstract class StateContainer<S extends object = any> {
static __excludeFromDevTools: boolean;
static enableStackTrace: boolean;
private _state;
private readonly listeners;
private _disposed;
private config;
private readonly systemEventHandlers;
/** Display name for this instance */
name: string;
/** Whether debug logging is enabled */
debug: boolean;
/** Unique identifier for this instance */
instanceId: string;
/** Timestamp when this instance was created */
createdAt: number;
private _dependencies;
get dependencies(): ReadonlyMap<StateContainerConstructor, string>;
protected depend<T extends StateContainerConstructor>(Type: T, instanceKey?: string): () => InstanceType<T>;
constructor(initialState: S);
/**
* Initialize configuration for this instance.
* Called by the registry after construction.
* @param config - Configuration options
*/
initConfig(config: StateContainerConfig): void;
/** Current state value */
get state(): Readonly<S>;
/** Whether this instance has been disposed */
get isDisposed(): boolean;
/**
* Subscribe to state changes
* @param listener - Function called when state changes
* @returns Unsubscribe function
*/
subscribe(listener: StateListener<S>): () => void;
/**
* Dispose this instance and clean up resources.
* Clears all listeners and emits the 'dispose' system event.
*/
dispose(): void;
/**
* Emit a new state value and notify all listeners.
* @param newState - The new state value
* @protected
*/
protected emit(newState: S): void;
private captureStackTrace;
private formatStackLine;
private cleanFilePath;
/** Timestamp of the last state update */
lastUpdateTimestamp: number;
/**
* Update state using a transform function.
* @param updater - Function that receives current state and returns new state
* @protected
*/
protected update(updater: (current: S) => S): void;
/**
* Subscribe to system lifecycle events.
* @param event - The event type to listen for
* @param handler - Handler function called when event occurs
* @returns Unsubscribe function
* @protected
*/
protected onSystemEvent: <E extends SystemEvent>(event: E, handler: SystemEventHandler<S, E>) => (() => void);
private emitSystemEvent;
}
/**
* Configuration options for initializing a StateContainer instance
*/
export declare interface StateContainerConfig {
/** Display name for the instance (defaults to class name) */
name?: string;
/** Enable debug logging for this instance */
debug?: boolean;
/** Custom instance identifier */
instanceId?: string;
}
/**
* Constructor type for StateContainer classes
* @template S - State type managed by the container
*/
export declare type StateContainerConstructor<S extends object = any> = new (...args: any[]) => StateContainer<S>;
export declare type StateContainerInstance<S extends object = any> = Omit<StateContainer<S>, 'state'> & {
state: Readonly<S>;
};
/**
* Central registry for managing StateContainer instances.
* Handles instance lifecycle, ref counting, and lifecycle event emission.
*
* @example
* ```ts
* const registry = new StateContainerRegistry();
* const instance = registry.acquire(MyBloc); // ownership, must release
* const other = registry.ensure(OtherBloc); // no ownership, bloc-to-bloc
* registry.on('stateChanged', (container, prev, next) => {
* console.log('State changed:', prev, '->', next);
* });
* ```
*/
declare class StateContainerRegistry {
private readonly instancesByConstructor;
private readonly types;
private readonly typeConfigs;
private readonly listeners;
/**
* Register a type for lifecycle event tracking
* @param constructor - The StateContainer class constructor
*/
registerType<T extends StateContainerConstructor>(constructor: T): void;
/**
* Register a StateContainer class with configuration
* @param constructor - The StateContainer class constructor
* @param isolated - Whether instances should be isolated (component-scoped)
* @throws Error if type is already registered
*/
register<T extends StateContainerConstructor>(constructor: T, isolated?: boolean): void;
private ensureInstancesMap;
/**
* Get the instances Map for a specific class (public API for stats/debugging)
*/
getInstancesMap<T extends StateContainerConstructor>(Type: T): Map<string, InstanceEntry>;
/**
* Acquire an instance with ref counting (ownership semantics).
* Creates a new instance if one doesn't exist, or returns existing and increments ref count.
* You must call `release()` when done to decrement the ref count.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param options - Acquisition options
* @param options.canCreate - Whether to create new instance if not found (default: true)
* @param options.countRef - Whether to increment ref count (default: true)
* @returns The state container instance
*/
acquire<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string, options?: {
canCreate?: boolean;
countRef?: boolean;
}): InstanceType<T>;
/**
* Borrow an existing instance without incrementing ref count (borrowing semantics).
* Tracks cross-bloc dependency for reactive updates.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
* @throws Error if instance doesn't exist
*/
borrow<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): InstanceType<T>;
/**
* Safely borrow an existing instance (borrowing semantics with error handling).
* Returns discriminated union for type-safe conditional access.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Discriminated union with either the instance or an error
*/
borrowSafe<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): {
error: Error;
instance: null;
} | {
error: null;
instance: InstanceType<T>;
};
/**
* Ensure an instance exists without taking ownership (for bloc-to-bloc communication).
* Gets existing instance OR creates it if it doesn't exist, without incrementing ref count.
* Tracks cross-bloc dependency for reactive updates.
*
* Use this in bloc-to-bloc communication when you need to ensure an instance exists
* but don't want to claim ownership (no ref count increment).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
*/
ensure<T extends StateContainerConstructor = StateContainerConstructor>(Type: T, instanceKey?: string): InstanceType<T>;
/**
* Release a reference to an instance.
* Decrements ref count and disposes when it reaches 0 (unless keepAlive).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param forceDispose - Force immediate disposal regardless of ref count
*/
release<T extends StateContainerConstructor>(Type: T, instanceKey?: string, forceDispose?: boolean): void;
/**
* Get all instances of a specific type.
* @param Type - The StateContainer class constructor
* @returns Array of all instances
*/
getAll<T extends StateContainerConstructor>(Type: T): InstanceReadonlyState<T>[];
/**
* Safely iterate over all instances of a type.
* Skips disposed instances and catches callback errors.
* @param Type - The StateContainer class constructor
* @param callback - Function to call for each instance
*/
forEach<T extends StateContainerConstructor>(Type: T, callback: (instance: InstanceReadonlyState<T>) => void): void;
/**
* Clear all instances of a specific type (disposes them).
* @param Type - The StateContainer class constructor
*/
clear<T extends StateContainerConstructor>(Type: T): void;
/**
* Get reference count for an instance.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Current ref count (0 if instance doesn't exist)
*/
getRefCount<T extends StateContainerConstructor>(Type: T, instanceKey?: string): number;
/**
* Check if an instance exists.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns true if instance exists
*/
hasInstance<T extends StateContainerConstructor>(Type: T, instanceKey?: string): boolean;
/**
* Clear all instances from all types (for testing)
*
* Iterates all registered types and clears their instances.
* Also clears type tracking to reset the registry state.
*/
clearAll(): void;
/**
* Get registry statistics for debugging.
* @returns Object with registeredTypes, totalInstances, and typeBreakdown
*/
getStats(): {
registeredTypes: number;
totalInstances: number;
typeBreakdown: Record<string, number>;
};
/**
* Get all registered types (for plugin system).
* @returns Array of all registered StateContainer class constructors
*/
getTypes(): StateContainerConstructor[];
/**
* Subscribe to lifecycle events
* @param event - The lifecycle event to listen for
* @param listener - The listener function to call when the event occurs
* @returns Unsubscribe function
*/
on<E extends LifecycleEvent>(event: E, listener: LifecycleListener<E>): () => void;
/* Excluded from this release type: emit */
}
/* Excluded from this release type: StateListener */
declare const STOP: unique symbol;
declare type StopSymbol = typeof STOP;
/**
* System events emitted by StateContainer lifecycle
*/
export declare type SystemEvent = 'stateChanged' | 'dispose';
/* Excluded from this release type: SystemEventHandler */
/**
* Payload types for each system event
* @template S - State type
*/
export declare interface SystemEventPayloads<S> {
/** Emitted when state changes via emit() or update() */
stateChanged: {
state: S;
previousState: S;
};
/** Emitted when the instance is disposed */
dispose: void;
}
export declare const watch: WatchFn;
/**
* Combined watch function type.
*/
export declare interface WatchFn extends WatchSingleFn {
<T extends readonly BlocInput[]>(blocs: T, callback: (blocs: ExtractInstances<T>) => void | StopSymbol): () => void;
}
/**
* Watch function signature for single bloc.
*/
declare interface WatchSingleFn {
<T extends StateContainerConstructor>(bloc: T | BlocRef<T>, callback: (bloc: InstanceType<T>) => void | StopSymbol): () => void;
STOP: StopSymbol;
}
export { }
export { StateContainer } from './core/StateContainer';
export type { StateContainerConfig, SystemEvent, SystemEventPayloads, } from './core/StateContainer';
export { Cubit } from './core/Cubit';
export { acquire, borrow, borrowSafe, ensure, release, clear, clearAll, register, hasInstance, getRefCount, getAll, forEach, getRegistry, setRegistry, getStats, } from './registry';
export { globalRegistry } from './core/StateContainerRegistry';
export type { LifecycleEvent, LifecycleListener, InstanceEntry, } from './core/StateContainerRegistry';
export { blac, type BlacOptions } from './decorators';
export { getPluginManager } from './core/StateContainerRegistry';
export type { BlacPlugin, BlacPluginWithInit, PluginContext, PluginConfig, InstanceMetadata, } from './plugin/BlacPlugin';
export { PluginManager } from './plugin/PluginManager';
export { watch, instance, type WatchFn, type BlocRef } from './watch';
export { tracked, createTrackedContext, TrackedContext, type TrackedResult, type TrackedOptions, } from './tracking/tracked';
export type { StateContainerConstructor, ExtractState, ExtractStateMutable, ExtractConstructorArgs, BlocInstanceType, BlocConstructor, InstanceReadonlyState, InstanceState, StateContainerInstance, } from './types/utilities';
export type { Brand, BrandedId, InstanceId } from './types/branded';
export { instanceId } from './types/branded';
export * from './tracking';
export { isIsolatedClass } from './utils/static-props';
export { generateIsolatedKey } from './utils/idGenerator';

@@ -1,7 +0,1 @@

import { i as BLAC_DEFAULTS, n as globalRegistry, o as BLAC_STATIC_PROPS, r as isIsolatedClass, s as PluginManager, t as getPluginManager } from "./StateContainerRegistry.js";
import { a as getAll, i as forEach, n as clearAll, o as getRefCount, s as hasInstance, t as clear } from "./management.js";
import { n as watch, r as ensure, t as instance } from "./watch.js";
import { _ as setActiveTracker, a as commitTrackedGetters, c as createDependencyState, g as invalidateRenderCache, h as hasTrackedData, i as clearActiveTracker, l as createGetterState, m as hasGetterChanges, n as DependencyManager, o as createBlocProxy, p as hasDependencyChanges, r as capturePaths, s as createDependencyProxy, t as resolveDependencies, v as startDependency, x as shallowEqual } from "./resolve-dependencies.js";
import "./tracking.js";
//#region src/utils/idGenerator.ts

@@ -40,2 +34,569 @@ /**

//#endregion
//#region src/constants.ts
/**
* Default configuration constants for BlaC
*
* Centralized location for all magic numbers and default values.
*/
/**
* Default configuration constants for BlaC
*/
const BLAC_DEFAULTS = {
DEFAULT_INSTANCE_KEY: "default",
MAX_GETTER_DEPTH: 10,
CLEANUP_INTERVAL_MS: 3e4,
WEAKREF_CLEANUP_INTERVAL_MS: 1e4,
MAX_SUBSCRIPTIONS: 1e3,
MAX_SUBSCRIPTIONS_HIGH_PERF: 1e4,
PIPELINE_TIMEOUT_MS: 5e3,
CLEANUP_INTERVAL_HIGH_PERF_MS: 5e3,
MAX_PIPELINE_STAGES: 30
};
/**
* Static property names for StateContainer classes
* Used for feature flags and configuration on bloc classes
*/
const BLAC_STATIC_PROPS = {
ISOLATED: "isolated",
KEEP_ALIVE: "keepAlive",
EXCLUDE_FROM_DEVTOOLS: "__excludeFromDevTools"
};
/**
* Standard error message prefix
*/
const BLAC_ERROR_PREFIX = "[BlaC]";
//#endregion
//#region src/plugin/PluginManager.ts
/**
* Manages plugin lifecycle for the BlaC state management system.
* Plugins receive notifications about state container lifecycle events.
*
* @example
* ```ts
* const manager = createPluginManager(registry);
* manager.install(myPlugin, { environment: 'development' });
* ```
*/
var PluginManager = class {
/**
* Create a new PluginManager
* @param registry - The StateContainerRegistry to monitor for lifecycle events
*/
constructor(registry) {
this.plugins = /* @__PURE__ */ new Map();
this.registry = registry;
this.setupLifecycleHooks();
}
/**
* Install a plugin with optional configuration
* @param plugin - The plugin to install
* @param config - Optional plugin configuration
* @throws Error if plugin is already installed
*/
install(plugin, config = {}) {
const effectiveConfig = {
enabled: true,
environment: "all",
...config
};
if (!this.shouldEnablePlugin(effectiveConfig)) {
console.log(`[BlaC] Plugin "${plugin.name}" skipped (environment mismatch)`);
return;
}
if (this.plugins.has(plugin.name)) throw new Error(`Plugin "${plugin.name}" is already installed`);
const context = this.createPluginContext();
this.plugins.set(plugin.name, {
plugin,
config: effectiveConfig,
context
});
if (plugin.onInstall) try {
plugin.onInstall(context);
} catch (error) {
console.error(`[BlaC] Error installing plugin "${plugin.name}":`, error);
this.plugins.delete(plugin.name);
throw error;
}
console.log(`[BlaC] Plugin "${plugin.name}" v${plugin.version} installed`);
}
/**
* Uninstall a plugin by name
* @param pluginName - The name of the plugin to uninstall
* @throws Error if plugin is not installed
*/
uninstall(pluginName) {
const installed = this.plugins.get(pluginName);
if (!installed) throw new Error(`Plugin "${pluginName}" is not installed`);
if (installed.plugin.onUninstall) try {
installed.plugin.onUninstall();
} catch (error) {
console.error(`[BlaC] Error uninstalling plugin "${pluginName}":`, error);
}
this.plugins.delete(pluginName);
console.log(`[BlaC] Plugin "${pluginName}" uninstalled`);
}
/**
* Get an installed plugin by name
* @param pluginName - The name of the plugin to retrieve
* @returns The plugin instance or undefined if not found
*/
getPlugin(pluginName) {
return this.plugins.get(pluginName)?.plugin;
}
/**
* Get all installed plugins
* @returns Array of all installed plugins
*/
getAllPlugins() {
return Array.from(this.plugins.values()).map((p) => p.plugin);
}
/**
* Check if a plugin is installed
* @param pluginName - The name of the plugin to check
* @returns true if the plugin is installed
*/
hasPlugin(pluginName) {
return this.plugins.has(pluginName);
}
/**
* Uninstall all plugins
*/
clear() {
for (const name of this.plugins.keys()) this.uninstall(name);
}
/**
* Setup lifecycle hooks to notify plugins
*/
setupLifecycleHooks() {
this.registry.on("created", (instance) => {
this.notifyPlugins("onInstanceCreated", instance);
});
this.registry.on("stateChanged", (instance, previousState, currentState, callstack) => {
this.notifyPlugins("onStateChanged", instance, previousState, currentState, callstack);
});
this.registry.on("disposed", (instance) => {
this.notifyPlugins("onInstanceDisposed", instance);
});
}
/**
* Notify all plugins of a lifecycle event
*/
notifyPlugins(hookName, ...args) {
for (const { plugin, config, context } of this.plugins.values()) {
if (!config.enabled) continue;
const hook = plugin[hookName];
if (typeof hook === "function") try {
hook.apply(plugin, [...args, context]);
} catch (error) {
console.error(`[BlaC] Error in plugin "${plugin.name}" ${hookName}:`, error);
}
}
}
/**
* Create plugin context with safe API access
*/
createPluginContext() {
return {
getInstanceMetadata: (instance) => {
return {
id: instance.instanceId,
className: instance.constructor.name,
isDisposed: instance.isDisposed,
name: instance.name,
lastStateChangeTimestamp: instance.lastUpdateTimestamp,
createdAt: instance.createdAt,
state: instance.state,
isIsolated: instance.instanceId.startsWith("isolated-")
};
},
getState: (instance) => {
return instance.state;
},
queryInstances: (typeClass) => {
return this.registry.getAll(typeClass);
},
getAllTypes: () => {
return this.registry.getTypes();
},
getStats: () => {
return this.registry.getStats();
}
};
}
/**
* Check if plugin should be enabled based on environment
*/
shouldEnablePlugin(config) {
if (!config.enabled) return false;
if (config.environment === "all") return true;
return this.getCurrentEnvironment() === config.environment;
}
/**
* Get current environment
*/
getCurrentEnvironment() {
if (typeof process !== "undefined") {
if (process.env.NODE_ENV === "test") return "test";
if (process.env.NODE_ENV === "production") return "production";
return "development";
}
return "development";
}
};
/**
* Create a plugin manager instance
* @param registry - The StateContainerRegistry to monitor for lifecycle events
* @returns A new PluginManager instance
*/
function createPluginManager(registry) {
return new PluginManager(registry);
}
//#endregion
//#region src/utils/static-props.ts
/**
* Utility functions for accessing static properties on StateContainer classes
*/
/**
* Get a static property from a class constructor
* Type-safe helper that avoids (Type as any) casts
*
* @param Type - The class constructor
* @param propName - The property name to access
* @param defaultValue - Optional default value if property is undefined
* @returns The property value or default
*/
function getStaticProp(Type, propName, defaultValue) {
return Type[propName] ?? defaultValue;
}
/**
* Check if a class is marked as isolated.
* Isolated classes create separate instances per component.
* @param Type - The class constructor to check
* @returns true if the class has `static isolated = true`
*/
function isIsolatedClass(Type) {
return getStaticProp(Type, BLAC_STATIC_PROPS.ISOLATED) === true;
}
/**
* Check if a class is marked as keepAlive.
* KeepAlive classes are never auto-disposed when ref count reaches 0.
* @param Type - The class constructor to check
* @returns true if the class has `static keepAlive = true`
*/
function isKeepAliveClass(Type) {
return getStaticProp(Type, BLAC_STATIC_PROPS.KEEP_ALIVE) === true;
}
//#endregion
//#region src/core/StateContainerRegistry.ts
/**
* Central registry for managing StateContainer instances.
* Handles instance lifecycle, ref counting, and lifecycle event emission.
*
* @example
* ```ts
* const registry = new StateContainerRegistry();
* const instance = registry.acquire(MyBloc); // ownership, must release
* const other = registry.ensure(OtherBloc); // no ownership, bloc-to-bloc
* registry.on('stateChanged', (container, prev, next) => {
* console.log('State changed:', prev, '->', next);
* });
* ```
*/
var StateContainerRegistry = class {
constructor() {
this.instancesByConstructor = /* @__PURE__ */ new WeakMap();
this.types = /* @__PURE__ */ new Set();
this.typeConfigs = /* @__PURE__ */ new Map();
this.listeners = /* @__PURE__ */ new Map();
}
/**
* Register a type for lifecycle event tracking
* @param constructor - The StateContainer class constructor
*/
registerType(constructor) {
this.types.add(constructor);
}
/**
* Register a StateContainer class with configuration
* @param constructor - The StateContainer class constructor
* @param isolated - Whether instances should be isolated (component-scoped)
* @throws Error if type is already registered
*/
register(constructor, isolated = false) {
const className = constructor.name;
if (!isolated && isIsolatedClass(constructor)) isolated = true;
if (this.typeConfigs.has(className)) throw new Error(`${BLAC_ERROR_PREFIX} Type "${className}" is already registered`);
this.typeConfigs.set(className, { isolated });
this.registerType(constructor);
}
ensureInstancesMap(Type) {
let instances = this.instancesByConstructor.get(Type);
if (!instances) {
instances = /* @__PURE__ */ new Map();
this.instancesByConstructor.set(Type, instances);
}
return instances;
}
/**
* Get the instances Map for a specific class (public API for stats/debugging)
*/
getInstancesMap(Type) {
return this.instancesByConstructor.get(Type) || /* @__PURE__ */ new Map();
}
/**
* Acquire an instance with ref counting (ownership semantics).
* Creates a new instance if one doesn't exist, or returns existing and increments ref count.
* You must call `release()` when done to decrement the ref count.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param options - Acquisition options
* @param options.canCreate - Whether to create new instance if not found (default: true)
* @param options.countRef - Whether to increment ref count (default: true)
* @returns The state container instance
*/
acquire(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, options = {}) {
const { canCreate = true, countRef = true } = options;
const registryConfig = this.typeConfigs.get(Type.name);
const isolated = isIsolatedClass(Type) || registryConfig?.isolated === true;
const config = { instanceId: instanceKey };
if (isolated && !canCreate) throw new Error(`${BLAC_ERROR_PREFIX} Cannot get isolated instance "${instanceKey}" of ${Type.name} when creation is disabled.`);
if (isolated) {
const instance = new Type();
instance.initConfig(config);
this.registerType(Type);
return instance;
}
const instances = this.ensureInstancesMap(Type);
let entry = instances.get(instanceKey);
if (entry?.instance.isDisposed) {
instances.delete(instanceKey);
entry = void 0;
}
if (entry && countRef) entry.refCount++;
if (entry) return entry.instance;
if (!canCreate) throw new Error(`${BLAC_ERROR_PREFIX} ${Type.name} instance "${instanceKey}" not found and creation is disabled.`);
const instance = new Type();
instance.initConfig(config);
instances.set(instanceKey, {
instance,
refCount: 1
});
this.registerType(Type);
return instance;
}
/**
* Borrow an existing instance without incrementing ref count (borrowing semantics).
* Tracks cross-bloc dependency for reactive updates.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
* @throws Error if instance doesn't exist
*/
borrow(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
return this.acquire(Type, instanceKey, {
canCreate: false,
countRef: false
});
}
/**
* Safely borrow an existing instance (borrowing semantics with error handling).
* Returns discriminated union for type-safe conditional access.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Discriminated union with either the instance or an error
*/
borrowSafe(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
try {
return {
error: null,
instance: this.borrow(Type, instanceKey)
};
} catch (error) {
return {
error,
instance: null
};
}
}
/**
* Ensure an instance exists without taking ownership (for bloc-to-bloc communication).
* Gets existing instance OR creates it if it doesn't exist, without incrementing ref count.
* Tracks cross-bloc dependency for reactive updates.
*
* Use this in bloc-to-bloc communication when you need to ensure an instance exists
* but don't want to claim ownership (no ref count increment).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns The state container instance
*/
ensure(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
return this.acquire(Type, instanceKey, {
canCreate: true,
countRef: false
});
}
/**
* Release a reference to an instance.
* Decrements ref count and disposes when it reaches 0 (unless keepAlive).
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @param forceDispose - Force immediate disposal regardless of ref count
*/
release(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY, forceDispose = false) {
const instances = this.ensureInstancesMap(Type);
const entry = instances.get(instanceKey);
if (!entry) return;
if (forceDispose) {
if (!entry.instance.isDisposed) entry.instance.dispose();
instances.delete(instanceKey);
return;
}
entry.refCount--;
const keepAlive = isKeepAliveClass(Type);
if (entry.refCount <= 0 && !keepAlive) {
if (!entry.instance.isDisposed) entry.instance.dispose();
instances.delete(instanceKey);
}
}
/**
* Get all instances of a specific type.
* @param Type - The StateContainer class constructor
* @returns Array of all instances
*/
getAll(Type) {
const instances = this.ensureInstancesMap(Type);
const result = [];
for (const entry of instances.values()) result.push(entry.instance);
return result;
}
/**
* Safely iterate over all instances of a type.
* Skips disposed instances and catches callback errors.
* @param Type - The StateContainer class constructor
* @param callback - Function to call for each instance
*/
forEach(Type, callback) {
const instances = this.ensureInstancesMap(Type);
for (const entry of instances.values()) {
const instance = entry.instance;
if (!instance.isDisposed) try {
callback(instance);
} catch (error) {
console.error(`${BLAC_ERROR_PREFIX} forEach callback error for ${Type.name}:`, error);
}
}
}
/**
* Clear all instances of a specific type (disposes them).
* @param Type - The StateContainer class constructor
*/
clear(Type) {
const instances = this.ensureInstancesMap(Type);
for (const entry of instances.values()) if (!entry.instance.isDisposed) entry.instance.dispose();
instances.clear();
}
/**
* Get reference count for an instance.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns Current ref count (0 if instance doesn't exist)
*/
getRefCount(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
return this.ensureInstancesMap(Type).get(instanceKey)?.refCount ?? 0;
}
/**
* Check if an instance exists.
* @param Type - The StateContainer class constructor
* @param instanceKey - Instance key (defaults to 'default')
* @returns true if instance exists
*/
hasInstance(Type, instanceKey = BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY) {
return this.ensureInstancesMap(Type).has(instanceKey);
}
/**
* Clear all instances from all types (for testing)
*
* Iterates all registered types and clears their instances.
* Also clears type tracking to reset the registry state.
*/
clearAll() {
for (const Type of this.types) this.clear(Type);
this.types.clear();
this.typeConfigs.clear();
}
/**
* Get registry statistics for debugging.
* @returns Object with registeredTypes, totalInstances, and typeBreakdown
*/
getStats() {
const typeBreakdown = {};
let totalInstances = 0;
for (const Type of this.types) {
const typeName = Type.name;
const count = this.getInstancesMap(Type).size;
typeBreakdown[typeName] = count;
totalInstances += count;
}
return {
registeredTypes: this.types.size,
totalInstances,
typeBreakdown
};
}
/**
* Get all registered types (for plugin system).
* @returns Array of all registered StateContainer class constructors
*/
getTypes() {
return Array.from(this.types);
}
/**
* Subscribe to lifecycle events
* @param event - The lifecycle event to listen for
* @param listener - The listener function to call when the event occurs
* @returns Unsubscribe function
*/
on(event, listener) {
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
const instance = this.listeners.get(event);
if (!instance) throw new Error(`${BLAC_ERROR_PREFIX} Failed to register listener for event '${event}'`);
instance.add(listener);
return () => {
this.listeners.get(event)?.delete(listener);
};
}
/**
* Emit lifecycle event to all listeners
* @internal - Called by StateContainer lifecycle methods
*/
emit(event, ...args) {
const listeners = this.listeners.get(event);
if (!listeners || listeners.size === 0) return;
for (const listener of listeners) try {
listener(...args);
} catch (error) {
console.error(`${BLAC_ERROR_PREFIX} Listener error for '${event}':`, error);
}
}
};
/**
* Global default registry instance
*/
const globalRegistry = new StateContainerRegistry();
/**
* Global plugin manager (initialized lazily)
*/
let _globalPluginManager = null;
/**
* Get the global plugin manager
*/
function getPluginManager() {
if (!_globalPluginManager) _globalPluginManager = createPluginManager(globalRegistry);
return _globalPluginManager;
}
//#endregion
//#region src/core/StateContainer.ts

@@ -239,4 +800,10 @@ const EMPTY_DEPS = /* @__PURE__ */ new Map();

if (typeof this.state !== "object" || this.state === null) throw new Error("patch() is only available for object state types");
this.update((current) => ({
...current,
const current = this.state;
let hasChanges = false;
for (const key in partial) if (!Object.is(current[key], partial[key])) {
hasChanges = true;
break;
}
if (hasChanges) this.update((c) => ({
...c,
...partial

@@ -281,2 +848,8 @@ }));

//#endregion
//#region src/registry/ensure.ts
function ensure(BlocClass, instanceKey) {
return globalRegistry.ensure(BlocClass, instanceKey);
}
//#endregion
//#region src/registry/release.ts

@@ -288,2 +861,43 @@ function release(BlocClass, instanceKey, forceDispose = false) {

//#endregion
//#region src/registry/queries.ts
function hasInstance(BlocClass, instanceKey) {
return globalRegistry.hasInstance(BlocClass, instanceKey);
}
function getRefCount(BlocClass, instanceKey) {
return globalRegistry.getRefCount(BlocClass, instanceKey);
}
function getAll(BlocClass) {
return globalRegistry.getAll(BlocClass);
}
function forEach(BlocClass, callback) {
globalRegistry.forEach(BlocClass, callback);
}
//#endregion
//#region src/registry/management.ts
function clear(BlocClass) {
globalRegistry.clear(BlocClass);
}
function clearAll() {
globalRegistry.clearAll();
}
function register(BlocClass, isolated = false) {
globalRegistry.register(BlocClass, isolated);
}
//#endregion
//#region src/registry/config.ts
let _registry = globalRegistry;
function getRegistry() {
return _registry;
}
function setRegistry(registry) {
_registry.clearAll();
_registry = registry;
}
function getStats() {
return _registry.getStats();
}
//#endregion
//#region src/decorators/blac.ts

@@ -322,3 +936,833 @@ /**

//#endregion
export { Cubit, DependencyManager, PluginManager, StateContainer, acquire, blac, borrow, borrowSafe, capturePaths, clear, clearActiveTracker, clearAll, commitTrackedGetters, createBlocProxy, createDependencyProxy, createDependencyState, createGetterState, ensure, forEach, generateIsolatedKey, getAll, getPluginManager, getRefCount, globalRegistry, hasDependencyChanges, hasGetterChanges, hasInstance, hasTrackedData, instance, invalidateRenderCache, isIsolatedClass, release, resolveDependencies, setActiveTracker, shallowEqual, startDependency, watch };
//#region src/tracking/path-utils.ts
/**
* Path utilities for dependency tracking
*
* Provides utilities for parsing property paths and extracting values
* from nested objects using path strings.
*
* @internal
*/
/**
* Parse a property path string into an array of segments
*
* @internal
*
* Handles both dot notation (a.b.c) and bracket notation (a[0].b)
*
* @example
* ```ts
* parsePath('user.name') // ['user', 'name']
* parsePath('items[0].name') // ['items', '0', 'name']
* parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']
* ```
*/
function parsePath(path) {
const segments = [];
let current = "";
let i = 0;
while (i < path.length) {
const char = path[i];
if (char === ".") {
if (current) segments.push(current);
current = "";
} else if (char === "[") {
if (current) segments.push(current);
current = "";
i++;
while (i < path.length && path[i] !== "]") current += path[i++];
if (current) segments.push(current);
current = "";
} else current += char;
i++;
}
if (current) segments.push(current);
return segments;
}
/**
* Get a value from an object using a path of segments
*
* @example
* ```ts
* const obj = { user: { name: 'Alice', age: 30 } }
* getValueAtPath(obj, ['user', 'name']) // 'Alice'
* getValueAtPath(obj, ['user', 'age']) // 30
* getValueAtPath(obj, ['user', 'missing']) // undefined
* ```
*
* @internal
*/
function getValueAtPath(obj, segments) {
if (obj == null) return void 0;
let current = obj;
for (let i = 0; i < segments.length; i++) {
current = current[segments[i]];
if (current == null) return void 0;
}
return current;
}
/**
* Shallow equality comparison for arrays
*
* Compares two arrays element-by-element using Object.is
*
* @example
* ```ts
* shallowEqual([1, 2, 3], [1, 2, 3]) // true
* shallowEqual([1, 2, 3], [1, 2, 4]) // false
* shallowEqual([1, 2], [1, 2, 3]) // false
* ```
*
* @internal
*/
function shallowEqual(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
for (let i = 0; i < arr1.length; i++) if (!Object.is(arr1[i], arr2[i])) return false;
return true;
}
//#endregion
//#region src/tracking/tracking-proxy.ts
/**
* Consolidated Tracking System
*
* This module provides all dependency and getter tracking functionality:
* - Proxy creation for automatic property access tracking
* - Dependency path tracking and change detection
* - Getter execution tracking for computed properties
* - Combined tracking proxy for watch/waitUntil use cases
*/
/**
* Check if a value can be proxied
* Returns true for plain objects and arrays only.
* @internal
*/
function isProxyable(value) {
if (typeof value !== "object" || value === null) return false;
const proto = Object.getPrototypeOf(value);
return proto === Object.prototype || proto === Array.prototype;
}
/**
* Create a new proxy tracker state
* @internal
*/
function createProxyState() {
return {
trackedPaths: /* @__PURE__ */ new Set(),
isTracking: false,
proxyCache: /* @__PURE__ */ new WeakMap(),
boundFunctionsCache: null,
lastProxiedState: null,
lastProxy: null,
maxDepth: 10
};
}
/**
* Start tracking property accesses
* @internal
*/
function startProxy(state) {
state.isTracking = true;
state.trackedPaths.clear();
}
/**
* Stop tracking and return the tracked paths
* @internal
*/
function stopProxy(state) {
state.isTracking = false;
return new Set(state.trackedPaths);
}
/**
* Create a proxy for an array with property access tracking
* @internal
*/
function createArrayProxy(state, target, path, depth = 0) {
const proxy = new Proxy(target, { get: (arr, prop) => {
if (typeof prop === "symbol") return Reflect.get(arr, prop);
const value = Reflect.get(arr, prop);
if (typeof value === "function") {
if (!state.boundFunctionsCache) state.boundFunctionsCache = /* @__PURE__ */ new WeakMap();
const cached = state.boundFunctionsCache.get(value);
if (cached) return cached;
const bound = value.bind(arr);
state.boundFunctionsCache.set(value, bound);
return bound;
}
if (prop === "length") {
if (state.isTracking) {
const fullPath = path ? `${path}.length` : "length";
state.trackedPaths.add(fullPath);
}
return value;
}
let fullPath;
if (typeof prop === "string") {
const index = Number(prop);
if (!isNaN(index) && index >= 0) fullPath = path ? `${path}[${index}]` : `[${index}]`;
else fullPath = path ? `${path}.${prop}` : prop;
} else return value;
if (isProxyable(value)) return createInternal(state, value, fullPath, depth + 1);
if (state.isTracking) state.trackedPaths.add(fullPath);
return value;
} });
state.proxyCache.set(target, proxy);
return proxy;
}
/**
* Create a proxy for an object with property access tracking
* @internal
*/
function createInternal(state, target, path = "", depth = 0) {
if (!state.isTracking || !isProxyable(target)) return target;
if (depth >= state.maxDepth) return target;
if (state.proxyCache.has(target)) return state.proxyCache.get(target);
if (Array.isArray(target)) return createArrayProxy(state, target, path, depth);
const proxy = new Proxy(target, {
get: (obj, prop) => {
if (typeof prop === "symbol") return Reflect.get(obj, prop);
const value = Reflect.get(obj, prop);
if (typeof value === "function") {
if (!state.boundFunctionsCache) state.boundFunctionsCache = /* @__PURE__ */ new WeakMap();
const cached = state.boundFunctionsCache.get(value);
if (cached) return cached;
const bound = value.bind(obj);
state.boundFunctionsCache.set(value, bound);
return bound;
}
const fullPath = path ? `${path}.${String(prop)}` : String(prop);
if (typeof prop === "string" && state.isTracking) {
if (!prop.startsWith("_") && !prop.startsWith("$$")) state.trackedPaths.add(fullPath);
}
if (isProxyable(value)) return createInternal(state, value, fullPath, depth + 1);
return value;
},
has: (obj, prop) => {
if (typeof prop === "string" && state.isTracking) {
const fullPath = path ? `${path}.${prop}` : prop;
state.trackedPaths.add(fullPath);
}
return Reflect.has(obj, prop);
},
ownKeys: (obj) => {
if (state.isTracking && path) state.trackedPaths.add(path);
return Reflect.ownKeys(obj);
}
});
state.proxyCache.set(target, proxy);
return proxy;
}
/**
* Create a proxy for a target with caching
* @internal
*/
function createForTarget(state, target) {
if (state.lastProxiedState === target && state.lastProxy) return state.lastProxy;
state.proxyCache = /* @__PURE__ */ new WeakMap();
state.boundFunctionsCache = null;
const proxy = createInternal(state, target, "", 0);
state.lastProxiedState = target;
state.lastProxy = proxy;
return proxy;
}
function isChildPath(child, parent) {
if (child === parent) return false;
return child.startsWith(parent + ".") || child.startsWith(parent + "[");
}
function getArrayParentPath(path) {
if (path.endsWith(".length")) return path.slice(0, -7);
const arrayIndexMatch = path.match(/^(.+?)\[\d+\]/);
if (arrayIndexMatch) return arrayIndexMatch[1];
return null;
}
/**
* @internal
*/
function optimizeTrackedPaths(paths) {
if (paths.size === 0) return /* @__PURE__ */ new Set();
if (paths.size === 1) return new Set(paths);
const sortedPaths = Array.from(paths).sort((a, b) => b.length - a.length);
const optimized = /* @__PURE__ */ new Set();
for (const path of sortedPaths) {
let hasMoreSpecificChild = false;
for (const optimizedPath of optimized) if (isChildPath(optimizedPath, path)) {
hasMoreSpecificChild = true;
break;
}
if (!hasMoreSpecificChild) optimized.add(path);
}
const arrayParents = /* @__PURE__ */ new Set();
for (const path of optimized) {
const arrayParent = getArrayParentPath(path);
if (arrayParent) arrayParents.add(arrayParent);
}
for (const arrayParent of arrayParents) optimized.add(arrayParent);
return optimized;
}
/**
* @internal
*/
function createDependencyState() {
return {
proxyState: createProxyState(),
previousRenderPaths: /* @__PURE__ */ new Set(),
currentRenderPaths: /* @__PURE__ */ new Set(),
pathCache: /* @__PURE__ */ new Map(),
lastCheckedState: null,
lastCheckedValues: /* @__PURE__ */ new Map()
};
}
/**
* @internal
*/
function startDependency(tracker) {
startProxy(tracker.proxyState);
}
/**
* @internal
*/
function createDependencyProxy(tracker, state) {
return createForTarget(tracker.proxyState, state);
}
/**
* @internal
*/
function capturePaths(tracker, state) {
tracker.previousRenderPaths = tracker.currentRenderPaths;
tracker.currentRenderPaths = optimizeTrackedPaths(stopProxy(tracker.proxyState));
if (tracker.previousRenderPaths.size === 0 && tracker.currentRenderPaths.size === 0) return;
const trackedPathsUnion = new Set(tracker.previousRenderPaths);
for (const path of tracker.currentRenderPaths) trackedPathsUnion.add(path);
const canReuseCache = tracker.lastCheckedState === state;
for (const path of trackedPathsUnion) if (!tracker.pathCache.has(path)) {
const segments = parsePath(path);
const value = canReuseCache && tracker.lastCheckedValues.has(path) ? tracker.lastCheckedValues.get(path) : getValueAtPath(state, segments);
tracker.pathCache.set(path, {
segments,
value
});
} else {
const info = tracker.pathCache.get(path);
info.value = canReuseCache && tracker.lastCheckedValues.has(path) ? tracker.lastCheckedValues.get(path) : getValueAtPath(state, info.segments);
}
tracker.lastCheckedValues.clear();
}
/**
* @internal
*/
function hasDependencyChanges(tracker, state) {
if (tracker.pathCache.size === 0) return true;
tracker.lastCheckedValues.clear();
for (const [path, info] of tracker.pathCache.entries()) {
const currentValue = getValueAtPath(state, info.segments);
tracker.lastCheckedValues.set(path, currentValue);
if (!Object.is(currentValue, info.value)) {
tracker.lastCheckedState = state;
return true;
}
}
tracker.lastCheckedState = state;
return false;
}
/**
* @internal
*/
function hasTrackedData(tracker) {
return tracker.proxyState.trackedPaths.size > 0 || tracker.pathCache.size > 0 || tracker.previousRenderPaths.size > 0;
}
const descriptorCache = /* @__PURE__ */ new WeakMap();
const blocProxyCache = /* @__PURE__ */ new WeakMap();
const activeTrackerMap = /* @__PURE__ */ new WeakMap();
const MAX_GETTER_DEPTH = BLAC_DEFAULTS.MAX_GETTER_DEPTH;
/**
* @internal
*/
function getDescriptor(obj, prop) {
const constructor = obj.constructor;
let constructorCache = descriptorCache.get(constructor);
if (constructorCache?.has(prop)) return constructorCache.get(prop);
let current = obj;
let descriptor;
while (current && current !== Object.prototype) {
descriptor = Object.getOwnPropertyDescriptor(current, prop);
if (descriptor) break;
current = Object.getPrototypeOf(current);
}
if (!constructorCache) {
constructorCache = /* @__PURE__ */ new Map();
descriptorCache.set(constructor, constructorCache);
}
constructorCache.set(prop, descriptor);
return descriptor;
}
/**
* @internal
*/
function isGetter(obj, prop) {
return getDescriptor(obj, prop)?.get !== void 0;
}
/**
* @internal
*/
function createGetterState() {
return {
trackedValues: /* @__PURE__ */ new Map(),
currentlyAccessing: /* @__PURE__ */ new Set(),
trackedGetters: /* @__PURE__ */ new Set(),
isTracking: false,
renderCache: /* @__PURE__ */ new Map(),
cacheValid: false,
depth: 0,
visitedBlocs: /* @__PURE__ */ new Set()
};
}
/**
* @internal
*/
function setActiveTracker(bloc, tracker) {
activeTrackerMap.set(bloc, tracker);
}
/**
* @internal
*/
function clearActiveTracker(bloc) {
activeTrackerMap.delete(bloc);
}
/**
* @internal
*/
function commitTrackedGetters(tracker) {
if (tracker.currentlyAccessing.size > 0) tracker.trackedGetters = new Set(tracker.currentlyAccessing);
tracker.currentlyAccessing.clear();
}
/**
* Execute a tracked getter with depth/circular dependency checks and context management.
* @internal
*/
function executeTrackedGetter(target, prop, tracker) {
tracker.currentlyAccessing.add(prop);
if (tracker.cacheValid && tracker.renderCache.has(prop)) {
const cachedValue = tracker.renderCache.get(prop);
tracker.trackedValues.set(prop, cachedValue);
return cachedValue;
}
if (tracker.depth >= MAX_GETTER_DEPTH) {
console.warn(`${BLAC_ERROR_PREFIX} Maximum getter depth (${MAX_GETTER_DEPTH}) exceeded. Possible circular dependency in getter "${String(prop)}" on ${target.constructor.name}.`);
return;
}
if (tracker.visitedBlocs.has(target)) {
console.warn(`${BLAC_ERROR_PREFIX} Circular dependency detected: getter "${String(prop)}" on ${target.constructor.name}.`);
return;
}
const prevDepth = tracker.depth;
const prevVisited = new Set(tracker.visitedBlocs);
tracker.depth++;
tracker.visitedBlocs.add(target);
try {
const value = getDescriptor(target, prop).get.call(target);
tracker.trackedValues.set(prop, value);
return value;
} catch (error) {
tracker.currentlyAccessing.delete(prop);
throw error;
} finally {
tracker.depth = prevDepth;
tracker.visitedBlocs = prevVisited;
}
}
/**
* @internal
*/
function createBlocProxy(bloc) {
const cached = blocProxyCache.get(bloc);
if (cached) return cached;
const proxy = new Proxy(bloc, { get(target, prop, receiver) {
const tracker = activeTrackerMap.get(target);
if (tracker?.isTracking && isGetter(target, prop)) return executeTrackedGetter(target, prop, tracker);
return Reflect.get(target, prop, receiver);
} });
blocProxyCache.set(bloc, proxy);
return proxy;
}
/**
* @internal
*/
function hasGetterChanges(bloc, tracker) {
if (!tracker || tracker.trackedGetters.size === 0) return false;
tracker.renderCache.clear();
let hasAnyChange = false;
for (const prop of tracker.trackedGetters) try {
const descriptor = getDescriptor(bloc, prop);
if (!descriptor?.get) continue;
const newValue = descriptor.get.call(bloc);
const oldValue = tracker.trackedValues.get(prop);
tracker.renderCache.set(prop, newValue);
tracker.trackedValues.set(prop, newValue);
if (!Object.is(newValue, oldValue)) hasAnyChange = true;
} catch (error) {
console.warn(`${BLAC_ERROR_PREFIX} Getter "${String(prop)}" threw error during change detection. Stopping tracking for this getter.`, error);
tracker.trackedGetters.delete(prop);
tracker.trackedValues.delete(prop);
tracker.cacheValid = false;
return true;
}
tracker.cacheValid = true;
return hasAnyChange;
}
/**
* @internal
*/
function invalidateRenderCache(tracker) {
tracker.cacheValid = false;
}
/**
* Create a new tracking proxy state.
*/
function createState() {
return {
dependencyState: createDependencyState(),
getterState: createGetterState(),
dependencies: /* @__PURE__ */ new Set(),
isTracking: false
};
}
/**
* Start tracking on a tracking proxy.
*/
function startTracking(tracker) {
tracker.isTracking = true;
tracker.dependencies.clear();
tracker.getterState.isTracking = true;
startDependency(tracker.dependencyState);
}
/**
* Stop tracking and collect all dependencies.
*/
function stopTracking(tracker, bloc) {
tracker.isTracking = false;
tracker.getterState.isTracking = false;
capturePaths(tracker.dependencyState, bloc.state);
commitTrackedGetters(tracker.getterState);
return new Set(tracker.dependencies);
}
/**
* Check if tracked state or getters have changed.
*/
function hasChanges(tracker, bloc) {
invalidateRenderCache(tracker.getterState);
const stateChanged = hasDependencyChanges(tracker.dependencyState, bloc.state);
const getterChanged = hasGetterChanges(bloc, tracker.getterState);
return stateChanged || getterChanged;
}
/**
* Create a tracking proxy for a bloc instance.
* Tracks both state property access and getter access.
*/
function createTrackingProxy(bloc, tracker) {
tracker.dependencies.add(bloc);
const stateProxyCache = /* @__PURE__ */ new WeakMap();
return new Proxy(bloc, { get(target, prop, receiver) {
if (prop === "state") {
if (!tracker.isTracking) return target.state;
const rawState = target.state;
if (rawState === null || typeof rawState !== "object") return rawState;
if (stateProxyCache.has(rawState)) return stateProxyCache.get(rawState);
const stateProxy = createDependencyProxy(tracker.dependencyState, rawState);
stateProxyCache.set(rawState, stateProxy);
return stateProxy;
}
if (typeof prop === "symbol") return Reflect.get(target, prop, receiver);
const value = Reflect.get(target, prop, receiver);
if (typeof value === "function") return value.bind(target);
if (tracker.isTracking && isGetter(target, prop)) return executeTrackedGetter(target, prop, tracker.getterState);
return value;
} });
}
//#endregion
//#region src/tracking/dependency-manager.ts
/**
* Manages subscriptions to state container dependencies.
* Provides efficient sync mechanism to add/remove subscriptions
* as dependencies change between callback invocations.
*/
var DependencyManager = class {
constructor() {
this.subscriptions = /* @__PURE__ */ new Map();
this.currentDeps = /* @__PURE__ */ new Set();
}
/**
* Sync subscriptions with a new set of dependencies.
* Adds subscriptions for new deps, removes subscriptions for stale deps.
*
* @param newDeps - The new set of dependencies to subscribe to
* @param onChange - Callback to invoke when any dependency changes
* @param exclude - Optional instance to exclude from subscriptions (e.g., primary bloc)
* @returns true if the dependency set changed, false if unchanged
*/
sync(newDeps, onChange, exclude) {
const filteredNewDeps = /* @__PURE__ */ new Set();
for (const dep of newDeps) if (dep !== exclude && !dep.isDisposed) filteredNewDeps.add(dep);
if (this.areSetsEqual(this.currentDeps, filteredNewDeps)) return false;
for (const dep of this.currentDeps) if (!filteredNewDeps.has(dep)) {
const unsub = this.subscriptions.get(dep);
if (unsub) {
unsub();
this.subscriptions.delete(dep);
}
}
for (const dep of filteredNewDeps) if (!this.currentDeps.has(dep) && !this.subscriptions.has(dep)) {
const unsub = dep.subscribe(onChange);
this.subscriptions.set(dep, unsub);
}
this.currentDeps = filteredNewDeps;
return true;
}
/**
* Add a single dependency subscription.
*/
add(dep, onChange) {
if (this.subscriptions.has(dep) || dep.isDisposed) return;
const unsub = dep.subscribe(onChange);
this.subscriptions.set(dep, unsub);
this.currentDeps.add(dep);
}
/**
* Check if a dependency is currently subscribed.
*/
has(dep) {
return this.currentDeps.has(dep);
}
/**
* Get the current set of dependencies.
*/
getDependencies() {
return new Set(this.currentDeps);
}
/**
* Clean up all active subscriptions.
*/
cleanup() {
for (const unsub of this.subscriptions.values()) unsub();
this.subscriptions.clear();
this.currentDeps.clear();
}
areSetsEqual(a, b) {
if (a.size !== b.size) return false;
for (const item of a) if (!b.has(item)) return false;
return true;
}
};
//#endregion
//#region src/tracking/resolve-dependencies.ts
/**
* Resolve all transitive dependencies of a bloc via BFS over `dependencies` maps.
* Uses cycle detection to avoid infinite loops.
* @internal
*/
function resolveDependencies(bloc) {
const result = /* @__PURE__ */ new Set();
const visited = /* @__PURE__ */ new Set();
const queue = [bloc];
while (queue.length > 0) {
const current = queue.shift();
for (const [Type, key] of current.dependencies) {
if (visited.has(Type)) continue;
visited.add(Type);
const dep = globalRegistry.ensure(Type, key);
result.add(dep);
if (dep.dependencies.size > 0) queue.push(dep);
}
}
result.delete(bloc);
return result;
}
//#endregion
//#region src/watch/watch.ts
const STOP = Symbol("watch.STOP");
const BLOC_REF_MARKER = Symbol("BlocRef");
/**
* Create a reference to a specific bloc instance.
*
* @example
* ```ts
* watch(instance(UserBloc, 'user-123'), (userBloc) => {
* console.log(userBloc.state.name);
* });
* ```
*/
function instance(BlocClass, instanceId) {
return {
[BLOC_REF_MARKER]: true,
blocClass: BlocClass,
instanceId
};
}
function isBlocRef(input) {
return typeof input === "object" && input !== null && BLOC_REF_MARKER in input;
}
function resolveBloc(input) {
if (isBlocRef(input)) return ensure(input.blocClass, input.instanceId);
return ensure(input, BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY);
}
function isArray(input) {
return Array.isArray(input);
}
function watchImpl(blocsOrBloc, callback) {
const isSingle = !isArray(blocsOrBloc);
const instances = (isSingle ? [blocsOrBloc] : blocsOrBloc).map(resolveBloc);
const tracker = createState();
const proxiedInstances = instances.map((inst) => createTrackingProxy(inst, tracker));
const externalDepsManager = new DependencyManager();
let disposed = false;
const primarySubscriptions = [];
const cleanup = () => {
if (disposed) return;
disposed = true;
primarySubscriptions.forEach((unsub) => unsub());
externalDepsManager.cleanup();
};
const runCallback = () => {
if (disposed) return;
startTracking(tracker);
let result;
try {
result = callback(isSingle ? proxiedInstances[0] : proxiedInstances);
} finally {
const externalDeps = /* @__PURE__ */ new Set();
for (const inst of instances) {
const deps = stopTracking(tracker, inst);
for (const dep of deps) externalDeps.add(dep);
for (const dep of resolveDependencies(inst)) externalDeps.add(dep);
}
for (const inst of instances) externalDeps.delete(inst);
externalDepsManager.sync(externalDeps, runCallback);
}
if (result === STOP) cleanup();
};
const onChange = () => {
if (disposed) return;
runCallback();
};
for (const inst of instances) primarySubscriptions.push(inst.subscribe(onChange));
runCallback();
return cleanup;
}
const watch = Object.assign(watchImpl, { STOP });
//#endregion
//#region src/tracking/tracked.ts
/**
* Run a callback while tracking all bloc dependencies accessed.
* Returns both the result and the set of discovered dependencies.
*
* @example
* ```ts
* const { result, dependencies } = tracked(() => {
* const user = ensure(UserBloc);
* return user.fullName; // getter that may access other blocs
* });
* // dependencies contains UserBloc + any blocs accessed in fullName getter
* ```
*/
function tracked(callback, options) {
const tracker = createState();
startTracking(tracker);
let result;
try {
result = callback();
} finally {
stopTracking(tracker, { state: null });
}
const dependencies = new Set(tracker.dependencies);
if (options?.exclude) dependencies.delete(options.exclude);
return {
result,
dependencies
};
}
/**
* Context for running tracked callbacks with bloc proxies.
* Provides methods to create proxies and check for changes.
*/
var TrackedContext = class {
constructor() {
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
this.primaryBlocs = /* @__PURE__ */ new Set();
this.tracker = createState();
}
/**
* Get a tracking proxy for a bloc instance.
* The proxy will track state and getter accesses.
*/
proxy(bloc) {
const cached = this.proxiedBlocs.get(bloc);
if (cached) return cached;
const proxied = createTrackingProxy(bloc, this.tracker);
this.proxiedBlocs.set(bloc, proxied);
this.primaryBlocs.add(bloc);
return proxied;
}
/**
* Start tracking for a new callback execution.
*/
start() {
startTracking(this.tracker);
}
/**
* Stop tracking and get discovered dependencies.
* Excludes primary blocs (those explicitly proxied via proxy()).
*/
stop() {
const allDeps = /* @__PURE__ */ new Set();
for (const bloc of this.primaryBlocs) {
const deps = stopTracking(this.tracker, bloc);
for (const dep of deps) if (!this.primaryBlocs.has(dep)) allDeps.add(dep);
}
return allDeps;
}
/**
* Check if any tracked state or getters have changed.
*/
changed() {
for (const bloc of this.primaryBlocs) if (hasChanges(this.tracker, bloc)) return true;
return false;
}
/**
* Get all primary blocs (those explicitly proxied).
*/
getPrimaryBlocs() {
return new Set(this.primaryBlocs);
}
/**
* Reset the context for reuse.
*/
reset() {
this.tracker = createState();
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
this.primaryBlocs.clear();
}
};
/**
* Create a new tracked context for manual control over tracking.
*/
function createTrackedContext() {
return new TrackedContext();
}
//#endregion
//#region src/types/branded.ts
/**
* Create a branded InstanceId from a string
* @param id - The string ID to brand
* @returns Branded InstanceId
*/
function instanceId(id) {
return id;
}
//#endregion
export { Cubit, DependencyManager, PluginManager, StateContainer, TrackedContext, acquire, blac, borrow, borrowSafe, capturePaths, clear, clearActiveTracker, clearAll, commitTrackedGetters, createBlocProxy, createDependencyProxy, createDependencyState, createGetterState, createTrackedContext, ensure, forEach, generateIsolatedKey, getAll, getPluginManager, getRefCount, getRegistry, getStats, globalRegistry, hasDependencyChanges, hasGetterChanges, hasInstance, hasTrackedData, instance, instanceId, invalidateRenderCache, isIsolatedClass, register, release, resolveDependencies, setActiveTracker, setRegistry, shallowEqual, startDependency, tracked, watch };
//# sourceMappingURL=index.js.map
{
"name": "@blac/core",
"version": "2.0.4",
"version": "2.0.5",
"license": "MIT",

@@ -28,81 +28,6 @@ "author": "Brendan Mullins <jsnanigans@gmail.com>",

}
},
"./types": {
"import": {
"types": "./dist/types.d.ts",
"default": "./dist/types.js"
},
"require": {
"types": "./dist/types.d.cts",
"default": "./dist/types.cjs"
}
},
"./tracking": {
"import": {
"types": "./dist/tracking.d.ts",
"default": "./dist/tracking.js"
},
"require": {
"types": "./dist/tracking.d.cts",
"default": "./dist/tracking.cjs"
}
},
"./watch": {
"import": {
"types": "./dist/watch-entry.d.ts",
"default": "./dist/watch-entry.js"
},
"require": {
"types": "./dist/watch-entry.d.cts",
"default": "./dist/watch-entry.cjs"
}
},
"./plugins": {
"import": {
"types": "./dist/plugins.d.ts",
"default": "./dist/plugins.js"
},
"require": {
"types": "./dist/plugins.d.cts",
"default": "./dist/plugins.cjs"
}
},
"./debug": {
"import": {
"types": "./dist/debug.d.ts",
"default": "./dist/debug.js"
},
"require": {
"types": "./dist/debug.d.cts",
"default": "./dist/debug.cjs"
}
}
},
"files": [
"dist/index.js",
"dist/index.cjs",
"dist/index.d.ts",
"dist/index.d.cts",
"dist/types.js",
"dist/types.cjs",
"dist/types.d.ts",
"dist/types.d.cts",
"dist/tracking.js",
"dist/tracking.cjs",
"dist/tracking.d.ts",
"dist/tracking.d.cts",
"dist/tracking/**/*.d.ts",
"dist/watch-entry.js",
"dist/watch-entry.cjs",
"dist/watch-entry.d.ts",
"dist/watch-entry.d.cts",
"dist/plugins.js",
"dist/plugins.cjs",
"dist/plugins.d.ts",
"dist/plugins.d.cts",
"dist/debug.js",
"dist/debug.cjs",
"dist/debug.d.ts",
"dist/debug.d.cts",
"dist/*.map",
"dist",
"README.md",

@@ -131,2 +56,3 @@ "LICENSE"

"vitest": "3.2.4",
"publint": "^0.3.12",
"zod": "^4.1.12"

@@ -136,6 +62,3 @@ },

"dev": "tsdown --watch",
"build": "pnpm build:js && pnpm build:types && pnpm build:dts",
"build:js": "tsdown",
"build:types": "tsc -p tsconfig.build.json",
"build:dts": "api-extractor run --local && cp dist/index.d.ts dist/index.d.cts && cp -r dist/.types/tracking dist/tracking && cp dist/.types/tracking.d.ts dist/tracking.d.ts && cp dist/.types/tracking.d.ts dist/tracking.d.cts && cp dist/.types/types.d.ts dist/types.d.ts && cp dist/.types/types.d.ts dist/types.d.cts && rm -rf dist/.types",
"build": "tsdown && tsc -p tsconfig.build.json && cp dist/index.d.ts dist/index.d.cts",
"clean": "rm -rf dist",

@@ -148,2 +71,3 @@ "format": "prettier --write \".\"",

"coverage": "vitest run --coverage",
"verify": "publint",
"typecheck": "tsc --noEmit",

@@ -150,0 +74,0 @@ "deploy": "pnpm publish --access public"

const require_StateContainerRegistry = require('./StateContainerRegistry.cjs');
const require_management = require('./management.cjs');
//#region src/registry/config.ts
let _registry = require_StateContainerRegistry.globalRegistry;
function getRegistry() {
return _registry;
}
function setRegistry(registry) {
_registry.clearAll();
_registry = registry;
}
function getStats() {
return _registry.getStats();
}
//#endregion
exports.forEach = require_management.forEach;
exports.getAll = require_management.getAll;
exports.getRefCount = require_management.getRefCount;
exports.getRegistry = getRegistry;
exports.getStats = getStats;
exports.globalRegistry = require_StateContainerRegistry.globalRegistry;
exports.hasInstance = require_management.hasInstance;
exports.register = require_management.register;
exports.setRegistry = setRegistry;
//# sourceMappingURL=debug.cjs.map
{"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"}
import { n as globalRegistry } from "./StateContainerRegistry.js";
import { a as getAll, i as forEach, o as getRefCount, r as register, s as hasInstance } from "./management.js";
//#region src/registry/config.ts
let _registry = globalRegistry;
function getRegistry() {
return _registry;
}
function setRegistry(registry) {
_registry.clearAll();
_registry = registry;
}
function getStats() {
return _registry.getStats();
}
//#endregion
export { forEach, getAll, getRefCount, getRegistry, getStats, globalRegistry, hasInstance, register, setRegistry };
//# sourceMappingURL=debug.js.map
{"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"}
{"version":3,"file":"management.cjs","names":["globalRegistry"],"sources":["../src/registry/queries.ts","../src/registry/management.ts"],"sourcesContent":["import { globalRegistry } from '../core/StateContainerRegistry';\nimport type {\n StateContainerConstructor,\n InstanceReadonlyState,\n} from '../types/utilities';\n\nexport function hasInstance<T extends StateContainerConstructor>(\n BlocClass: T,\n instanceKey?: string,\n): boolean {\n return globalRegistry.hasInstance(BlocClass, instanceKey);\n}\n\nexport function getRefCount<T extends StateContainerConstructor>(\n BlocClass: T,\n instanceKey?: string,\n): number {\n return globalRegistry.getRefCount(BlocClass, instanceKey);\n}\n\nexport function getAll<T extends StateContainerConstructor>(\n BlocClass: T,\n): InstanceReadonlyState<T>[] {\n return globalRegistry.getAll(BlocClass);\n}\n\nexport function forEach<T extends StateContainerConstructor>(\n BlocClass: T,\n callback: (instance: InstanceReadonlyState<T>) => void,\n): void {\n globalRegistry.forEach(BlocClass, callback);\n}\n","import { globalRegistry } from '../core/StateContainerRegistry';\nimport type { StateContainerConstructor } from '../types/utilities';\n\nexport function clear<T extends StateContainerConstructor>(BlocClass: T): void {\n globalRegistry.clear(BlocClass);\n}\n\nexport function clearAll(): void {\n globalRegistry.clearAll();\n}\n\nexport function register<T extends StateContainerConstructor>(\n BlocClass: T,\n isolated = false,\n): void {\n globalRegistry.register(BlocClass, isolated);\n}\n"],"mappings":";;;AAMA,SAAgB,YACd,WACA,aACS;AACT,QAAOA,8CAAe,YAAY,WAAW,YAAY;;AAG3D,SAAgB,YACd,WACA,aACQ;AACR,QAAOA,8CAAe,YAAY,WAAW,YAAY;;AAG3D,SAAgB,OACd,WAC4B;AAC5B,QAAOA,8CAAe,OAAO,UAAU;;AAGzC,SAAgB,QACd,WACA,UACM;AACN,+CAAe,QAAQ,WAAW,SAAS;;;;;AC3B7C,SAAgB,MAA2C,WAAoB;AAC7E,+CAAe,MAAM,UAAU;;AAGjC,SAAgB,WAAiB;AAC/B,+CAAe,UAAU;;AAG3B,SAAgB,SACd,WACA,WAAW,OACL;AACN,+CAAe,SAAS,WAAW,SAAS"}
{"version":3,"file":"management.js","names":[],"sources":["../src/registry/queries.ts","../src/registry/management.ts"],"sourcesContent":["import { globalRegistry } from '../core/StateContainerRegistry';\nimport type {\n StateContainerConstructor,\n InstanceReadonlyState,\n} from '../types/utilities';\n\nexport function hasInstance<T extends StateContainerConstructor>(\n BlocClass: T,\n instanceKey?: string,\n): boolean {\n return globalRegistry.hasInstance(BlocClass, instanceKey);\n}\n\nexport function getRefCount<T extends StateContainerConstructor>(\n BlocClass: T,\n instanceKey?: string,\n): number {\n return globalRegistry.getRefCount(BlocClass, instanceKey);\n}\n\nexport function getAll<T extends StateContainerConstructor>(\n BlocClass: T,\n): InstanceReadonlyState<T>[] {\n return globalRegistry.getAll(BlocClass);\n}\n\nexport function forEach<T extends StateContainerConstructor>(\n BlocClass: T,\n callback: (instance: InstanceReadonlyState<T>) => void,\n): void {\n globalRegistry.forEach(BlocClass, callback);\n}\n","import { globalRegistry } from '../core/StateContainerRegistry';\nimport type { StateContainerConstructor } from '../types/utilities';\n\nexport function clear<T extends StateContainerConstructor>(BlocClass: T): void {\n globalRegistry.clear(BlocClass);\n}\n\nexport function clearAll(): void {\n globalRegistry.clearAll();\n}\n\nexport function register<T extends StateContainerConstructor>(\n BlocClass: T,\n isolated = false,\n): void {\n globalRegistry.register(BlocClass, isolated);\n}\n"],"mappings":";;;AAMA,SAAgB,YACd,WACA,aACS;AACT,QAAO,eAAe,YAAY,WAAW,YAAY;;AAG3D,SAAgB,YACd,WACA,aACQ;AACR,QAAO,eAAe,YAAY,WAAW,YAAY;;AAG3D,SAAgB,OACd,WAC4B;AAC5B,QAAO,eAAe,OAAO,UAAU;;AAGzC,SAAgB,QACd,WACA,UACM;AACN,gBAAe,QAAQ,WAAW,SAAS;;;;;AC3B7C,SAAgB,MAA2C,WAAoB;AAC7E,gBAAe,MAAM,UAAU;;AAGjC,SAAgB,WAAiB;AAC/B,gBAAe,UAAU;;AAG3B,SAAgB,SACd,WACA,WAAW,OACL;AACN,gBAAe,SAAS,WAAW,SAAS"}
const require_StateContainerRegistry = require('./StateContainerRegistry.cjs');
exports.PluginManager = require_StateContainerRegistry.PluginManager;
exports.getPluginManager = require_StateContainerRegistry.getPluginManager;
import { s as PluginManager, t as getPluginManager } from "./StateContainerRegistry.js";
export { PluginManager, getPluginManager };
{"version":3,"file":"resolve-dependencies.cjs","names":["BLAC_DEFAULTS","BLAC_ERROR_PREFIX","globalRegistry"],"sources":["../src/tracking/path-utils.ts","../src/tracking/tracking-proxy.ts","../src/tracking/dependency-manager.ts","../src/tracking/resolve-dependencies.ts"],"sourcesContent":["/**\n * Path utilities for dependency tracking\n *\n * Provides utilities for parsing property paths and extracting values\n * from nested objects using path strings.\n *\n * @internal\n */\n\n/**\n * Parse a property path string into an array of segments\n *\n * @internal\n *\n * Handles both dot notation (a.b.c) and bracket notation (a[0].b)\n *\n * @example\n * ```ts\n * parsePath('user.name') // ['user', 'name']\n * parsePath('items[0].name') // ['items', '0', 'name']\n * parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']\n * ```\n */\nexport function parsePath(path: string): string[] {\n const segments: string[] = [];\n let current = '';\n let i = 0;\n\n while (i < path.length) {\n const char = path[i];\n if (char === '.') {\n if (current) segments.push(current);\n current = '';\n } else if (char === '[') {\n if (current) segments.push(current);\n current = '';\n // Skip bracket\n i++;\n // Read until ]\n while (i < path.length && path[i] !== ']') {\n current += path[i++];\n }\n if (current) segments.push(current);\n current = '';\n } else {\n current += char;\n }\n i++;\n }\n\n if (current) segments.push(current);\n return segments;\n}\n\n/**\n * Get a value from an object using a path of segments\n *\n * @example\n * ```ts\n * const obj = { user: { name: 'Alice', age: 30 } }\n * getValueAtPath(obj, ['user', 'name']) // 'Alice'\n * getValueAtPath(obj, ['user', 'age']) // 30\n * getValueAtPath(obj, ['user', 'missing']) // undefined\n * ```\n *\n * @internal\n */\nexport function getValueAtPath(obj: any, segments: string[]): any {\n if (obj == null) return undefined;\n\n let current = obj;\n for (let i = 0; i < segments.length; i++) {\n current = current[segments[i]];\n if (current == null) return undefined;\n }\n return current;\n}\n\n/**\n * Shallow equality comparison for arrays\n *\n * Compares two arrays element-by-element using Object.is\n *\n * @example\n * ```ts\n * shallowEqual([1, 2, 3], [1, 2, 3]) // true\n * shallowEqual([1, 2, 3], [1, 2, 4]) // false\n * shallowEqual([1, 2], [1, 2, 3]) // false\n * ```\n *\n * @internal\n */\nexport function shallowEqual(arr1: unknown[], arr2: unknown[]): boolean {\n if (arr1.length !== arr2.length) return false;\n for (let i = 0; i < arr1.length; i++) {\n if (!Object.is(arr1[i], arr2[i])) return false;\n }\n return true;\n}\n","/**\n * Consolidated Tracking System\n *\n * This module provides all dependency and getter tracking functionality:\n * - Proxy creation for automatic property access tracking\n * - Dependency path tracking and change detection\n * - Getter execution tracking for computed properties\n * - Combined tracking proxy for watch/waitUntil use cases\n */\nimport { BLAC_DEFAULTS, BLAC_ERROR_PREFIX } from '../constants';\nimport type { StateContainerInstance } from '../types/utilities';\nimport { parsePath, getValueAtPath } from './path-utils';\n\n// =============================================================================\n// PROXY TRACKER (Low-level proxy creation)\n// =============================================================================\n\n/**\n * Check if a value can be proxied\n * Returns true for plain objects and arrays only.\n * @internal\n */\nexport function isProxyable(value: unknown): value is object {\n if (typeof value !== 'object' || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === Array.prototype;\n}\n\n/**\n * State container for proxy tracking\n * @internal\n */\nexport interface ProxyState<T> {\n trackedPaths: Set<string>;\n isTracking: boolean;\n proxyCache: WeakMap<object, any>;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n boundFunctionsCache: WeakMap<Function, Function> | null;\n lastProxiedState: T | null;\n lastProxy: T | null;\n maxDepth: number;\n}\n\n/**\n * Create a new proxy tracker state\n * @internal\n */\nexport function createProxyState<T>(): ProxyState<T> {\n return {\n trackedPaths: new Set<string>(),\n isTracking: false,\n proxyCache: new WeakMap<object, any>(),\n boundFunctionsCache: null,\n lastProxiedState: null,\n lastProxy: null,\n maxDepth: 10,\n };\n}\n\n/**\n * Start tracking property accesses\n * @internal\n */\nexport function startProxy<T>(state: ProxyState<T>): void {\n state.isTracking = true;\n state.trackedPaths.clear();\n}\n\n/**\n * Stop tracking and return the tracked paths\n * @internal\n */\nexport function stopProxy<T>(state: ProxyState<T>): Set<string> {\n state.isTracking = false;\n return new Set(state.trackedPaths);\n}\n\n/**\n * Create a proxy for an array with property access tracking\n * @internal\n */\nexport function createArrayProxy<T, U>(\n state: ProxyState<T>,\n target: U[],\n path: string,\n depth: number = 0,\n): U[] {\n const proxy = new Proxy(target, {\n get: (arr, prop: string | symbol) => {\n if (typeof prop === 'symbol') {\n return Reflect.get(arr, prop);\n }\n\n const value = Reflect.get(arr, prop);\n\n if (typeof value === 'function') {\n if (!state.boundFunctionsCache) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n state.boundFunctionsCache = new WeakMap<Function, Function>();\n }\n const cached = state.boundFunctionsCache.get(value);\n if (cached) {\n return cached;\n }\n const bound = value.bind(arr);\n state.boundFunctionsCache.set(value, bound);\n return bound;\n }\n\n if (prop === 'length') {\n if (state.isTracking) {\n const fullPath = path ? `${path}.length` : 'length';\n state.trackedPaths.add(fullPath);\n }\n return value;\n }\n\n let fullPath: string;\n if (typeof prop === 'string') {\n const index = Number(prop);\n if (!isNaN(index) && index >= 0) {\n fullPath = path ? `${path}[${index}]` : `[${index}]`;\n } else {\n fullPath = path ? `${path}.${prop}` : prop;\n }\n } else {\n return value;\n }\n\n if (isProxyable(value)) {\n return createInternal(state, value as T, fullPath, depth + 1);\n }\n\n if (state.isTracking) {\n state.trackedPaths.add(fullPath);\n }\n\n return value;\n },\n });\n\n state.proxyCache.set(target, proxy);\n return proxy;\n}\n\n/**\n * Create a proxy for an object with property access tracking\n * @internal\n */\nexport function createInternal<T>(\n state: ProxyState<T>,\n target: T,\n path: string = '',\n depth: number = 0,\n): T {\n if (!state.isTracking || !isProxyable(target)) {\n return target;\n }\n\n if (depth >= state.maxDepth) {\n return target;\n }\n\n if (state.proxyCache.has(target)) {\n return state.proxyCache.get(target);\n }\n\n if (Array.isArray(target)) {\n return createArrayProxy(\n state,\n target as unknown as any[],\n path,\n depth,\n ) as unknown as T;\n }\n\n const proxy = new Proxy(target, {\n get: (obj, prop: string | symbol) => {\n if (typeof prop === 'symbol') {\n return Reflect.get(obj, prop);\n }\n\n const value = Reflect.get(obj, prop);\n\n if (typeof value === 'function') {\n if (!state.boundFunctionsCache) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n state.boundFunctionsCache = new WeakMap<Function, Function>();\n }\n const cached = state.boundFunctionsCache.get(value);\n if (cached) {\n return cached;\n }\n const bound = value.bind(obj);\n state.boundFunctionsCache.set(value, bound);\n return bound;\n }\n\n const fullPath = path ? `${path}.${String(prop)}` : String(prop);\n\n if (typeof prop === 'string' && state.isTracking) {\n if (!prop.startsWith('_') && !prop.startsWith('$$')) {\n state.trackedPaths.add(fullPath);\n }\n }\n\n if (isProxyable(value)) {\n const proxiedValue = createInternal(\n state,\n value as T,\n fullPath,\n depth + 1,\n );\n return proxiedValue;\n }\n\n return value;\n },\n\n has: (obj, prop: string | symbol) => {\n if (typeof prop === 'string' && state.isTracking) {\n const fullPath = path ? `${path}.${prop}` : prop;\n state.trackedPaths.add(fullPath);\n }\n return Reflect.has(obj, prop);\n },\n\n ownKeys: (obj) => {\n if (state.isTracking && path) {\n state.trackedPaths.add(path);\n }\n return Reflect.ownKeys(obj);\n },\n });\n\n state.proxyCache.set(target, proxy);\n return proxy as T;\n}\n\n/**\n * Create a proxy for a target with caching\n * @internal\n */\nexport function createForTarget<T>(state: ProxyState<T>, target: T): T {\n if (state.lastProxiedState === target && state.lastProxy) {\n return state.lastProxy;\n }\n\n state.proxyCache = new WeakMap<object, any>();\n state.boundFunctionsCache = null;\n\n const proxy = createInternal(state, target, '', 0);\n state.lastProxiedState = target;\n state.lastProxy = proxy;\n return proxy;\n}\n\n// =============================================================================\n// DEPENDENCY TRACKER (Path tracking and change detection)\n// =============================================================================\n\n/**\n * @internal\n */\nexport interface PathInfo {\n segments: string[];\n value: any;\n}\n\n/**\n * @internal\n */\nexport interface DependencyState<T> {\n proxyState: ProxyState<T>;\n previousRenderPaths: Set<string>;\n currentRenderPaths: Set<string>;\n pathCache: Map<string, PathInfo>;\n lastCheckedState: T | null;\n lastCheckedValues: Map<string, any>;\n}\n\nfunction isChildPath(child: string, parent: string): boolean {\n if (child === parent) return false;\n return child.startsWith(parent + '.') || child.startsWith(parent + '[');\n}\n\nfunction getArrayParentPath(path: string): string | null {\n if (path.endsWith('.length')) {\n return path.slice(0, -7);\n }\n const arrayIndexMatch = path.match(/^(.+?)\\[\\d+\\]/);\n if (arrayIndexMatch) {\n return arrayIndexMatch[1];\n }\n return null;\n}\n\n/**\n * @internal\n */\nexport function optimizeTrackedPaths(paths: Set<string>): Set<string> {\n if (paths.size === 0) {\n return new Set();\n }\n\n if (paths.size === 1) {\n return new Set(paths);\n }\n\n const sortedPaths = Array.from(paths).sort((a, b) => b.length - a.length);\n const optimized = new Set<string>();\n\n for (const path of sortedPaths) {\n let hasMoreSpecificChild = false;\n\n for (const optimizedPath of optimized) {\n if (isChildPath(optimizedPath, path)) {\n hasMoreSpecificChild = true;\n break;\n }\n }\n\n if (!hasMoreSpecificChild) {\n optimized.add(path);\n }\n }\n\n const arrayParents = new Set<string>();\n for (const path of optimized) {\n const arrayParent = getArrayParentPath(path);\n if (arrayParent) {\n arrayParents.add(arrayParent);\n }\n }\n\n for (const arrayParent of arrayParents) {\n optimized.add(arrayParent);\n }\n\n return optimized;\n}\n\n/**\n * @internal\n */\nexport function createDependencyState<T>(): DependencyState<T> {\n return {\n proxyState: createProxyState<T>(),\n previousRenderPaths: new Set<string>(),\n currentRenderPaths: new Set<string>(),\n pathCache: new Map<string, PathInfo>(),\n lastCheckedState: null,\n lastCheckedValues: new Map<string, any>(),\n };\n}\n\n/**\n * @internal\n */\nexport function startDependency<T>(tracker: DependencyState<T>): void {\n startProxy(tracker.proxyState);\n}\n\n/**\n * @internal\n */\nexport function createDependencyProxy<T>(\n tracker: DependencyState<T>,\n state: T,\n): T {\n return createForTarget(tracker.proxyState, state);\n}\n\n/**\n * @internal\n */\nexport function capturePaths<T>(tracker: DependencyState<T>, state: T): void {\n tracker.previousRenderPaths = tracker.currentRenderPaths;\n\n const rawPaths = stopProxy(tracker.proxyState);\n tracker.currentRenderPaths = optimizeTrackedPaths(rawPaths);\n\n if (\n tracker.previousRenderPaths.size === 0 &&\n tracker.currentRenderPaths.size === 0\n ) {\n return;\n }\n\n const trackedPathsUnion = new Set(tracker.previousRenderPaths);\n for (const path of tracker.currentRenderPaths) {\n trackedPathsUnion.add(path);\n }\n\n const canReuseCache = tracker.lastCheckedState === state;\n\n for (const path of trackedPathsUnion) {\n if (!tracker.pathCache.has(path)) {\n const segments = parsePath(path);\n const value =\n canReuseCache && tracker.lastCheckedValues.has(path)\n ? tracker.lastCheckedValues.get(path)\n : getValueAtPath(state, segments);\n\n tracker.pathCache.set(path, { segments, value });\n } else {\n const info = tracker.pathCache.get(path)!;\n info.value =\n canReuseCache && tracker.lastCheckedValues.has(path)\n ? tracker.lastCheckedValues.get(path)\n : getValueAtPath(state, info.segments);\n }\n }\n\n tracker.lastCheckedValues.clear();\n}\n\n/**\n * @internal\n */\nexport function hasDependencyChanges<T>(\n tracker: DependencyState<T>,\n state: T,\n): boolean {\n if (tracker.pathCache.size === 0) {\n return true;\n }\n\n tracker.lastCheckedValues.clear();\n\n for (const [path, info] of tracker.pathCache.entries()) {\n const currentValue = getValueAtPath(state, info.segments);\n tracker.lastCheckedValues.set(path, currentValue);\n\n if (!Object.is(currentValue, info.value)) {\n tracker.lastCheckedState = state;\n return true;\n }\n }\n\n tracker.lastCheckedState = state;\n return false;\n}\n\n/**\n * @internal\n */\nexport function hasTrackedData<T>(tracker: DependencyState<T>): boolean {\n return (\n tracker.proxyState.trackedPaths.size > 0 ||\n tracker.pathCache.size > 0 ||\n tracker.previousRenderPaths.size > 0\n );\n}\n\n// =============================================================================\n// GETTER TRACKER (Getter execution tracking)\n// =============================================================================\n\n/**\n * @internal\n */\nexport interface GetterState {\n trackedValues: Map<string | symbol, unknown>;\n currentlyAccessing: Set<string | symbol>;\n trackedGetters: Set<string | symbol>;\n isTracking: boolean;\n renderCache: Map<string | symbol, unknown>;\n cacheValid: boolean;\n depth: number;\n visitedBlocs: Set<StateContainerInstance>;\n}\n\nconst descriptorCache = new WeakMap<\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n Function,\n Map<string | symbol, PropertyDescriptor | undefined>\n>();\n\nconst blocProxyCache = new WeakMap<StateContainerInstance>();\n\nconst activeTrackerMap = new WeakMap<StateContainerInstance, GetterState>();\n\nconst MAX_GETTER_DEPTH = BLAC_DEFAULTS.MAX_GETTER_DEPTH;\n\n/**\n * @internal\n */\nexport function getDescriptor(\n obj: any,\n prop: string | symbol,\n): PropertyDescriptor | undefined {\n const constructor = obj.constructor;\n\n let constructorCache = descriptorCache.get(constructor);\n if (constructorCache?.has(prop)) {\n return constructorCache.get(prop);\n }\n\n let current = obj;\n let descriptor: PropertyDescriptor | undefined;\n\n while (current && current !== Object.prototype) {\n descriptor = Object.getOwnPropertyDescriptor(current, prop);\n if (descriptor) {\n break;\n }\n current = Object.getPrototypeOf(current);\n }\n\n if (!constructorCache) {\n constructorCache = new Map();\n descriptorCache.set(constructor, constructorCache);\n }\n constructorCache.set(prop, descriptor);\n\n return descriptor;\n}\n\n/**\n * @internal\n */\nexport function isGetter(obj: any, prop: string | symbol): boolean {\n const descriptor = getDescriptor(obj, prop);\n return descriptor?.get !== undefined;\n}\n\n/**\n * @internal\n */\nexport function createGetterState(): GetterState {\n return {\n trackedValues: new Map(),\n currentlyAccessing: new Set(),\n trackedGetters: new Set(),\n isTracking: false,\n renderCache: new Map(),\n cacheValid: false,\n depth: 0,\n visitedBlocs: new Set(),\n };\n}\n\n/**\n * @internal\n */\nexport function setActiveTracker<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n tracker: GetterState,\n): void {\n activeTrackerMap.set(bloc, tracker);\n}\n\n/**\n * @internal\n */\nexport function clearActiveTracker<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n): void {\n activeTrackerMap.delete(bloc);\n}\n\n/**\n * @internal\n */\nexport function getActiveTracker<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n): GetterState | undefined {\n return activeTrackerMap.get(bloc);\n}\n\n/**\n * @internal\n */\nexport function commitTrackedGetters(tracker: GetterState): void {\n if (tracker.currentlyAccessing.size > 0) {\n tracker.trackedGetters = new Set(tracker.currentlyAccessing);\n }\n tracker.currentlyAccessing.clear();\n}\n\n/**\n * Execute a tracked getter with depth/circular dependency checks and context management.\n * @internal\n */\nfunction executeTrackedGetter<T extends StateContainerInstance>(\n target: T,\n prop: string | symbol,\n tracker: GetterState,\n): unknown {\n tracker.currentlyAccessing.add(prop);\n\n if (tracker.cacheValid && tracker.renderCache.has(prop)) {\n const cachedValue = tracker.renderCache.get(prop);\n tracker.trackedValues.set(prop, cachedValue);\n return cachedValue;\n }\n\n if (tracker.depth >= MAX_GETTER_DEPTH) {\n console.warn(\n `${BLAC_ERROR_PREFIX} Maximum getter depth (${MAX_GETTER_DEPTH}) exceeded. ` +\n `Possible circular dependency in getter \"${String(prop)}\" on ${target.constructor.name}.`,\n );\n return undefined;\n }\n\n if (tracker.visitedBlocs.has(target)) {\n console.warn(\n `${BLAC_ERROR_PREFIX} Circular dependency detected: getter \"${String(prop)}\" on ${target.constructor.name}.`,\n );\n return undefined;\n }\n\n const prevDepth = tracker.depth;\n const prevVisited = new Set(tracker.visitedBlocs);\n\n tracker.depth++;\n tracker.visitedBlocs.add(target);\n\n try {\n const descriptor = getDescriptor(target, prop);\n const value = descriptor!.get!.call(target);\n tracker.trackedValues.set(prop, value);\n return value;\n } catch (error) {\n tracker.currentlyAccessing.delete(prop);\n throw error;\n } finally {\n tracker.depth = prevDepth;\n tracker.visitedBlocs = prevVisited;\n }\n}\n\n/**\n * @internal\n */\nexport function createBlocProxy<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n): TBloc {\n const cached = blocProxyCache.get(bloc);\n if (cached) {\n return cached;\n }\n\n const proxy = new Proxy(bloc, {\n get(target, prop, receiver) {\n const tracker = activeTrackerMap.get(target);\n\n if (tracker?.isTracking && isGetter(target, prop)) {\n return executeTrackedGetter(target, prop, tracker);\n }\n\n return Reflect.get(target, prop, receiver);\n },\n });\n\n blocProxyCache.set(bloc, proxy);\n return proxy;\n}\n\n/**\n * @internal\n */\nexport function hasGetterChanges<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n tracker: GetterState | null,\n): boolean {\n if (!tracker || tracker.trackedGetters.size === 0) {\n return false;\n }\n\n tracker.renderCache.clear();\n\n let hasAnyChange = false;\n\n for (const prop of tracker.trackedGetters) {\n try {\n const descriptor = getDescriptor(bloc, prop);\n if (!descriptor?.get) {\n continue;\n }\n\n const newValue = descriptor.get.call(bloc);\n const oldValue = tracker.trackedValues.get(prop);\n\n tracker.renderCache.set(prop, newValue);\n tracker.trackedValues.set(prop, newValue);\n\n if (!Object.is(newValue, oldValue)) {\n hasAnyChange = true;\n }\n } catch (error) {\n console.warn(\n `${BLAC_ERROR_PREFIX} Getter \"${String(prop)}\" threw error during change detection. Stopping tracking for this getter.`,\n error,\n );\n\n tracker.trackedGetters.delete(prop);\n tracker.trackedValues.delete(prop);\n tracker.cacheValid = false;\n return true;\n }\n }\n\n tracker.cacheValid = true;\n\n return hasAnyChange;\n}\n\n/**\n * @internal\n */\nexport function invalidateRenderCache(tracker: GetterState): void {\n tracker.cacheValid = false;\n}\n\n/**\n * @internal\n */\nexport function resetGetterState(tracker: GetterState): void {\n tracker.trackedValues.clear();\n tracker.currentlyAccessing.clear();\n tracker.trackedGetters.clear();\n tracker.renderCache.clear();\n tracker.cacheValid = false;\n tracker.isTracking = false;\n tracker.depth = 0;\n tracker.visitedBlocs.clear();\n}\n\n// =============================================================================\n// TRACKING PROXY (Combined tracking for watch/waitUntil)\n// =============================================================================\n\n/**\n * State for tracking both state property access and getter access.\n */\nexport interface TrackingProxyState {\n dependencyState: DependencyState<any>;\n getterState: GetterState;\n dependencies: Set<StateContainerInstance>;\n isTracking: boolean;\n}\n\n/**\n * Create a new tracking proxy state.\n */\nexport function createState(): TrackingProxyState {\n return {\n dependencyState: createDependencyState(),\n getterState: createGetterState(),\n dependencies: new Set(),\n isTracking: false,\n };\n}\n\n/**\n * Start tracking on a tracking proxy.\n */\nexport function startTracking(tracker: TrackingProxyState): void {\n tracker.isTracking = true;\n tracker.dependencies.clear();\n tracker.getterState.isTracking = true;\n startDependency(tracker.dependencyState);\n}\n\n/**\n * Stop tracking and collect all dependencies.\n */\nexport function stopTracking(\n tracker: TrackingProxyState,\n bloc: StateContainerInstance,\n): Set<StateContainerInstance> {\n tracker.isTracking = false;\n tracker.getterState.isTracking = false;\n\n capturePaths(tracker.dependencyState, bloc.state);\n commitTrackedGetters(tracker.getterState);\n\n return new Set(tracker.dependencies);\n}\n\n/**\n * Check if tracked state or getters have changed.\n */\nexport function hasChanges(\n tracker: TrackingProxyState,\n bloc: StateContainerInstance,\n): boolean {\n invalidateRenderCache(tracker.getterState);\n\n const stateChanged = hasDependencyChanges(\n tracker.dependencyState,\n bloc.state,\n );\n const getterChanged = hasGetterChanges(bloc, tracker.getterState);\n\n return stateChanged || getterChanged;\n}\n\n/**\n * Create a tracking proxy for a bloc instance.\n * Tracks both state property access and getter access.\n */\nexport function createTrackingProxy<T extends StateContainerInstance>(\n bloc: T,\n tracker: TrackingProxyState,\n): T {\n tracker.dependencies.add(bloc);\n\n const stateProxyCache = new WeakMap<object, any>();\n\n const proxy = new Proxy(bloc, {\n get(target, prop, receiver) {\n if (prop === 'state') {\n if (!tracker.isTracking) {\n return target.state;\n }\n\n const rawState = target.state;\n if (rawState === null || typeof rawState !== 'object') {\n return rawState;\n }\n\n if (stateProxyCache.has(rawState)) {\n return stateProxyCache.get(rawState);\n }\n\n const stateProxy = createDependencyProxy(\n tracker.dependencyState,\n rawState,\n );\n stateProxyCache.set(rawState, stateProxy);\n return stateProxy;\n }\n\n if (typeof prop === 'symbol') {\n return Reflect.get(target, prop, receiver);\n }\n\n const value = Reflect.get(target, prop, receiver);\n\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n if (tracker.isTracking && isGetter(target, prop)) {\n return executeTrackedGetter(target, prop, tracker.getterState);\n }\n\n return value;\n },\n });\n\n return proxy as T;\n}\n","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","import { globalRegistry } from '../core/StateContainerRegistry';\nimport type {\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\n\n/**\n * Resolve all transitive dependencies of a bloc via BFS over `dependencies` maps.\n * Uses cycle detection to avoid infinite loops.\n * @internal\n */\nexport function resolveDependencies(\n bloc: StateContainerInstance,\n): Set<StateContainerInstance> {\n const result = new Set<StateContainerInstance>();\n const visited = new Set<StateContainerConstructor>();\n const queue: StateContainerInstance[] = [bloc];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const [Type, key] of current.dependencies) {\n if (visited.has(Type)) continue;\n visited.add(Type);\n const dep = globalRegistry.ensure(Type, key);\n result.add(dep);\n if (dep.dependencies.size > 0) {\n queue.push(dep);\n }\n }\n }\n\n result.delete(bloc);\n return result;\n}\n"],"mappings":"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"}
{"version":3,"file":"resolve-dependencies.js","names":[],"sources":["../src/tracking/path-utils.ts","../src/tracking/tracking-proxy.ts","../src/tracking/dependency-manager.ts","../src/tracking/resolve-dependencies.ts"],"sourcesContent":["/**\n * Path utilities for dependency tracking\n *\n * Provides utilities for parsing property paths and extracting values\n * from nested objects using path strings.\n *\n * @internal\n */\n\n/**\n * Parse a property path string into an array of segments\n *\n * @internal\n *\n * Handles both dot notation (a.b.c) and bracket notation (a[0].b)\n *\n * @example\n * ```ts\n * parsePath('user.name') // ['user', 'name']\n * parsePath('items[0].name') // ['items', '0', 'name']\n * parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']\n * ```\n */\nexport function parsePath(path: string): string[] {\n const segments: string[] = [];\n let current = '';\n let i = 0;\n\n while (i < path.length) {\n const char = path[i];\n if (char === '.') {\n if (current) segments.push(current);\n current = '';\n } else if (char === '[') {\n if (current) segments.push(current);\n current = '';\n // Skip bracket\n i++;\n // Read until ]\n while (i < path.length && path[i] !== ']') {\n current += path[i++];\n }\n if (current) segments.push(current);\n current = '';\n } else {\n current += char;\n }\n i++;\n }\n\n if (current) segments.push(current);\n return segments;\n}\n\n/**\n * Get a value from an object using a path of segments\n *\n * @example\n * ```ts\n * const obj = { user: { name: 'Alice', age: 30 } }\n * getValueAtPath(obj, ['user', 'name']) // 'Alice'\n * getValueAtPath(obj, ['user', 'age']) // 30\n * getValueAtPath(obj, ['user', 'missing']) // undefined\n * ```\n *\n * @internal\n */\nexport function getValueAtPath(obj: any, segments: string[]): any {\n if (obj == null) return undefined;\n\n let current = obj;\n for (let i = 0; i < segments.length; i++) {\n current = current[segments[i]];\n if (current == null) return undefined;\n }\n return current;\n}\n\n/**\n * Shallow equality comparison for arrays\n *\n * Compares two arrays element-by-element using Object.is\n *\n * @example\n * ```ts\n * shallowEqual([1, 2, 3], [1, 2, 3]) // true\n * shallowEqual([1, 2, 3], [1, 2, 4]) // false\n * shallowEqual([1, 2], [1, 2, 3]) // false\n * ```\n *\n * @internal\n */\nexport function shallowEqual(arr1: unknown[], arr2: unknown[]): boolean {\n if (arr1.length !== arr2.length) return false;\n for (let i = 0; i < arr1.length; i++) {\n if (!Object.is(arr1[i], arr2[i])) return false;\n }\n return true;\n}\n","/**\n * Consolidated Tracking System\n *\n * This module provides all dependency and getter tracking functionality:\n * - Proxy creation for automatic property access tracking\n * - Dependency path tracking and change detection\n * - Getter execution tracking for computed properties\n * - Combined tracking proxy for watch/waitUntil use cases\n */\nimport { BLAC_DEFAULTS, BLAC_ERROR_PREFIX } from '../constants';\nimport type { StateContainerInstance } from '../types/utilities';\nimport { parsePath, getValueAtPath } from './path-utils';\n\n// =============================================================================\n// PROXY TRACKER (Low-level proxy creation)\n// =============================================================================\n\n/**\n * Check if a value can be proxied\n * Returns true for plain objects and arrays only.\n * @internal\n */\nexport function isProxyable(value: unknown): value is object {\n if (typeof value !== 'object' || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === Array.prototype;\n}\n\n/**\n * State container for proxy tracking\n * @internal\n */\nexport interface ProxyState<T> {\n trackedPaths: Set<string>;\n isTracking: boolean;\n proxyCache: WeakMap<object, any>;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n boundFunctionsCache: WeakMap<Function, Function> | null;\n lastProxiedState: T | null;\n lastProxy: T | null;\n maxDepth: number;\n}\n\n/**\n * Create a new proxy tracker state\n * @internal\n */\nexport function createProxyState<T>(): ProxyState<T> {\n return {\n trackedPaths: new Set<string>(),\n isTracking: false,\n proxyCache: new WeakMap<object, any>(),\n boundFunctionsCache: null,\n lastProxiedState: null,\n lastProxy: null,\n maxDepth: 10,\n };\n}\n\n/**\n * Start tracking property accesses\n * @internal\n */\nexport function startProxy<T>(state: ProxyState<T>): void {\n state.isTracking = true;\n state.trackedPaths.clear();\n}\n\n/**\n * Stop tracking and return the tracked paths\n * @internal\n */\nexport function stopProxy<T>(state: ProxyState<T>): Set<string> {\n state.isTracking = false;\n return new Set(state.trackedPaths);\n}\n\n/**\n * Create a proxy for an array with property access tracking\n * @internal\n */\nexport function createArrayProxy<T, U>(\n state: ProxyState<T>,\n target: U[],\n path: string,\n depth: number = 0,\n): U[] {\n const proxy = new Proxy(target, {\n get: (arr, prop: string | symbol) => {\n if (typeof prop === 'symbol') {\n return Reflect.get(arr, prop);\n }\n\n const value = Reflect.get(arr, prop);\n\n if (typeof value === 'function') {\n if (!state.boundFunctionsCache) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n state.boundFunctionsCache = new WeakMap<Function, Function>();\n }\n const cached = state.boundFunctionsCache.get(value);\n if (cached) {\n return cached;\n }\n const bound = value.bind(arr);\n state.boundFunctionsCache.set(value, bound);\n return bound;\n }\n\n if (prop === 'length') {\n if (state.isTracking) {\n const fullPath = path ? `${path}.length` : 'length';\n state.trackedPaths.add(fullPath);\n }\n return value;\n }\n\n let fullPath: string;\n if (typeof prop === 'string') {\n const index = Number(prop);\n if (!isNaN(index) && index >= 0) {\n fullPath = path ? `${path}[${index}]` : `[${index}]`;\n } else {\n fullPath = path ? `${path}.${prop}` : prop;\n }\n } else {\n return value;\n }\n\n if (isProxyable(value)) {\n return createInternal(state, value as T, fullPath, depth + 1);\n }\n\n if (state.isTracking) {\n state.trackedPaths.add(fullPath);\n }\n\n return value;\n },\n });\n\n state.proxyCache.set(target, proxy);\n return proxy;\n}\n\n/**\n * Create a proxy for an object with property access tracking\n * @internal\n */\nexport function createInternal<T>(\n state: ProxyState<T>,\n target: T,\n path: string = '',\n depth: number = 0,\n): T {\n if (!state.isTracking || !isProxyable(target)) {\n return target;\n }\n\n if (depth >= state.maxDepth) {\n return target;\n }\n\n if (state.proxyCache.has(target)) {\n return state.proxyCache.get(target);\n }\n\n if (Array.isArray(target)) {\n return createArrayProxy(\n state,\n target as unknown as any[],\n path,\n depth,\n ) as unknown as T;\n }\n\n const proxy = new Proxy(target, {\n get: (obj, prop: string | symbol) => {\n if (typeof prop === 'symbol') {\n return Reflect.get(obj, prop);\n }\n\n const value = Reflect.get(obj, prop);\n\n if (typeof value === 'function') {\n if (!state.boundFunctionsCache) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n state.boundFunctionsCache = new WeakMap<Function, Function>();\n }\n const cached = state.boundFunctionsCache.get(value);\n if (cached) {\n return cached;\n }\n const bound = value.bind(obj);\n state.boundFunctionsCache.set(value, bound);\n return bound;\n }\n\n const fullPath = path ? `${path}.${String(prop)}` : String(prop);\n\n if (typeof prop === 'string' && state.isTracking) {\n if (!prop.startsWith('_') && !prop.startsWith('$$')) {\n state.trackedPaths.add(fullPath);\n }\n }\n\n if (isProxyable(value)) {\n const proxiedValue = createInternal(\n state,\n value as T,\n fullPath,\n depth + 1,\n );\n return proxiedValue;\n }\n\n return value;\n },\n\n has: (obj, prop: string | symbol) => {\n if (typeof prop === 'string' && state.isTracking) {\n const fullPath = path ? `${path}.${prop}` : prop;\n state.trackedPaths.add(fullPath);\n }\n return Reflect.has(obj, prop);\n },\n\n ownKeys: (obj) => {\n if (state.isTracking && path) {\n state.trackedPaths.add(path);\n }\n return Reflect.ownKeys(obj);\n },\n });\n\n state.proxyCache.set(target, proxy);\n return proxy as T;\n}\n\n/**\n * Create a proxy for a target with caching\n * @internal\n */\nexport function createForTarget<T>(state: ProxyState<T>, target: T): T {\n if (state.lastProxiedState === target && state.lastProxy) {\n return state.lastProxy;\n }\n\n state.proxyCache = new WeakMap<object, any>();\n state.boundFunctionsCache = null;\n\n const proxy = createInternal(state, target, '', 0);\n state.lastProxiedState = target;\n state.lastProxy = proxy;\n return proxy;\n}\n\n// =============================================================================\n// DEPENDENCY TRACKER (Path tracking and change detection)\n// =============================================================================\n\n/**\n * @internal\n */\nexport interface PathInfo {\n segments: string[];\n value: any;\n}\n\n/**\n * @internal\n */\nexport interface DependencyState<T> {\n proxyState: ProxyState<T>;\n previousRenderPaths: Set<string>;\n currentRenderPaths: Set<string>;\n pathCache: Map<string, PathInfo>;\n lastCheckedState: T | null;\n lastCheckedValues: Map<string, any>;\n}\n\nfunction isChildPath(child: string, parent: string): boolean {\n if (child === parent) return false;\n return child.startsWith(parent + '.') || child.startsWith(parent + '[');\n}\n\nfunction getArrayParentPath(path: string): string | null {\n if (path.endsWith('.length')) {\n return path.slice(0, -7);\n }\n const arrayIndexMatch = path.match(/^(.+?)\\[\\d+\\]/);\n if (arrayIndexMatch) {\n return arrayIndexMatch[1];\n }\n return null;\n}\n\n/**\n * @internal\n */\nexport function optimizeTrackedPaths(paths: Set<string>): Set<string> {\n if (paths.size === 0) {\n return new Set();\n }\n\n if (paths.size === 1) {\n return new Set(paths);\n }\n\n const sortedPaths = Array.from(paths).sort((a, b) => b.length - a.length);\n const optimized = new Set<string>();\n\n for (const path of sortedPaths) {\n let hasMoreSpecificChild = false;\n\n for (const optimizedPath of optimized) {\n if (isChildPath(optimizedPath, path)) {\n hasMoreSpecificChild = true;\n break;\n }\n }\n\n if (!hasMoreSpecificChild) {\n optimized.add(path);\n }\n }\n\n const arrayParents = new Set<string>();\n for (const path of optimized) {\n const arrayParent = getArrayParentPath(path);\n if (arrayParent) {\n arrayParents.add(arrayParent);\n }\n }\n\n for (const arrayParent of arrayParents) {\n optimized.add(arrayParent);\n }\n\n return optimized;\n}\n\n/**\n * @internal\n */\nexport function createDependencyState<T>(): DependencyState<T> {\n return {\n proxyState: createProxyState<T>(),\n previousRenderPaths: new Set<string>(),\n currentRenderPaths: new Set<string>(),\n pathCache: new Map<string, PathInfo>(),\n lastCheckedState: null,\n lastCheckedValues: new Map<string, any>(),\n };\n}\n\n/**\n * @internal\n */\nexport function startDependency<T>(tracker: DependencyState<T>): void {\n startProxy(tracker.proxyState);\n}\n\n/**\n * @internal\n */\nexport function createDependencyProxy<T>(\n tracker: DependencyState<T>,\n state: T,\n): T {\n return createForTarget(tracker.proxyState, state);\n}\n\n/**\n * @internal\n */\nexport function capturePaths<T>(tracker: DependencyState<T>, state: T): void {\n tracker.previousRenderPaths = tracker.currentRenderPaths;\n\n const rawPaths = stopProxy(tracker.proxyState);\n tracker.currentRenderPaths = optimizeTrackedPaths(rawPaths);\n\n if (\n tracker.previousRenderPaths.size === 0 &&\n tracker.currentRenderPaths.size === 0\n ) {\n return;\n }\n\n const trackedPathsUnion = new Set(tracker.previousRenderPaths);\n for (const path of tracker.currentRenderPaths) {\n trackedPathsUnion.add(path);\n }\n\n const canReuseCache = tracker.lastCheckedState === state;\n\n for (const path of trackedPathsUnion) {\n if (!tracker.pathCache.has(path)) {\n const segments = parsePath(path);\n const value =\n canReuseCache && tracker.lastCheckedValues.has(path)\n ? tracker.lastCheckedValues.get(path)\n : getValueAtPath(state, segments);\n\n tracker.pathCache.set(path, { segments, value });\n } else {\n const info = tracker.pathCache.get(path)!;\n info.value =\n canReuseCache && tracker.lastCheckedValues.has(path)\n ? tracker.lastCheckedValues.get(path)\n : getValueAtPath(state, info.segments);\n }\n }\n\n tracker.lastCheckedValues.clear();\n}\n\n/**\n * @internal\n */\nexport function hasDependencyChanges<T>(\n tracker: DependencyState<T>,\n state: T,\n): boolean {\n if (tracker.pathCache.size === 0) {\n return true;\n }\n\n tracker.lastCheckedValues.clear();\n\n for (const [path, info] of tracker.pathCache.entries()) {\n const currentValue = getValueAtPath(state, info.segments);\n tracker.lastCheckedValues.set(path, currentValue);\n\n if (!Object.is(currentValue, info.value)) {\n tracker.lastCheckedState = state;\n return true;\n }\n }\n\n tracker.lastCheckedState = state;\n return false;\n}\n\n/**\n * @internal\n */\nexport function hasTrackedData<T>(tracker: DependencyState<T>): boolean {\n return (\n tracker.proxyState.trackedPaths.size > 0 ||\n tracker.pathCache.size > 0 ||\n tracker.previousRenderPaths.size > 0\n );\n}\n\n// =============================================================================\n// GETTER TRACKER (Getter execution tracking)\n// =============================================================================\n\n/**\n * @internal\n */\nexport interface GetterState {\n trackedValues: Map<string | symbol, unknown>;\n currentlyAccessing: Set<string | symbol>;\n trackedGetters: Set<string | symbol>;\n isTracking: boolean;\n renderCache: Map<string | symbol, unknown>;\n cacheValid: boolean;\n depth: number;\n visitedBlocs: Set<StateContainerInstance>;\n}\n\nconst descriptorCache = new WeakMap<\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n Function,\n Map<string | symbol, PropertyDescriptor | undefined>\n>();\n\nconst blocProxyCache = new WeakMap<StateContainerInstance>();\n\nconst activeTrackerMap = new WeakMap<StateContainerInstance, GetterState>();\n\nconst MAX_GETTER_DEPTH = BLAC_DEFAULTS.MAX_GETTER_DEPTH;\n\n/**\n * @internal\n */\nexport function getDescriptor(\n obj: any,\n prop: string | symbol,\n): PropertyDescriptor | undefined {\n const constructor = obj.constructor;\n\n let constructorCache = descriptorCache.get(constructor);\n if (constructorCache?.has(prop)) {\n return constructorCache.get(prop);\n }\n\n let current = obj;\n let descriptor: PropertyDescriptor | undefined;\n\n while (current && current !== Object.prototype) {\n descriptor = Object.getOwnPropertyDescriptor(current, prop);\n if (descriptor) {\n break;\n }\n current = Object.getPrototypeOf(current);\n }\n\n if (!constructorCache) {\n constructorCache = new Map();\n descriptorCache.set(constructor, constructorCache);\n }\n constructorCache.set(prop, descriptor);\n\n return descriptor;\n}\n\n/**\n * @internal\n */\nexport function isGetter(obj: any, prop: string | symbol): boolean {\n const descriptor = getDescriptor(obj, prop);\n return descriptor?.get !== undefined;\n}\n\n/**\n * @internal\n */\nexport function createGetterState(): GetterState {\n return {\n trackedValues: new Map(),\n currentlyAccessing: new Set(),\n trackedGetters: new Set(),\n isTracking: false,\n renderCache: new Map(),\n cacheValid: false,\n depth: 0,\n visitedBlocs: new Set(),\n };\n}\n\n/**\n * @internal\n */\nexport function setActiveTracker<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n tracker: GetterState,\n): void {\n activeTrackerMap.set(bloc, tracker);\n}\n\n/**\n * @internal\n */\nexport function clearActiveTracker<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n): void {\n activeTrackerMap.delete(bloc);\n}\n\n/**\n * @internal\n */\nexport function getActiveTracker<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n): GetterState | undefined {\n return activeTrackerMap.get(bloc);\n}\n\n/**\n * @internal\n */\nexport function commitTrackedGetters(tracker: GetterState): void {\n if (tracker.currentlyAccessing.size > 0) {\n tracker.trackedGetters = new Set(tracker.currentlyAccessing);\n }\n tracker.currentlyAccessing.clear();\n}\n\n/**\n * Execute a tracked getter with depth/circular dependency checks and context management.\n * @internal\n */\nfunction executeTrackedGetter<T extends StateContainerInstance>(\n target: T,\n prop: string | symbol,\n tracker: GetterState,\n): unknown {\n tracker.currentlyAccessing.add(prop);\n\n if (tracker.cacheValid && tracker.renderCache.has(prop)) {\n const cachedValue = tracker.renderCache.get(prop);\n tracker.trackedValues.set(prop, cachedValue);\n return cachedValue;\n }\n\n if (tracker.depth >= MAX_GETTER_DEPTH) {\n console.warn(\n `${BLAC_ERROR_PREFIX} Maximum getter depth (${MAX_GETTER_DEPTH}) exceeded. ` +\n `Possible circular dependency in getter \"${String(prop)}\" on ${target.constructor.name}.`,\n );\n return undefined;\n }\n\n if (tracker.visitedBlocs.has(target)) {\n console.warn(\n `${BLAC_ERROR_PREFIX} Circular dependency detected: getter \"${String(prop)}\" on ${target.constructor.name}.`,\n );\n return undefined;\n }\n\n const prevDepth = tracker.depth;\n const prevVisited = new Set(tracker.visitedBlocs);\n\n tracker.depth++;\n tracker.visitedBlocs.add(target);\n\n try {\n const descriptor = getDescriptor(target, prop);\n const value = descriptor!.get!.call(target);\n tracker.trackedValues.set(prop, value);\n return value;\n } catch (error) {\n tracker.currentlyAccessing.delete(prop);\n throw error;\n } finally {\n tracker.depth = prevDepth;\n tracker.visitedBlocs = prevVisited;\n }\n}\n\n/**\n * @internal\n */\nexport function createBlocProxy<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n): TBloc {\n const cached = blocProxyCache.get(bloc);\n if (cached) {\n return cached;\n }\n\n const proxy = new Proxy(bloc, {\n get(target, prop, receiver) {\n const tracker = activeTrackerMap.get(target);\n\n if (tracker?.isTracking && isGetter(target, prop)) {\n return executeTrackedGetter(target, prop, tracker);\n }\n\n return Reflect.get(target, prop, receiver);\n },\n });\n\n blocProxyCache.set(bloc, proxy);\n return proxy;\n}\n\n/**\n * @internal\n */\nexport function hasGetterChanges<TBloc extends StateContainerInstance>(\n bloc: TBloc,\n tracker: GetterState | null,\n): boolean {\n if (!tracker || tracker.trackedGetters.size === 0) {\n return false;\n }\n\n tracker.renderCache.clear();\n\n let hasAnyChange = false;\n\n for (const prop of tracker.trackedGetters) {\n try {\n const descriptor = getDescriptor(bloc, prop);\n if (!descriptor?.get) {\n continue;\n }\n\n const newValue = descriptor.get.call(bloc);\n const oldValue = tracker.trackedValues.get(prop);\n\n tracker.renderCache.set(prop, newValue);\n tracker.trackedValues.set(prop, newValue);\n\n if (!Object.is(newValue, oldValue)) {\n hasAnyChange = true;\n }\n } catch (error) {\n console.warn(\n `${BLAC_ERROR_PREFIX} Getter \"${String(prop)}\" threw error during change detection. Stopping tracking for this getter.`,\n error,\n );\n\n tracker.trackedGetters.delete(prop);\n tracker.trackedValues.delete(prop);\n tracker.cacheValid = false;\n return true;\n }\n }\n\n tracker.cacheValid = true;\n\n return hasAnyChange;\n}\n\n/**\n * @internal\n */\nexport function invalidateRenderCache(tracker: GetterState): void {\n tracker.cacheValid = false;\n}\n\n/**\n * @internal\n */\nexport function resetGetterState(tracker: GetterState): void {\n tracker.trackedValues.clear();\n tracker.currentlyAccessing.clear();\n tracker.trackedGetters.clear();\n tracker.renderCache.clear();\n tracker.cacheValid = false;\n tracker.isTracking = false;\n tracker.depth = 0;\n tracker.visitedBlocs.clear();\n}\n\n// =============================================================================\n// TRACKING PROXY (Combined tracking for watch/waitUntil)\n// =============================================================================\n\n/**\n * State for tracking both state property access and getter access.\n */\nexport interface TrackingProxyState {\n dependencyState: DependencyState<any>;\n getterState: GetterState;\n dependencies: Set<StateContainerInstance>;\n isTracking: boolean;\n}\n\n/**\n * Create a new tracking proxy state.\n */\nexport function createState(): TrackingProxyState {\n return {\n dependencyState: createDependencyState(),\n getterState: createGetterState(),\n dependencies: new Set(),\n isTracking: false,\n };\n}\n\n/**\n * Start tracking on a tracking proxy.\n */\nexport function startTracking(tracker: TrackingProxyState): void {\n tracker.isTracking = true;\n tracker.dependencies.clear();\n tracker.getterState.isTracking = true;\n startDependency(tracker.dependencyState);\n}\n\n/**\n * Stop tracking and collect all dependencies.\n */\nexport function stopTracking(\n tracker: TrackingProxyState,\n bloc: StateContainerInstance,\n): Set<StateContainerInstance> {\n tracker.isTracking = false;\n tracker.getterState.isTracking = false;\n\n capturePaths(tracker.dependencyState, bloc.state);\n commitTrackedGetters(tracker.getterState);\n\n return new Set(tracker.dependencies);\n}\n\n/**\n * Check if tracked state or getters have changed.\n */\nexport function hasChanges(\n tracker: TrackingProxyState,\n bloc: StateContainerInstance,\n): boolean {\n invalidateRenderCache(tracker.getterState);\n\n const stateChanged = hasDependencyChanges(\n tracker.dependencyState,\n bloc.state,\n );\n const getterChanged = hasGetterChanges(bloc, tracker.getterState);\n\n return stateChanged || getterChanged;\n}\n\n/**\n * Create a tracking proxy for a bloc instance.\n * Tracks both state property access and getter access.\n */\nexport function createTrackingProxy<T extends StateContainerInstance>(\n bloc: T,\n tracker: TrackingProxyState,\n): T {\n tracker.dependencies.add(bloc);\n\n const stateProxyCache = new WeakMap<object, any>();\n\n const proxy = new Proxy(bloc, {\n get(target, prop, receiver) {\n if (prop === 'state') {\n if (!tracker.isTracking) {\n return target.state;\n }\n\n const rawState = target.state;\n if (rawState === null || typeof rawState !== 'object') {\n return rawState;\n }\n\n if (stateProxyCache.has(rawState)) {\n return stateProxyCache.get(rawState);\n }\n\n const stateProxy = createDependencyProxy(\n tracker.dependencyState,\n rawState,\n );\n stateProxyCache.set(rawState, stateProxy);\n return stateProxy;\n }\n\n if (typeof prop === 'symbol') {\n return Reflect.get(target, prop, receiver);\n }\n\n const value = Reflect.get(target, prop, receiver);\n\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n if (tracker.isTracking && isGetter(target, prop)) {\n return executeTrackedGetter(target, prop, tracker.getterState);\n }\n\n return value;\n },\n });\n\n return proxy as T;\n}\n","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","import { globalRegistry } from '../core/StateContainerRegistry';\nimport type {\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\n\n/**\n * Resolve all transitive dependencies of a bloc via BFS over `dependencies` maps.\n * Uses cycle detection to avoid infinite loops.\n * @internal\n */\nexport function resolveDependencies(\n bloc: StateContainerInstance,\n): Set<StateContainerInstance> {\n const result = new Set<StateContainerInstance>();\n const visited = new Set<StateContainerConstructor>();\n const queue: StateContainerInstance[] = [bloc];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const [Type, key] of current.dependencies) {\n if (visited.has(Type)) continue;\n visited.add(Type);\n const dep = globalRegistry.ensure(Type, key);\n result.add(dep);\n if (dep.dependencies.size > 0) {\n queue.push(dep);\n }\n }\n }\n\n result.delete(bloc);\n return result;\n}\n"],"mappings":"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"}
{"version":3,"file":"StateContainerRegistry.cjs","names":[],"sources":["../src/plugin/PluginManager.ts","../src/constants.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 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 * Default configuration constants for BlaC\n *\n * Centralized location for all magic numbers and default values.\n */\n\n/**\n * Default configuration constants for BlaC\n */\nexport const BLAC_DEFAULTS = {\n /**\n * Default instance key for shared instances\n */\n DEFAULT_INSTANCE_KEY: 'default',\n\n /**\n * Maximum getter nesting depth (prevents infinite recursion)\n */\n MAX_GETTER_DEPTH: 10,\n\n /**\n * Default cleanup interval for subscriptions (30 seconds)\n */\n CLEANUP_INTERVAL_MS: 30_000,\n\n /**\n * Cleanup interval for weak reference stage (10 seconds)\n */\n WEAKREF_CLEANUP_INTERVAL_MS: 10_000,\n\n /**\n * Default maximum subscriptions per container\n */\n MAX_SUBSCRIPTIONS: 1_000,\n\n /**\n * Maximum subscriptions for high-performance mode\n */\n MAX_SUBSCRIPTIONS_HIGH_PERF: 10_000,\n\n /**\n * Default timeout for pipeline execution (5 seconds)\n */\n PIPELINE_TIMEOUT_MS: 5_000,\n\n /**\n * Cleanup interval for high-performance mode (5 seconds)\n */\n CLEANUP_INTERVAL_HIGH_PERF_MS: 5_000,\n\n /**\n * Maximum number of stages in a pipeline\n */\n MAX_PIPELINE_STAGES: 30,\n} as const;\n\n/**\n * Static property names for StateContainer classes\n * Used for feature flags and configuration on bloc classes\n */\nexport const BLAC_STATIC_PROPS = {\n /**\n * Mark a bloc as isolated (each component gets its own instance)\n */\n ISOLATED: 'isolated',\n\n /**\n * Mark a bloc to never be auto-disposed (kept alive permanently)\n */\n KEEP_ALIVE: 'keepAlive',\n\n /**\n * Exclude a bloc from DevTools reporting (prevents infinite loops)\n */\n EXCLUDE_FROM_DEVTOOLS: '__excludeFromDevTools',\n} as const;\n\n/**\n * ID generation patterns and constants\n */\nexport const BLAC_ID_PATTERNS = {\n /**\n * Prefix for isolated instance keys\n */\n ISOLATED_PREFIX: 'isolated-',\n\n /**\n * Length of generated ID portion (9 characters from base36)\n */\n ID_LENGTH: 9,\n} as const;\n\n/**\n * Standard error message prefix\n */\nexport const BLAC_ERROR_PREFIX = '[BlaC]' as const;\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 { 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 /**\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 * @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 } = {},\n ): InstanceType<T> {\n const { canCreate = true, countRef = true } = 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 return instance;\n }\n\n // Shared: singleton pattern with ref counting\n const instances = this.ensureInstancesMap(Type);\n let entry = instances.get(instanceKey);\n\n // Detect stale disposed entries (disposed directly, not through release)\n if (entry?.instance.isDisposed) {\n instances.delete(instanceKey);\n entry = undefined;\n }\n\n if (entry && countRef) {\n entry.refCount++;\n }\n\n if (entry) {\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 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 countRef: false,\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 });\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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"}
{"version":3,"file":"StateContainerRegistry.js","names":[],"sources":["../src/plugin/PluginManager.ts","../src/constants.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 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 * Default configuration constants for BlaC\n *\n * Centralized location for all magic numbers and default values.\n */\n\n/**\n * Default configuration constants for BlaC\n */\nexport const BLAC_DEFAULTS = {\n /**\n * Default instance key for shared instances\n */\n DEFAULT_INSTANCE_KEY: 'default',\n\n /**\n * Maximum getter nesting depth (prevents infinite recursion)\n */\n MAX_GETTER_DEPTH: 10,\n\n /**\n * Default cleanup interval for subscriptions (30 seconds)\n */\n CLEANUP_INTERVAL_MS: 30_000,\n\n /**\n * Cleanup interval for weak reference stage (10 seconds)\n */\n WEAKREF_CLEANUP_INTERVAL_MS: 10_000,\n\n /**\n * Default maximum subscriptions per container\n */\n MAX_SUBSCRIPTIONS: 1_000,\n\n /**\n * Maximum subscriptions for high-performance mode\n */\n MAX_SUBSCRIPTIONS_HIGH_PERF: 10_000,\n\n /**\n * Default timeout for pipeline execution (5 seconds)\n */\n PIPELINE_TIMEOUT_MS: 5_000,\n\n /**\n * Cleanup interval for high-performance mode (5 seconds)\n */\n CLEANUP_INTERVAL_HIGH_PERF_MS: 5_000,\n\n /**\n * Maximum number of stages in a pipeline\n */\n MAX_PIPELINE_STAGES: 30,\n} as const;\n\n/**\n * Static property names for StateContainer classes\n * Used for feature flags and configuration on bloc classes\n */\nexport const BLAC_STATIC_PROPS = {\n /**\n * Mark a bloc as isolated (each component gets its own instance)\n */\n ISOLATED: 'isolated',\n\n /**\n * Mark a bloc to never be auto-disposed (kept alive permanently)\n */\n KEEP_ALIVE: 'keepAlive',\n\n /**\n * Exclude a bloc from DevTools reporting (prevents infinite loops)\n */\n EXCLUDE_FROM_DEVTOOLS: '__excludeFromDevTools',\n} as const;\n\n/**\n * ID generation patterns and constants\n */\nexport const BLAC_ID_PATTERNS = {\n /**\n * Prefix for isolated instance keys\n */\n ISOLATED_PREFIX: 'isolated-',\n\n /**\n * Length of generated ID portion (9 characters from base36)\n */\n ID_LENGTH: 9,\n} as const;\n\n/**\n * Standard error message prefix\n */\nexport const BLAC_ERROR_PREFIX = '[BlaC]' as const;\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 { 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 /**\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 * @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 } = {},\n ): InstanceType<T> {\n const { canCreate = true, countRef = true } = 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 return instance;\n }\n\n // Shared: singleton pattern with ref counting\n const instances = this.ensureInstancesMap(Type);\n let entry = instances.get(instanceKey);\n\n // Detect stale disposed entries (disposed directly, not through release)\n if (entry?.instance.isDisposed) {\n instances.delete(instanceKey);\n entry = undefined;\n }\n\n if (entry && countRef) {\n entry.refCount++;\n }\n\n if (entry) {\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 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 countRef: false,\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 });\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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"}
const require_resolve_dependencies = require('./resolve-dependencies.cjs');
exports.DependencyManager = require_resolve_dependencies.DependencyManager;
exports.capturePaths = require_resolve_dependencies.capturePaths;
exports.clearActiveTracker = require_resolve_dependencies.clearActiveTracker;
exports.commitTrackedGetters = require_resolve_dependencies.commitTrackedGetters;
exports.createBlocProxy = require_resolve_dependencies.createBlocProxy;
exports.createDependencyProxy = require_resolve_dependencies.createDependencyProxy;
exports.createDependencyState = require_resolve_dependencies.createDependencyState;
exports.createGetterState = require_resolve_dependencies.createGetterState;
exports.hasDependencyChanges = require_resolve_dependencies.hasDependencyChanges;
exports.hasGetterChanges = require_resolve_dependencies.hasGetterChanges;
exports.hasTrackedData = require_resolve_dependencies.hasTrackedData;
exports.invalidateRenderCache = require_resolve_dependencies.invalidateRenderCache;
exports.resolveDependencies = require_resolve_dependencies.resolveDependencies;
exports.setActiveTracker = require_resolve_dependencies.setActiveTracker;
exports.shallowEqual = require_resolve_dependencies.shallowEqual;
exports.startDependency = require_resolve_dependencies.startDependency;
/**
* Tracking Subpath Export
*
* Dependency tracking utilities for framework adapters (React, Vue, etc.).
* Import from '@blac/core/tracking'
*
* @packageDocumentation
*/
export * from './tracking/index';
import { _ as setActiveTracker, a as commitTrackedGetters, c as createDependencyState, g as invalidateRenderCache, h as hasTrackedData, i as clearActiveTracker, l as createGetterState, m as hasGetterChanges, n as DependencyManager, o as createBlocProxy, p as hasDependencyChanges, r as capturePaths, s as createDependencyProxy, t as resolveDependencies, v as startDependency, x as shallowEqual } from "./resolve-dependencies.js";
export { DependencyManager, capturePaths, clearActiveTracker, commitTrackedGetters, createBlocProxy, createDependencyProxy, createDependencyState, createGetterState, hasDependencyChanges, hasGetterChanges, hasTrackedData, invalidateRenderCache, resolveDependencies, setActiveTracker, shallowEqual, startDependency };
//#region src/types/branded.ts
/**
* Create a branded InstanceId from a string
* @param id - The string ID to brand
* @returns Branded InstanceId
*/
function instanceId(id) {
return id;
}
//#endregion
exports.instanceId = instanceId;
//# sourceMappingURL=types.cjs.map
{"version":3,"file":"types.cjs","names":[],"sources":["../src/types/branded.ts"],"sourcesContent":["declare const brand: unique symbol;\n\n/**\n * Utility type for creating branded/nominal types.\n * Prevents accidental type confusion between similar primitive types.\n * @template T - The base type\n * @template B - The brand identifier\n */\nexport type Brand<T, B> = T & { [brand]: B };\n\n/**\n * Branded string type for type-safe IDs.\n * @template B - The brand identifier\n */\nexport type BrandedId<B> = Brand<string, B>;\n\n/**\n * Branded string type for state container instance IDs\n */\nexport type InstanceId = Brand<string, 'InstanceId'>;\n\n/**\n * Create a branded InstanceId from a string\n * @param id - The string ID to brand\n * @returns Branded InstanceId\n */\nexport function instanceId(id: string): InstanceId {\n return id as InstanceId;\n}\n"],"mappings":";;;;;;;AA0BA,SAAgB,WAAW,IAAwB;AACjD,QAAO"}
/**
* Branded Types Subpath Export
*
* Advanced type utilities for creating nominal/branded types.
* Import from '@blac/core/types'
*/
export type { Brand, BrandedId, InstanceId } from './types/branded';
export { instanceId } from './types/branded';
//#region src/types/branded.ts
/**
* Create a branded InstanceId from a string
* @param id - The string ID to brand
* @returns Branded InstanceId
*/
function instanceId(id) {
return id;
}
//#endregion
export { instanceId };
//# sourceMappingURL=types.js.map
{"version":3,"file":"types.js","names":[],"sources":["../src/types/branded.ts"],"sourcesContent":["declare const brand: unique symbol;\n\n/**\n * Utility type for creating branded/nominal types.\n * Prevents accidental type confusion between similar primitive types.\n * @template T - The base type\n * @template B - The brand identifier\n */\nexport type Brand<T, B> = T & { [brand]: B };\n\n/**\n * Branded string type for type-safe IDs.\n * @template B - The brand identifier\n */\nexport type BrandedId<B> = Brand<string, B>;\n\n/**\n * Branded string type for state container instance IDs\n */\nexport type InstanceId = Brand<string, 'InstanceId'>;\n\n/**\n * Create a branded InstanceId from a string\n * @param id - The string ID to brand\n * @returns Branded InstanceId\n */\nexport function instanceId(id: string): InstanceId {\n return id as InstanceId;\n}\n"],"mappings":";;;;;;AA0BA,SAAgB,WAAW,IAAwB;AACjD,QAAO"}
const require_watch = require('./watch.cjs');
const require_resolve_dependencies = require('./resolve-dependencies.cjs');
//#region src/tracking/tracked.ts
/**
* Run a callback while tracking all bloc dependencies accessed.
* Returns both the result and the set of discovered dependencies.
*
* @example
* ```ts
* const { result, dependencies } = tracked(() => {
* const user = ensure(UserBloc);
* return user.fullName; // getter that may access other blocs
* });
* // dependencies contains UserBloc + any blocs accessed in fullName getter
* ```
*/
function tracked(callback, options) {
const tracker = require_resolve_dependencies.createState();
require_resolve_dependencies.startTracking(tracker);
let result;
try {
result = callback();
} finally {
require_resolve_dependencies.stopTracking(tracker, { state: null });
}
const dependencies = new Set(tracker.dependencies);
if (options?.exclude) dependencies.delete(options.exclude);
return {
result,
dependencies
};
}
/**
* Context for running tracked callbacks with bloc proxies.
* Provides methods to create proxies and check for changes.
*/
var TrackedContext = class {
constructor() {
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
this.primaryBlocs = /* @__PURE__ */ new Set();
this.tracker = require_resolve_dependencies.createState();
}
/**
* Get a tracking proxy for a bloc instance.
* The proxy will track state and getter accesses.
*/
proxy(bloc) {
const cached = this.proxiedBlocs.get(bloc);
if (cached) return cached;
const proxied = require_resolve_dependencies.createTrackingProxy(bloc, this.tracker);
this.proxiedBlocs.set(bloc, proxied);
this.primaryBlocs.add(bloc);
return proxied;
}
/**
* Start tracking for a new callback execution.
*/
start() {
require_resolve_dependencies.startTracking(this.tracker);
}
/**
* Stop tracking and get discovered dependencies.
* Excludes primary blocs (those explicitly proxied via proxy()).
*/
stop() {
const allDeps = /* @__PURE__ */ new Set();
for (const bloc of this.primaryBlocs) {
const deps = require_resolve_dependencies.stopTracking(this.tracker, bloc);
for (const dep of deps) if (!this.primaryBlocs.has(dep)) allDeps.add(dep);
}
return allDeps;
}
/**
* Check if any tracked state or getters have changed.
*/
changed() {
for (const bloc of this.primaryBlocs) if (require_resolve_dependencies.hasChanges(this.tracker, bloc)) return true;
return false;
}
/**
* Get all primary blocs (those explicitly proxied).
*/
getPrimaryBlocs() {
return new Set(this.primaryBlocs);
}
/**
* Reset the context for reuse.
*/
reset() {
this.tracker = require_resolve_dependencies.createState();
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
this.primaryBlocs.clear();
}
};
/**
* Create a new tracked context for manual control over tracking.
*/
function createTrackedContext() {
return new TrackedContext();
}
//#endregion
exports.TrackedContext = TrackedContext;
exports.createTrackedContext = createTrackedContext;
exports.instance = require_watch.instance;
exports.tracked = tracked;
exports.watch = require_watch.watch;
//# sourceMappingURL=watch-entry.cjs.map
{"version":3,"file":"watch-entry.cjs","names":["createState","createTrackingProxy","stopTracking","hasChanges"],"sources":["../src/tracking/tracked.ts"],"sourcesContent":["import type { StateContainerInstance } from '../types/utilities';\nimport {\n createState,\n startTracking,\n stopTracking,\n createTrackingProxy,\n hasChanges,\n type TrackingProxyState,\n} from './tracking-proxy';\nimport { DependencyManager } from './dependency-manager';\n\n/**\n * Result of running a tracked callback.\n */\nexport interface TrackedResult<T> {\n result: T;\n dependencies: Set<StateContainerInstance>;\n}\n\n/**\n * Options for the tracked() function.\n */\nexport interface TrackedOptions {\n exclude?: StateContainerInstance;\n}\n\n/**\n * Run a callback while tracking all bloc dependencies accessed.\n * Returns both the result and the set of discovered dependencies.\n *\n * @example\n * ```ts\n * const { result, dependencies } = tracked(() => {\n * const user = ensure(UserBloc);\n * return user.fullName; // getter that may access other blocs\n * });\n * // dependencies contains UserBloc + any blocs accessed in fullName getter\n * ```\n */\nexport function tracked<T>(\n callback: () => T,\n options?: TrackedOptions,\n): TrackedResult<T> {\n const tracker = createState();\n startTracking(tracker);\n\n let result: T;\n try {\n result = callback();\n } finally {\n stopTracking(tracker, { state: null } as any);\n }\n\n const dependencies = new Set(tracker.dependencies);\n\n if (options?.exclude) {\n dependencies.delete(options.exclude);\n }\n\n return { result, dependencies };\n}\n\n/**\n * Context for running tracked callbacks with bloc proxies.\n * Provides methods to create proxies and check for changes.\n */\nexport class TrackedContext {\n private tracker: TrackingProxyState;\n private proxiedBlocs = new WeakMap<\n StateContainerInstance,\n StateContainerInstance\n >();\n private primaryBlocs = new Set<StateContainerInstance>();\n\n constructor() {\n this.tracker = createState();\n }\n\n /**\n * Get a tracking proxy for a bloc instance.\n * The proxy will track state and getter accesses.\n */\n proxy<T extends StateContainerInstance>(bloc: T): T {\n const cached = this.proxiedBlocs.get(bloc);\n if (cached) {\n return cached as T;\n }\n\n const proxied = createTrackingProxy(bloc, this.tracker);\n this.proxiedBlocs.set(bloc, proxied);\n this.primaryBlocs.add(bloc);\n return proxied;\n }\n\n /**\n * Start tracking for a new callback execution.\n */\n start(): void {\n startTracking(this.tracker);\n }\n\n /**\n * Stop tracking and get discovered dependencies.\n * Excludes primary blocs (those explicitly proxied via proxy()).\n */\n stop(): Set<StateContainerInstance> {\n const allDeps = new Set<StateContainerInstance>();\n\n for (const bloc of this.primaryBlocs) {\n const deps = stopTracking(this.tracker, bloc);\n for (const dep of deps) {\n if (!this.primaryBlocs.has(dep)) {\n allDeps.add(dep);\n }\n }\n }\n\n return allDeps;\n }\n\n /**\n * Check if any tracked state or getters have changed.\n */\n changed(): boolean {\n for (const bloc of this.primaryBlocs) {\n if (hasChanges(this.tracker, bloc)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get all primary blocs (those explicitly proxied).\n */\n getPrimaryBlocs(): Set<StateContainerInstance> {\n return new Set(this.primaryBlocs);\n }\n\n /**\n * Reset the context for reuse.\n */\n reset(): void {\n this.tracker = createState();\n this.proxiedBlocs = new WeakMap();\n this.primaryBlocs.clear();\n }\n}\n\n/**\n * Create a new tracked context for manual control over tracking.\n */\nexport function createTrackedContext(): TrackedContext {\n return new TrackedContext();\n}\n\nexport { DependencyManager };\n"],"mappings":";;;;;;;;;;;;;;;;;AAuCA,SAAgB,QACd,UACA,SACkB;CAClB,MAAM,UAAUA,0CAAa;AAC7B,4CAAc,QAAQ;CAEtB,IAAI;AACJ,KAAI;AACF,WAAS,UAAU;WACX;AACR,4CAAa,SAAS,EAAE,OAAO,MAAM,CAAQ;;CAG/C,MAAM,eAAe,IAAI,IAAI,QAAQ,aAAa;AAElD,KAAI,SAAS,QACX,cAAa,OAAO,QAAQ,QAAQ;AAGtC,QAAO;EAAE;EAAQ;EAAc;;;;;;AAOjC,IAAa,iBAAb,MAA4B;CAQ1B,cAAc;sCANS,IAAI,SAGxB;sCACoB,IAAI,KAA6B;AAGtD,OAAK,UAAUA,0CAAa;;;;;;CAO9B,MAAwC,MAAY;EAClD,MAAM,SAAS,KAAK,aAAa,IAAI,KAAK;AAC1C,MAAI,OACF,QAAO;EAGT,MAAM,UAAUC,iDAAoB,MAAM,KAAK,QAAQ;AACvD,OAAK,aAAa,IAAI,MAAM,QAAQ;AACpC,OAAK,aAAa,IAAI,KAAK;AAC3B,SAAO;;;;;CAMT,QAAc;AACZ,6CAAc,KAAK,QAAQ;;;;;;CAO7B,OAAoC;EAClC,MAAM,0BAAU,IAAI,KAA6B;AAEjD,OAAK,MAAM,QAAQ,KAAK,cAAc;GACpC,MAAM,OAAOC,0CAAa,KAAK,SAAS,KAAK;AAC7C,QAAK,MAAM,OAAO,KAChB,KAAI,CAAC,KAAK,aAAa,IAAI,IAAI,CAC7B,SAAQ,IAAI,IAAI;;AAKtB,SAAO;;;;;CAMT,UAAmB;AACjB,OAAK,MAAM,QAAQ,KAAK,aACtB,KAAIC,wCAAW,KAAK,SAAS,KAAK,CAChC,QAAO;AAGX,SAAO;;;;;CAMT,kBAA+C;AAC7C,SAAO,IAAI,IAAI,KAAK,aAAa;;;;;CAMnC,QAAc;AACZ,OAAK,UAAUH,0CAAa;AAC5B,OAAK,+BAAe,IAAI,SAAS;AACjC,OAAK,aAAa,OAAO;;;;;;AAO7B,SAAgB,uBAAuC;AACrD,QAAO,IAAI,gBAAgB"}
import { n as watch, t as instance } from "./watch.js";
import { b as stopTracking, d as createTrackingProxy, f as hasChanges, u as createState, y as startTracking } from "./resolve-dependencies.js";
//#region src/tracking/tracked.ts
/**
* Run a callback while tracking all bloc dependencies accessed.
* Returns both the result and the set of discovered dependencies.
*
* @example
* ```ts
* const { result, dependencies } = tracked(() => {
* const user = ensure(UserBloc);
* return user.fullName; // getter that may access other blocs
* });
* // dependencies contains UserBloc + any blocs accessed in fullName getter
* ```
*/
function tracked(callback, options) {
const tracker = createState();
startTracking(tracker);
let result;
try {
result = callback();
} finally {
stopTracking(tracker, { state: null });
}
const dependencies = new Set(tracker.dependencies);
if (options?.exclude) dependencies.delete(options.exclude);
return {
result,
dependencies
};
}
/**
* Context for running tracked callbacks with bloc proxies.
* Provides methods to create proxies and check for changes.
*/
var TrackedContext = class {
constructor() {
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
this.primaryBlocs = /* @__PURE__ */ new Set();
this.tracker = createState();
}
/**
* Get a tracking proxy for a bloc instance.
* The proxy will track state and getter accesses.
*/
proxy(bloc) {
const cached = this.proxiedBlocs.get(bloc);
if (cached) return cached;
const proxied = createTrackingProxy(bloc, this.tracker);
this.proxiedBlocs.set(bloc, proxied);
this.primaryBlocs.add(bloc);
return proxied;
}
/**
* Start tracking for a new callback execution.
*/
start() {
startTracking(this.tracker);
}
/**
* Stop tracking and get discovered dependencies.
* Excludes primary blocs (those explicitly proxied via proxy()).
*/
stop() {
const allDeps = /* @__PURE__ */ new Set();
for (const bloc of this.primaryBlocs) {
const deps = stopTracking(this.tracker, bloc);
for (const dep of deps) if (!this.primaryBlocs.has(dep)) allDeps.add(dep);
}
return allDeps;
}
/**
* Check if any tracked state or getters have changed.
*/
changed() {
for (const bloc of this.primaryBlocs) if (hasChanges(this.tracker, bloc)) return true;
return false;
}
/**
* Get all primary blocs (those explicitly proxied).
*/
getPrimaryBlocs() {
return new Set(this.primaryBlocs);
}
/**
* Reset the context for reuse.
*/
reset() {
this.tracker = createState();
this.proxiedBlocs = /* @__PURE__ */ new WeakMap();
this.primaryBlocs.clear();
}
};
/**
* Create a new tracked context for manual control over tracking.
*/
function createTrackedContext() {
return new TrackedContext();
}
//#endregion
export { TrackedContext, createTrackedContext, instance, tracked, watch };
//# sourceMappingURL=watch-entry.js.map
{"version":3,"file":"watch-entry.js","names":[],"sources":["../src/tracking/tracked.ts"],"sourcesContent":["import type { StateContainerInstance } from '../types/utilities';\nimport {\n createState,\n startTracking,\n stopTracking,\n createTrackingProxy,\n hasChanges,\n type TrackingProxyState,\n} from './tracking-proxy';\nimport { DependencyManager } from './dependency-manager';\n\n/**\n * Result of running a tracked callback.\n */\nexport interface TrackedResult<T> {\n result: T;\n dependencies: Set<StateContainerInstance>;\n}\n\n/**\n * Options for the tracked() function.\n */\nexport interface TrackedOptions {\n exclude?: StateContainerInstance;\n}\n\n/**\n * Run a callback while tracking all bloc dependencies accessed.\n * Returns both the result and the set of discovered dependencies.\n *\n * @example\n * ```ts\n * const { result, dependencies } = tracked(() => {\n * const user = ensure(UserBloc);\n * return user.fullName; // getter that may access other blocs\n * });\n * // dependencies contains UserBloc + any blocs accessed in fullName getter\n * ```\n */\nexport function tracked<T>(\n callback: () => T,\n options?: TrackedOptions,\n): TrackedResult<T> {\n const tracker = createState();\n startTracking(tracker);\n\n let result: T;\n try {\n result = callback();\n } finally {\n stopTracking(tracker, { state: null } as any);\n }\n\n const dependencies = new Set(tracker.dependencies);\n\n if (options?.exclude) {\n dependencies.delete(options.exclude);\n }\n\n return { result, dependencies };\n}\n\n/**\n * Context for running tracked callbacks with bloc proxies.\n * Provides methods to create proxies and check for changes.\n */\nexport class TrackedContext {\n private tracker: TrackingProxyState;\n private proxiedBlocs = new WeakMap<\n StateContainerInstance,\n StateContainerInstance\n >();\n private primaryBlocs = new Set<StateContainerInstance>();\n\n constructor() {\n this.tracker = createState();\n }\n\n /**\n * Get a tracking proxy for a bloc instance.\n * The proxy will track state and getter accesses.\n */\n proxy<T extends StateContainerInstance>(bloc: T): T {\n const cached = this.proxiedBlocs.get(bloc);\n if (cached) {\n return cached as T;\n }\n\n const proxied = createTrackingProxy(bloc, this.tracker);\n this.proxiedBlocs.set(bloc, proxied);\n this.primaryBlocs.add(bloc);\n return proxied;\n }\n\n /**\n * Start tracking for a new callback execution.\n */\n start(): void {\n startTracking(this.tracker);\n }\n\n /**\n * Stop tracking and get discovered dependencies.\n * Excludes primary blocs (those explicitly proxied via proxy()).\n */\n stop(): Set<StateContainerInstance> {\n const allDeps = new Set<StateContainerInstance>();\n\n for (const bloc of this.primaryBlocs) {\n const deps = stopTracking(this.tracker, bloc);\n for (const dep of deps) {\n if (!this.primaryBlocs.has(dep)) {\n allDeps.add(dep);\n }\n }\n }\n\n return allDeps;\n }\n\n /**\n * Check if any tracked state or getters have changed.\n */\n changed(): boolean {\n for (const bloc of this.primaryBlocs) {\n if (hasChanges(this.tracker, bloc)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get all primary blocs (those explicitly proxied).\n */\n getPrimaryBlocs(): Set<StateContainerInstance> {\n return new Set(this.primaryBlocs);\n }\n\n /**\n * Reset the context for reuse.\n */\n reset(): void {\n this.tracker = createState();\n this.proxiedBlocs = new WeakMap();\n this.primaryBlocs.clear();\n }\n}\n\n/**\n * Create a new tracked context for manual control over tracking.\n */\nexport function createTrackedContext(): TrackedContext {\n return new TrackedContext();\n}\n\nexport { DependencyManager };\n"],"mappings":";;;;;;;;;;;;;;;;;AAuCA,SAAgB,QACd,UACA,SACkB;CAClB,MAAM,UAAU,aAAa;AAC7B,eAAc,QAAQ;CAEtB,IAAI;AACJ,KAAI;AACF,WAAS,UAAU;WACX;AACR,eAAa,SAAS,EAAE,OAAO,MAAM,CAAQ;;CAG/C,MAAM,eAAe,IAAI,IAAI,QAAQ,aAAa;AAElD,KAAI,SAAS,QACX,cAAa,OAAO,QAAQ,QAAQ;AAGtC,QAAO;EAAE;EAAQ;EAAc;;;;;;AAOjC,IAAa,iBAAb,MAA4B;CAQ1B,cAAc;sCANS,IAAI,SAGxB;sCACoB,IAAI,KAA6B;AAGtD,OAAK,UAAU,aAAa;;;;;;CAO9B,MAAwC,MAAY;EAClD,MAAM,SAAS,KAAK,aAAa,IAAI,KAAK;AAC1C,MAAI,OACF,QAAO;EAGT,MAAM,UAAU,oBAAoB,MAAM,KAAK,QAAQ;AACvD,OAAK,aAAa,IAAI,MAAM,QAAQ;AACpC,OAAK,aAAa,IAAI,KAAK;AAC3B,SAAO;;;;;CAMT,QAAc;AACZ,gBAAc,KAAK,QAAQ;;;;;;CAO7B,OAAoC;EAClC,MAAM,0BAAU,IAAI,KAA6B;AAEjD,OAAK,MAAM,QAAQ,KAAK,cAAc;GACpC,MAAM,OAAO,aAAa,KAAK,SAAS,KAAK;AAC7C,QAAK,MAAM,OAAO,KAChB,KAAI,CAAC,KAAK,aAAa,IAAI,IAAI,CAC7B,SAAQ,IAAI,IAAI;;AAKtB,SAAO;;;;;CAMT,UAAmB;AACjB,OAAK,MAAM,QAAQ,KAAK,aACtB,KAAI,WAAW,KAAK,SAAS,KAAK,CAChC,QAAO;AAGX,SAAO;;;;;CAMT,kBAA+C;AAC7C,SAAO,IAAI,IAAI,KAAK,aAAa;;;;;CAMnC,QAAc;AACZ,OAAK,UAAU,aAAa;AAC5B,OAAK,+BAAe,IAAI,SAAS;AACjC,OAAK,aAAa,OAAO;;;;;;AAO7B,SAAgB,uBAAuC;AACrD,QAAO,IAAI,gBAAgB"}
{"version":3,"file":"watch.cjs","names":["globalRegistry","BLAC_DEFAULTS","createState","createTrackingProxy","DependencyManager","stopTracking","resolveDependencies"],"sources":["../src/registry/ensure.ts","../src/watch/watch.ts"],"sourcesContent":["import { globalRegistry } from '../core/StateContainerRegistry';\nimport type { StateContainerConstructor } from '../types/utilities';\n\nexport function ensure<T extends StateContainerConstructor>(\n BlocClass: T,\n instanceKey?: string,\n): InstanceType<T> {\n return globalRegistry.ensure(BlocClass, instanceKey);\n}\n","import { ensure } from '../registry';\nimport type {\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\nimport { BLAC_DEFAULTS } from '../constants';\nimport {\n createState,\n startTracking,\n stopTracking,\n createTrackingProxy,\n type TrackingProxyState,\n} from '../tracking/tracking-proxy';\nimport { DependencyManager } from '../tracking/dependency-manager';\nimport { resolveDependencies } from '../tracking/resolve-dependencies';\n\nconst STOP: unique symbol = Symbol('watch.STOP');\n\nconst BLOC_REF_MARKER = Symbol('BlocRef');\n\n/**\n * Reference to a specific bloc instance by class and instance ID.\n */\nexport interface BlocRef<T extends StateContainerConstructor> {\n [BLOC_REF_MARKER]: true;\n blocClass: T;\n instanceId: string;\n}\n\n/**\n * Create a reference to a specific bloc instance.\n *\n * @example\n * ```ts\n * watch(instance(UserBloc, 'user-123'), (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n */\nexport function instance<T extends StateContainerConstructor>(\n BlocClass: T,\n instanceId: string,\n): BlocRef<T> {\n return {\n [BLOC_REF_MARKER]: true,\n blocClass: BlocClass,\n instanceId,\n };\n}\n\nfunction isBlocRef(\n input: unknown,\n): input is BlocRef<StateContainerConstructor> {\n return (\n typeof input === 'object' && input !== null && BLOC_REF_MARKER in input\n );\n}\n\ntype BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;\n\ntype ExtractInstance<T> =\n T extends BlocRef<infer C>\n ? InstanceType<C>\n : T extends StateContainerConstructor\n ? InstanceType<T>\n : never;\n\ntype ExtractInstances<T extends readonly BlocInput[]> = {\n [K in keyof T]: ExtractInstance<T[K]>;\n};\n\ntype StopSymbol = typeof STOP;\n\n/**\n * Watch function signature for single bloc.\n */\nexport interface WatchSingleFn {\n <T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Watch function signature for multiple blocs.\n */\nexport interface WatchMultipleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Combined watch function type.\n */\nexport interface WatchFn extends WatchSingleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n}\n\nfunction resolveBloc(input: BlocInput): StateContainerInstance {\n if (isBlocRef(input)) {\n return ensure(input.blocClass, input.instanceId);\n }\n return ensure(input, BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY);\n}\n\nfunction isArray(input: unknown): input is readonly BlocInput[] {\n return Array.isArray(input);\n}\n\n/**\n * Watch one or more blocs for state changes.\n * Automatically tracks state property and getter accesses.\n *\n * @example Single bloc\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * console.log(userBloc.state.name);\n * console.log(userBloc.fullName); // getter also tracked\n * });\n * ```\n *\n * @example Multiple blocs\n * ```ts\n * const unwatch = watch(\n * [UserBloc, SettingsBloc] as const,\n * ([userBloc, settingsBloc]) => {\n * console.log(userBloc.state.name, settingsBloc.state.theme);\n * }\n * );\n * ```\n *\n * @example With specific instance\n * ```ts\n * const unwatch = watch(\n * instance(UserBloc, 'user-123'),\n * (userBloc) => {\n * console.log(userBloc.state.name);\n * }\n * );\n * ```\n *\n * @example Stop watching from callback\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * if (userBloc.state.done) {\n * return watch.STOP;\n * }\n * });\n * ```\n */\nfunction watchImpl<T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl<T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl(\n blocsOrBloc: BlocInput | readonly BlocInput[],\n callback: (blocsOrBloc: any) => void | StopSymbol,\n): () => void {\n const isSingle = !isArray(blocsOrBloc);\n const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;\n\n const instances = inputs.map(resolveBloc);\n\n const tracker: TrackingProxyState = createState();\n const proxiedInstances = instances.map((inst) =>\n createTrackingProxy(inst, tracker),\n );\n\n const externalDepsManager = new DependencyManager();\n\n let disposed = false;\n const primarySubscriptions: (() => void)[] = [];\n\n const cleanup = () => {\n if (disposed) return;\n disposed = true;\n primarySubscriptions.forEach((unsub) => unsub());\n externalDepsManager.cleanup();\n };\n\n const runCallback = () => {\n if (disposed) return;\n\n startTracking(tracker);\n\n let result: void | StopSymbol;\n try {\n const arg = isSingle ? proxiedInstances[0] : proxiedInstances;\n result = callback(arg);\n } finally {\n const externalDeps = new Set<StateContainerInstance>();\n for (const inst of instances) {\n const deps = stopTracking(tracker, inst);\n for (const dep of deps) {\n externalDeps.add(dep);\n }\n for (const dep of resolveDependencies(inst)) {\n externalDeps.add(dep);\n }\n }\n\n for (const inst of instances) {\n externalDeps.delete(inst);\n }\n\n externalDepsManager.sync(externalDeps, runCallback);\n }\n\n if (result === STOP) {\n cleanup();\n }\n };\n\n const onChange = () => {\n if (disposed) return;\n runCallback();\n };\n\n for (const inst of instances) {\n primarySubscriptions.push(inst.subscribe(onChange));\n }\n\n runCallback();\n\n return cleanup;\n}\n\nexport const watch: WatchFn = Object.assign(watchImpl, { STOP }) as WatchFn;\n"],"mappings":";;;;AAGA,SAAgB,OACd,WACA,aACiB;AACjB,QAAOA,8CAAe,OAAO,WAAW,YAAY;;;;;ACStD,MAAM,OAAsB,OAAO,aAAa;AAEhD,MAAM,kBAAkB,OAAO,UAAU;;;;;;;;;;;AAqBzC,SAAgB,SACd,WACA,YACY;AACZ,QAAO;GACJ,kBAAkB;EACnB,WAAW;EACX;EACD;;AAGH,SAAS,UACP,OAC6C;AAC7C,QACE,OAAO,UAAU,YAAY,UAAU,QAAQ,mBAAmB;;AAqDtE,SAAS,YAAY,OAA0C;AAC7D,KAAI,UAAU,MAAM,CAClB,QAAO,OAAO,MAAM,WAAW,MAAM,WAAW;AAElD,QAAO,OAAO,OAAOC,6CAAc,qBAAqB;;AAG1D,SAAS,QAAQ,OAA+C;AAC9D,QAAO,MAAM,QAAQ,MAAM;;AAsD7B,SAAS,UACP,aACA,UACY;CACZ,MAAM,WAAW,CAAC,QAAQ,YAAY;CAGtC,MAAM,aAFS,WAAW,CAAC,YAAY,GAAG,aAEjB,IAAI,YAAY;CAEzC,MAAM,UAA8BC,0CAAa;CACjD,MAAM,mBAAmB,UAAU,KAAK,SACtCC,iDAAoB,MAAM,QAAQ,CACnC;CAED,MAAM,sBAAsB,IAAIC,gDAAmB;CAEnD,IAAI,WAAW;CACf,MAAM,uBAAuC,EAAE;CAE/C,MAAM,gBAAgB;AACpB,MAAI,SAAU;AACd,aAAW;AACX,uBAAqB,SAAS,UAAU,OAAO,CAAC;AAChD,sBAAoB,SAAS;;CAG/B,MAAM,oBAAoB;AACxB,MAAI,SAAU;AAEd,6CAAc,QAAQ;EAEtB,IAAI;AACJ,MAAI;AAEF,YAAS,SADG,WAAW,iBAAiB,KAAK,iBACvB;YACd;GACR,MAAM,+BAAe,IAAI,KAA6B;AACtD,QAAK,MAAM,QAAQ,WAAW;IAC5B,MAAM,OAAOC,0CAAa,SAAS,KAAK;AACxC,SAAK,MAAM,OAAO,KAChB,cAAa,IAAI,IAAI;AAEvB,SAAK,MAAM,OAAOC,iDAAoB,KAAK,CACzC,cAAa,IAAI,IAAI;;AAIzB,QAAK,MAAM,QAAQ,UACjB,cAAa,OAAO,KAAK;AAG3B,uBAAoB,KAAK,cAAc,YAAY;;AAGrD,MAAI,WAAW,KACb,UAAS;;CAIb,MAAM,iBAAiB;AACrB,MAAI,SAAU;AACd,eAAa;;AAGf,MAAK,MAAM,QAAQ,UACjB,sBAAqB,KAAK,KAAK,UAAU,SAAS,CAAC;AAGrD,cAAa;AAEb,QAAO;;AAGT,MAAa,QAAiB,OAAO,OAAO,WAAW,EAAE,MAAM,CAAC"}
{"version":3,"file":"watch.js","names":[],"sources":["../src/registry/ensure.ts","../src/watch/watch.ts"],"sourcesContent":["import { globalRegistry } from '../core/StateContainerRegistry';\nimport type { StateContainerConstructor } from '../types/utilities';\n\nexport function ensure<T extends StateContainerConstructor>(\n BlocClass: T,\n instanceKey?: string,\n): InstanceType<T> {\n return globalRegistry.ensure(BlocClass, instanceKey);\n}\n","import { ensure } from '../registry';\nimport type {\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\nimport { BLAC_DEFAULTS } from '../constants';\nimport {\n createState,\n startTracking,\n stopTracking,\n createTrackingProxy,\n type TrackingProxyState,\n} from '../tracking/tracking-proxy';\nimport { DependencyManager } from '../tracking/dependency-manager';\nimport { resolveDependencies } from '../tracking/resolve-dependencies';\n\nconst STOP: unique symbol = Symbol('watch.STOP');\n\nconst BLOC_REF_MARKER = Symbol('BlocRef');\n\n/**\n * Reference to a specific bloc instance by class and instance ID.\n */\nexport interface BlocRef<T extends StateContainerConstructor> {\n [BLOC_REF_MARKER]: true;\n blocClass: T;\n instanceId: string;\n}\n\n/**\n * Create a reference to a specific bloc instance.\n *\n * @example\n * ```ts\n * watch(instance(UserBloc, 'user-123'), (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n */\nexport function instance<T extends StateContainerConstructor>(\n BlocClass: T,\n instanceId: string,\n): BlocRef<T> {\n return {\n [BLOC_REF_MARKER]: true,\n blocClass: BlocClass,\n instanceId,\n };\n}\n\nfunction isBlocRef(\n input: unknown,\n): input is BlocRef<StateContainerConstructor> {\n return (\n typeof input === 'object' && input !== null && BLOC_REF_MARKER in input\n );\n}\n\ntype BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;\n\ntype ExtractInstance<T> =\n T extends BlocRef<infer C>\n ? InstanceType<C>\n : T extends StateContainerConstructor\n ? InstanceType<T>\n : never;\n\ntype ExtractInstances<T extends readonly BlocInput[]> = {\n [K in keyof T]: ExtractInstance<T[K]>;\n};\n\ntype StopSymbol = typeof STOP;\n\n/**\n * Watch function signature for single bloc.\n */\nexport interface WatchSingleFn {\n <T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Watch function signature for multiple blocs.\n */\nexport interface WatchMultipleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Combined watch function type.\n */\nexport interface WatchFn extends WatchSingleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n}\n\nfunction resolveBloc(input: BlocInput): StateContainerInstance {\n if (isBlocRef(input)) {\n return ensure(input.blocClass, input.instanceId);\n }\n return ensure(input, BLAC_DEFAULTS.DEFAULT_INSTANCE_KEY);\n}\n\nfunction isArray(input: unknown): input is readonly BlocInput[] {\n return Array.isArray(input);\n}\n\n/**\n * Watch one or more blocs for state changes.\n * Automatically tracks state property and getter accesses.\n *\n * @example Single bloc\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * console.log(userBloc.state.name);\n * console.log(userBloc.fullName); // getter also tracked\n * });\n * ```\n *\n * @example Multiple blocs\n * ```ts\n * const unwatch = watch(\n * [UserBloc, SettingsBloc] as const,\n * ([userBloc, settingsBloc]) => {\n * console.log(userBloc.state.name, settingsBloc.state.theme);\n * }\n * );\n * ```\n *\n * @example With specific instance\n * ```ts\n * const unwatch = watch(\n * instance(UserBloc, 'user-123'),\n * (userBloc) => {\n * console.log(userBloc.state.name);\n * }\n * );\n * ```\n *\n * @example Stop watching from callback\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * if (userBloc.state.done) {\n * return watch.STOP;\n * }\n * });\n * ```\n */\nfunction watchImpl<T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl<T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl(\n blocsOrBloc: BlocInput | readonly BlocInput[],\n callback: (blocsOrBloc: any) => void | StopSymbol,\n): () => void {\n const isSingle = !isArray(blocsOrBloc);\n const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;\n\n const instances = inputs.map(resolveBloc);\n\n const tracker: TrackingProxyState = createState();\n const proxiedInstances = instances.map((inst) =>\n createTrackingProxy(inst, tracker),\n );\n\n const externalDepsManager = new DependencyManager();\n\n let disposed = false;\n const primarySubscriptions: (() => void)[] = [];\n\n const cleanup = () => {\n if (disposed) return;\n disposed = true;\n primarySubscriptions.forEach((unsub) => unsub());\n externalDepsManager.cleanup();\n };\n\n const runCallback = () => {\n if (disposed) return;\n\n startTracking(tracker);\n\n let result: void | StopSymbol;\n try {\n const arg = isSingle ? proxiedInstances[0] : proxiedInstances;\n result = callback(arg);\n } finally {\n const externalDeps = new Set<StateContainerInstance>();\n for (const inst of instances) {\n const deps = stopTracking(tracker, inst);\n for (const dep of deps) {\n externalDeps.add(dep);\n }\n for (const dep of resolveDependencies(inst)) {\n externalDeps.add(dep);\n }\n }\n\n for (const inst of instances) {\n externalDeps.delete(inst);\n }\n\n externalDepsManager.sync(externalDeps, runCallback);\n }\n\n if (result === STOP) {\n cleanup();\n }\n };\n\n const onChange = () => {\n if (disposed) return;\n runCallback();\n };\n\n for (const inst of instances) {\n primarySubscriptions.push(inst.subscribe(onChange));\n }\n\n runCallback();\n\n return cleanup;\n}\n\nexport const watch: WatchFn = Object.assign(watchImpl, { STOP }) as WatchFn;\n"],"mappings":";;;;AAGA,SAAgB,OACd,WACA,aACiB;AACjB,QAAO,eAAe,OAAO,WAAW,YAAY;;;;;ACStD,MAAM,OAAsB,OAAO,aAAa;AAEhD,MAAM,kBAAkB,OAAO,UAAU;;;;;;;;;;;AAqBzC,SAAgB,SACd,WACA,YACY;AACZ,QAAO;GACJ,kBAAkB;EACnB,WAAW;EACX;EACD;;AAGH,SAAS,UACP,OAC6C;AAC7C,QACE,OAAO,UAAU,YAAY,UAAU,QAAQ,mBAAmB;;AAqDtE,SAAS,YAAY,OAA0C;AAC7D,KAAI,UAAU,MAAM,CAClB,QAAO,OAAO,MAAM,WAAW,MAAM,WAAW;AAElD,QAAO,OAAO,OAAO,cAAc,qBAAqB;;AAG1D,SAAS,QAAQ,OAA+C;AAC9D,QAAO,MAAM,QAAQ,MAAM;;AAsD7B,SAAS,UACP,aACA,UACY;CACZ,MAAM,WAAW,CAAC,QAAQ,YAAY;CAGtC,MAAM,aAFS,WAAW,CAAC,YAAY,GAAG,aAEjB,IAAI,YAAY;CAEzC,MAAM,UAA8B,aAAa;CACjD,MAAM,mBAAmB,UAAU,KAAK,SACtC,oBAAoB,MAAM,QAAQ,CACnC;CAED,MAAM,sBAAsB,IAAI,mBAAmB;CAEnD,IAAI,WAAW;CACf,MAAM,uBAAuC,EAAE;CAE/C,MAAM,gBAAgB;AACpB,MAAI,SAAU;AACd,aAAW;AACX,uBAAqB,SAAS,UAAU,OAAO,CAAC;AAChD,sBAAoB,SAAS;;CAG/B,MAAM,oBAAoB;AACxB,MAAI,SAAU;AAEd,gBAAc,QAAQ;EAEtB,IAAI;AACJ,MAAI;AAEF,YAAS,SADG,WAAW,iBAAiB,KAAK,iBACvB;YACd;GACR,MAAM,+BAAe,IAAI,KAA6B;AACtD,QAAK,MAAM,QAAQ,WAAW;IAC5B,MAAM,OAAO,aAAa,SAAS,KAAK;AACxC,SAAK,MAAM,OAAO,KAChB,cAAa,IAAI,IAAI;AAEvB,SAAK,MAAM,OAAO,oBAAoB,KAAK,CACzC,cAAa,IAAI,IAAI;;AAIzB,QAAK,MAAM,QAAQ,UACjB,cAAa,OAAO,KAAK;AAG3B,uBAAoB,KAAK,cAAc,YAAY;;AAGrD,MAAI,WAAW,KACb,UAAS;;CAIb,MAAM,iBAAiB;AACrB,MAAI,SAAU;AACd,eAAa;;AAGf,MAAK,MAAM,QAAQ,UACjB,sBAAqB,KAAK,KAAK,UAAU,SAAS,CAAC;AAGrD,cAAa;AAEb,QAAO;;AAGT,MAAa,QAAiB,OAAO,OAAO,WAAW,EAAE,MAAM,CAAC"}

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display