@blac/core 2.1.1 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/StateContainer-CwByTd5L.js +656 -0
- package/dist/StateContainer-CwByTd5L.js.map +1 -0
- package/dist/StateContainer-D2b10eR4.cjs +691 -0
- package/dist/StateContainer-D2b10eR4.cjs.map +1 -0
- package/dist/StateContainerRegistry-B6O6cfJd.cjs +903 -0
- package/dist/StateContainerRegistry-B6O6cfJd.cjs.map +1 -0
- package/dist/StateContainerRegistry-CrTtRX5V.js +772 -0
- package/dist/StateContainerRegistry-CrTtRX5V.js.map +1 -0
- package/dist/constants.d.cts +2 -0
- package/dist/constants.d.ts +2 -0
- package/dist/core/StateContainer.d.ts +7 -1
- package/dist/core/StateContainerRegistry.d.ts +2 -0
- package/dist/core/meta.d.ts +3 -0
- package/dist/core/onActivated.d.ts +10 -0
- package/dist/core/symbols.d.ts +5 -0
- package/dist/decorators/blac.d.ts +7 -0
- package/dist/ensure-CwtQVTam.js +46 -0
- package/dist/ensure-CwtQVTam.js.map +1 -0
- package/dist/ensure-DShrbIYY.cjs +63 -0
- package/dist/ensure-DShrbIYY.cjs.map +1 -0
- package/dist/index.cjs +27 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +25 -4
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +2 -2
- package/dist/internal.js +2 -2
- package/dist/plugin/BlacPlugin.d.ts +3 -1
- package/dist/plugin/PluginManager.d.ts +4 -4
- package/dist/plugins.cjs +5 -5
- package/dist/plugins.cjs.map +1 -1
- package/dist/plugins.js +5 -5
- package/dist/plugins.js.map +1 -1
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/management.d.ts +2 -0
- package/dist/testing.cjs +28 -3
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +9 -1
- package/dist/testing.d.ts +9 -1
- package/dist/testing.js +28 -4
- package/dist/testing.js.map +1 -1
- package/dist/utils/static-props.d.ts +6 -0
- package/dist/watch/watch.d.ts +6 -0
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StateContainerRegistry-CrTtRX5V.js","names":[],"sources":["../src/config.ts","../src/constants.ts","../src/utils/static-props.ts","../src/utils/structural-key.ts","../src/core/symbols.ts","../src/core/StateContainerRegistry.ts"],"sourcesContent":["export type EqualityFn = <S>(prev: S, next: S) => boolean;\n\nexport interface BlacConfig {\n /**\n * Equality check used by `StateContainer.applyState` to skip emits when\n * `prev` and `next` are structurally equal. Default: `shallowEqualState`.\n *\n * Return `true` to skip the emit (states considered equal).\n */\n equality: EqualityFn;\n\n /**\n * Circuit breaker: maximum number of live instances allowed under a single\n * bloc constructor before `acquire` throws. Guards against runaway instance\n * creation — typically an unstable/args-derived key churning out instances\n * that are never disposed (a memory leak that eventually freezes the app).\n *\n * Default: `100000`. Set to `Infinity` (or any non-positive value) to disable.\n */\n maxInstancesPerType: number;\n\n /**\n * Circuit breaker: maximum number of distinct live references (consumers)\n * allowed on a single instance before `acquire` throws. Guards against the\n * other leak shape — consumer cleanup (e.g. `useBloc` unmount `release`)\n * never firing, so refs accumulate without bound on one instance.\n *\n * Default: `100000`. Set to `Infinity` (or any non-positive value) to disable.\n */\n maxRefsPerInstance: number;\n\n /**\n * Dev-only soft circuit breaker: if a single instance emits more than this\n * many *real* state changes within a rolling one-second window, log a single\n * `console.warn`. This is the \"frozen app\" smell — almost always a tight loop\n * (RAF/animation, or an effect that emits on every commit) pushing\n * high-frequency data through bloc state, which then saturates subscribers,\n * plugins (logging/devtools), and the main thread.\n *\n * Heuristic by nature — warns, never throws, since high-frequency state can\n * occasionally be legitimate. No-op in production. Default: `1000`. Set to\n * `Infinity` (or any non-positive value) to disable.\n */\n maxEmitsPerSecond: number;\n\n /**\n * How long an instance created speculatively during a render stays alive\n * without an owner before it is disposed. Covers renders that never commit\n * (SSR, discarded or suspended renders) while giving a time-sliced render\n * time to commit. Default: `5000`.\n */\n unownedSweepDelayMs: number;\n}\n\n/**\n * Default equality: shallow per-key `Object.is` comparison.\n * Falls through to `false` for primitives/null so reference-only state still\n * behaves correctly.\n */\nexport const shallowEqualState: EqualityFn = (prev, next) => {\n if (Object.is(prev, next)) return true;\n if (typeof prev !== 'object' || prev === null) return false;\n if (typeof next !== 'object' || next === null) return false;\n\n // `for...in` visits enumerable keys without allocating key arrays; state\n // objects are plain, so own and enumerable coincide.\n const p = prev as Record<string, unknown>;\n const n = next as Record<string, unknown>;\n let prevCount = 0;\n for (const key in p) {\n prevCount++;\n if (!Object.is(p[key], n[key])) return false;\n }\n let nextCount = 0;\n for (const _ in n) nextCount++;\n return prevCount === nextCount;\n};\n\nconst defaultConfig: BlacConfig = {\n equality: shallowEqualState,\n maxInstancesPerType: 100000,\n maxRefsPerInstance: 100000,\n maxEmitsPerSecond: 1000,\n unownedSweepDelayMs: 5000,\n};\n\nlet globalConfig: BlacConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for `@blac/core`.\n *\n * @example\n * ```ts\n * import { configureBlac, shallowEqualState } from '@blac/core';\n *\n * // Swap in a deep-equality check for all blocs\n * configureBlac({ equality: myDeepEqual });\n * ```\n */\nexport function configureBlac(config: Partial<BlacConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacConfig(): BlacConfig {\n return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacConfig(): void {\n globalConfig = { ...defaultConfig };\n}\n","/** Static property names used for feature flags and configuration on bloc classes. */\nexport const BLAC_STATIC_PROPS = {\n /** Mark a bloc to never be auto-disposed (kept alive permanently). */\n KEEP_ALIVE: 'keepAlive',\n\n /** Give each React `useBloc` mount its own private instance. */\n ISOLATED: 'isolated',\n\n /** Exclude a bloc from DevTools reporting (prevents infinite loops). */\n EXCLUDE_FROM_DEVTOOLS: '__excludeFromDevTools',\n\n /**\n * Per-class equality function used to short-circuit `emit`/`patch` when the\n * new state is structurally equal to the previous state. Falls back to the\n * global `configureBlac({ equality })` value when unset.\n */\n EQUALITY: '__equality',\n\n /**\n * Per-class key function: `static key = (args) => string`.\n * When set, the registry calls `Type.key(args)` to derive the instance key\n * instead of using a structural hash of `args`. Allows blocs to ignore\n * non-identity fields (e.g., `readonly` flags) while still keying by id.\n */\n KEY: 'key',\n\n /**\n * Explicit, minification-safe identity for a bloc class: `static blacName = '...'`.\n * When unset, identity falls back to `constructor.name`.\n */\n BLAC_NAME: 'blacName',\n} as const;\n\nexport const BLAC_ERROR_PREFIX = '[BlaC]' as const;\n\nexport function readNodeEnv(): string | undefined {\n try {\n return process.env.NODE_ENV;\n } catch {\n return undefined;\n }\n}\n\nconst nodeEnv = readNodeEnv();\n\n/**\n * True only when `process.env.NODE_ENV` is defined and not `'production'`.\n *\n * Dev-only checks (emit-rate breaker, deps collision scan, args-mismatch key)\n * cost real work per emit/acquire, so an environment that says nothing about\n * its mode — plain ESM in the browser, Deno, a bundle without a `process`\n * shim — is treated as production. Bundlers that define `process.env.NODE_ENV`\n * still constant-fold the read.\n */\nexport const IS_DEV: boolean =\n nodeEnv !== undefined && nodeEnv !== 'production';\n","import { BLAC_STATIC_PROPS } from '../constants';\nimport type { EqualityFn } from '../config';\nimport { StateContainerConstructor } from '../types/utilities';\n\n/**\n * Get a static property from a class constructor, walking the prototype\n * chain so subclasses inherit the value unless they define their own.\n */\nexport function getStaticProp<\n V,\n T extends StateContainerConstructor = StateContainerConstructor,\n>(Type: T, propName: string): V | undefined {\n return (Type as any)[propName];\n}\n\n/**\n * Get a static property declared directly on `Type`, ignoring the prototype\n * chain, so subclasses never inherit a base class's value.\n */\nexport function getOwnStaticProp<\n V,\n T extends StateContainerConstructor = StateContainerConstructor,\n>(Type: T, propName: string): V | undefined {\n return Object.hasOwn(Type, propName) ? (Type as any)[propName] : undefined;\n}\n\n/**\n * Whether a class is marked `keepAlive` (never auto-disposed at ref count 0).\n * Inherited: a subclass keeps a base class's `keepAlive` unless overridden.\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 * Whether a class is marked `isolated` (each `useBloc` mount gets its own\n * instance). Inherited: a subclass keeps a base class's `isolated` unless\n * overridden.\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 * Whether a class is excluded from DevTools (avoids DevTools tracking itself\n * into an infinite loop). Inherited unless overridden by a subclass.\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\n/**\n * Get the per-class equality function set via `@blac({ equality })`, if any.\n * Inherited: a subclass keeps a base class's equality fn unless overridden.\n */\nexport function getClassEquality<T extends StateContainerConstructor>(\n Type: T,\n): EqualityFn | undefined {\n const fn = getStaticProp<EqualityFn>(Type, BLAC_STATIC_PROPS.EQUALITY);\n return typeof fn === 'function' ? fn : undefined;\n}\n\n/**\n * Get a class's minification-safe identity name (`static blacName`), falling\n * back to `Type.name`. Own only: a subclass never inherits a base class's\n * explicit `blacName`, since that would collapse two distinct blocs onto one\n * identity.\n */\nexport function getBlacName<T extends StateContainerConstructor>(\n Type: T,\n): string {\n return (\n getOwnStaticProp<string>(Type, BLAC_STATIC_PROPS.BLAC_NAME) ?? Type.name\n );\n}\n\n/**\n * Get the per-class key function set via `@blac({ key })` or `static key = …`.\n * Own only: a subclass never inherits a base class's `key`, since a\n * different `Args` shape would derive the wrong instance key.\n */\nexport function getClassKey(\n Type: unknown,\n): ((args: any) => string) | undefined {\n const fn = getOwnStaticProp<(args: any) => string>(\n Type as StateContainerConstructor,\n BLAC_STATIC_PROPS.KEY,\n );\n return typeof fn === 'function' ? fn : undefined;\n}\n","import { IS_DEV } from '../constants';\n\nexport const DEFAULT_STRUCTURAL_KEY = 'default';\n\n/**\n * Produce a stable string key for serializable args.\n * - `undefined` / `void` args → `'default'` sentinel (no-args blocs stay on the default key).\n * - Object keys are sorted for order-independence.\n * - Arrays keep their insertion order.\n * - Functions throw — they must be passed via `deps`, not `args`.\n * - JSON semantics otherwise: `{ a: undefined }` equals `{}`, and `NaN` and\n * `Infinity` serialize as `null`.\n * - Object args are memoized by identity; callers on hot paths (`resolveKey`,\n * `depend`) re-resolve the same args object on every call. Mutating an args\n * object after first use therefore keeps its old key.\n */\nconst keyCache = new WeakMap<object, string>();\n\nexport function structuralKey(args: unknown): string {\n if (args === undefined || args === null) {\n return DEFAULT_STRUCTURAL_KEY;\n }\n\n if (typeof args === 'object') {\n const cached = keyCache.get(args);\n if (cached !== undefined) return cached;\n const key = serialize(args);\n keyCache.set(args, key);\n return key;\n }\n\n return serialize(args);\n}\n\nfunction serialize(args: unknown): string {\n return JSON.stringify(args, function (_k, v) {\n if (typeof v === 'function') {\n throw new Error(\n `[blac] args must be serializable; put refs/callbacks in \\`deps\\` ` +\n `(found a function at key \"${_k || '(root)'}\")`,\n );\n }\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n if (IS_DEV && !isPlainObject(v)) {\n throw new Error(\n `[blac] args must be plain data; put refs/instances in \\`deps\\` ` +\n `(found a ${v.constructor?.name ?? 'non-plain object'} at key \"${_k || '(root)'}\")`,\n );\n }\n return Object.keys(v)\n .sort()\n .reduce(\n (o, k) => {\n (o as any)[k] = (v as any)[k];\n return o;\n },\n {} as Record<string, unknown>,\n );\n }\n return v;\n });\n}\n\nfunction isPlainObject(value: object): boolean {\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n","/**\n * @internal Apply one owner's (consumer's) deps slice to an instance.\n * Called by framework adapters (e.g. `@blac/react` useBloc) — not public API.\n */\nexport const APPLY_DEPS = Symbol('blac.applyDeps');\n\n/**\n * @internal Withdraw one owner's entire deps slice (consumer unmounted).\n * Called by framework adapters — not public API.\n */\nexport const REMOVE_DEPS_OWNER = Symbol('blac.removeDepsOwner');\n\n/**\n * @internal Subscribe to this specific instance's own disposal, bypassing\n * the global registry `'disposed'` event. Called by `watch()` — not public\n * API.\n */\nexport const ON_DISPOSE = Symbol('blac.onDispose');\n\n/**\n * @internal Register a callback that runs on each activation with that\n * activation's signal. Called by `onActivated()` — not public API.\n */\nexport const ON_ACTIVATED = Symbol('blac.onActivated');\n\n/**\n * @internal Symbol-keyed configuration entry point on `StateContainer`.\n * Writes the instance's identity fields (`_name`/`_debug`/`_instanceId`),\n * resolves per-class equality, emits the registry `created` event, and runs\n * `init()` once.\n *\n * Framework-only — the registry (`StateContainerRegistry.ensure`) and testing\n * helpers are the sole callers, mirroring the `APPLY_DEPS` precedent.\n */\nexport const INIT_CONFIG = Symbol('blac.initConfig');\n\n/**\n * @internal Run `fn` with `state` temporarily reporting a render's tracking\n * proxy, so getters record the paths they read. Called by `@blac/react`'s\n * `buildTrackedProxy` — not public API. Getters run with `this` bound to the\n * real instance, so ES `#private` works in user blocs.\n */\nexport const WITH_TRACKED_STATE = Symbol('blac.withTrackedState');\n\n/**\n * @internal Drive the activation lifecycle from the registry's 0↔1 ownership\n * transition. Owns the per-instance AbortController so `onActivate`'s signal\n * aborts on the matching deactivation and on dispose.\n *\n * Framework-only — `StateContainerRegistry` is the sole caller.\n */\nexport const SET_ACTIVE = Symbol('blac.setActive');\n\n/**\n * @internal Insert an instance entry directly, bypassing acquire/release.\n * Called by the testing helpers — not public API.\n */\nexport const INSERT_INSTANCE = Symbol('blac.insertInstance');\n","import type {\n HydrationStatus,\n StateContainer,\n StateContainerConfig,\n} from './StateContainer';\nimport { BLAC_ERROR_PREFIX, IS_DEV } from '../constants';\nimport { getBlacConfig } from '../config';\nimport {\n isKeepAliveClass,\n getClassKey,\n getBlacName,\n} from '../utils/static-props';\nimport { structuralKey, DEFAULT_STRUCTURAL_KEY } from '../utils/structural-key';\nimport {\n InstanceReadonlyState,\n StateContainerConstructor,\n} from '../types/utilities';\nimport { INIT_CONFIG, INSERT_INSTANCE, SET_ACTIVE } from './symbols';\n\n/**\n * Entry in the instance registry.\n * @typeParam T - Instance type\n * @internal\n */\nexport interface InstanceEntry<T = any> {\n instance: T;\n key: string;\n /** refId to acquire count. */\n refs: Map<string, number>;\n /** Args from creation, for the dev arg-mismatch warning. */\n args?: unknown;\n argsKey?: string;\n /** `depend()`-owners holding this instance. */\n dependents?: Set<StateContainer<any, any, any>>;\n sweepTimer?: ReturnType<typeof setTimeout>;\n}\n\nconst EMPTY_INSTANCES_MAP: ReadonlyMap<string, InstanceEntry> = new Map();\n\n/**\n * Lifecycle events emitted by the registry\n * @public\n */\nexport type LifecycleEvent =\n | 'created'\n | 'stateChanged'\n | 'disposed'\n | 'refAcquired'\n | 'refReleased'\n | 'depsChanged'\n | 'hydrationChanged'\n | 'activated'\n | 'deactivated';\n\n/**\n * Listener function type for each lifecycle event\n * @typeParam E - The lifecycle event type\n * @public\n */\nexport type LifecycleListener<E extends LifecycleEvent> = E extends 'created'\n ? (container: StateContainer<any, any, any>) => void\n : E extends 'stateChanged'\n ? (\n container: StateContainer<any, any, any>,\n previousState: Readonly<Record<string, unknown>>,\n currentState: Readonly<Record<string, unknown>>,\n ) => void\n : E extends 'disposed'\n ? (container: StateContainer<any, any, any>) => void\n : E extends 'refAcquired'\n ? (container: StateContainer<any, any, any>, refId: string) => void\n : E extends 'refReleased'\n ? (container: StateContainer<any, any, any>, refId: string) => void\n : E extends 'depsChanged'\n ? (\n container: StateContainer<any, any, any>,\n previousDeps: Readonly<Record<string, unknown>>,\n currentDeps: Readonly<Record<string, unknown>>,\n ) => void\n : E extends 'hydrationChanged'\n ? (\n container: StateContainer<any, any, any>,\n status: HydrationStatus,\n previousStatus: HydrationStatus,\n ) => void\n : E extends 'activated'\n ? (\n container: StateContainer<any, any, any>,\n signal: AbortSignal,\n ) => void\n : E extends 'deactivated'\n ? (container: StateContainer<any, any, any>) => void\n : never;\n\n/**\n * Owns StateContainer instances: creation, ref tracking, disposal and\n * lifecycle events.\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 *\n * `stateChanged` fires once per emit (microtask-deferred, not coalesced).\n * Plugins' `onStateChange` fires once per channel flush with coalesced\n * `prev`/`next` and a `PathSet`.\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 /**\n * `depend()`-owner to the (Type, key) entries it resolved, per key because\n * one handle resolves a different key per `args`.\n */\n private readonly _dependentEdges = new WeakMap<\n StateContainer<any, any, any>,\n Map<StateContainerConstructor, Set<string>>\n >();\n\n private readonly _entryByInstance = new WeakMap<\n StateContainer<any, any, any>,\n InstanceEntry\n >();\n\n /**\n * Only for `PluginContext.getRefIds`: ids can collide across same-named\n * classes, so nothing else may rely on it.\n */\n private readonly _entryById = new Map<string, InstanceEntry>();\n\n private readonly listeners = new Map<\n LifecycleEvent,\n Set<(...args: any[]) => void>\n >();\n\n get hasStateChangedListeners(): boolean {\n return (this.listeners.get('stateChanged')?.size ?? 0) > 0;\n }\n private _pendingStateChanges: Array<\n [StateContainer<any, any, any>, any, any]\n > | null = null;\n\n private _autoRefIdCounter = 0;\n\n constructor() {\n // Also covers a direct `dispose()` that bypasses `release()`.\n this.on('disposed', (container) => this._handleDisposed(container));\n }\n\n /** Prune a tracked instance's entry and release its `depend()` edges. */\n private _handleDisposed(container: StateContainer<any, any, any>): void {\n const Type = container.constructor as StateContainerConstructor;\n const found = this._pruneEntry(Type, container);\n if (!found) return;\n const edges = this._dependentEdges.get(container);\n if (!edges) return;\n this._dependentEdges.delete(container);\n for (const [DepType, keys] of edges) {\n for (const depKey of keys) {\n this._releaseDependent(DepType, depKey, container);\n }\n }\n }\n\n /** The single dispose decision: no refs, no dependents, not keepAlive. */\n private _isUnowned(\n Type: StateContainerConstructor,\n entry: InstanceEntry,\n ): boolean {\n return this._hasNoOwners(entry) && !isKeepAliveClass(Type);\n }\n\n /** Ignores keepAlive: a keepAlive instance still deactivates. */\n private _hasNoOwners(entry: InstanceEntry): boolean {\n return (\n entry.refs.size === 0 &&\n (entry.dependents === undefined || entry.dependents.size === 0)\n );\n }\n\n /**\n * Idempotent, so every acquire/release path calls it. The events fire after\n * the instance's own `onActivate`/`onDeactivate`.\n */\n private _syncActivation(entry: InstanceEntry): void {\n const transition = entry.instance[SET_ACTIVE](!this._hasNoOwners(entry));\n if (transition === 'none') return;\n if (transition === 'deactivated') {\n this.emit('deactivated', entry.instance);\n } else {\n this.emit('activated', entry.instance, transition.signal);\n }\n }\n\n private _recordDependentEdge(\n dependent: StateContainer<any, any, any>,\n Type: StateContainerConstructor,\n key: string,\n ): void {\n let byType = this._dependentEdges.get(dependent);\n if (!byType) this._dependentEdges.set(dependent, (byType = new Map()));\n let keys = byType.get(Type);\n if (!keys) byType.set(Type, (keys = new Set()));\n keys.add(key);\n }\n\n /** @returns true if this registry tracked `container`. */\n private _pruneEntry(\n Type: StateContainerConstructor,\n container: StateContainer<any, any, any>,\n ): boolean {\n const entry = this._entryByInstance.get(container);\n if (entry === undefined) return false;\n this._entryByInstance.delete(container);\n const instances = this.instancesByConstructor.get(Type);\n if (instances?.get(entry.key) === entry) instances.delete(entry.key);\n const id = container.$blac.id;\n if (this._entryById.get(id) === entry) this._entryById.delete(id);\n return true;\n }\n\n private _indexEntry(entry: InstanceEntry): void {\n this._entryByInstance.set(entry.instance, entry);\n this._entryById.set(entry.instance.$blac.id, entry);\n }\n\n /** Disposing here recurses through `disposed`, unwinding dep chains. */\n private _releaseDependent(\n Type: StateContainerConstructor,\n key: string,\n dependent: StateContainer<any, any, any>,\n ): void {\n const instances = this.instancesByConstructor.get(Type);\n const entry = instances?.get(key);\n if (!entry) return;\n entry.dependents?.delete(dependent);\n if (this._isUnowned(Type, entry)) {\n if (!entry.instance.$blac.disposed) entry.instance.dispose();\n return;\n }\n this._syncActivation(entry);\n }\n\n /**\n * Register a StateContainer class with configuration\n * @param constructor - The StateContainer class constructor\n * @throws Error if type is already registered\n */\n register<T extends StateContainerConstructor>(constructor: T): void {\n if (this.types.has(constructor)) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} Type \"${getBlacName(constructor)}\" is already registered`,\n );\n }\n this.types.add(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 ): ReadonlyMap<string, InstanceEntry> {\n return this.instancesByConstructor.get(Type) || EMPTY_INSTANCES_MAP;\n }\n\n /**\n * Insert an entry, replacing the one at `instanceKey`. The instance is not\n * configured here.\n *\n * @internal Used by testing helpers only.\n */\n [INSERT_INSTANCE]<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string,\n instance: InstanceType<T>,\n refs: Map<string, number> = new Map(),\n ): void {\n const instances = this.ensureInstancesMap(Type);\n const existingEntry = instances.get(instanceKey);\n if (\n existingEntry &&\n existingEntry.instance !== instance &&\n !existingEntry.instance.$blac.disposed\n ) {\n existingEntry.instance.dispose();\n }\n const entry: InstanceEntry = { instance, key: instanceKey, refs };\n instances.set(instanceKey, entry);\n this._indexEntry(entry);\n this.types.add(Type);\n }\n\n /**\n * The single source of keying, so `acquire` and `release` agree: explicit\n * key \\> `static key(args)` \\> structural hash of args \\> default key.\n *\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Explicit key, or undefined to derive from args\n * @param args - Construction args used for structural/`static key` derivation\n */\n resolveKey<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey: string | undefined,\n args: unknown,\n ): string {\n if (instanceKey !== undefined) {\n return instanceKey;\n }\n const keyFn = getClassKey(Type);\n if (keyFn) {\n return keyFn(args);\n }\n if (args !== undefined) {\n return structuralKey(args);\n }\n return DEFAULT_STRUCTURAL_KEY;\n }\n\n private assertInstanceLimit(\n Type: StateContainerConstructor,\n currentCount: number,\n ): void {\n const limit = getBlacConfig().maxInstancesPerType;\n if (limit > 0 && currentCount >= limit) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} ${getBlacName(Type)} exceeded the maximum of ${limit} live instances. ` +\n `This usually means the instance key is unstable — e.g. \\`args\\` that ` +\n `change identity every render, or a missing \\`static key\\` — so a new ` +\n `instance is created and never disposed (memory leak). Stabilize the key, ` +\n `add a \\`static key(args)\\`, or raise \\`configureBlac({ maxInstancesPerType })\\`.`,\n );\n }\n }\n\n private assertRefLimit(\n Type: StateContainerConstructor,\n resolvedKey: string,\n refCount: number,\n ): void {\n const limit = getBlacConfig().maxRefsPerInstance;\n if (limit > 0 && refCount > limit) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} ${getBlacName(Type)} instance \"${resolvedKey}\" exceeded the maximum of ${limit} live references. ` +\n `This usually means references are acquired without a matching release ` +\n `(e.g. a consumer that never unmounts/cleans up), leaking refs that keep ` +\n `the instance alive forever. Ensure every acquire is paired with a release, ` +\n `or raise \\`configureBlac({ maxRefsPerInstance })\\`.`,\n );\n }\n }\n\n /**\n * Get or create an instance and add a ref; `release()` it with the same\n * refId.\n *\n * @internal Internal key tier. Public callers use the args-based `acquire`\n * wrapper; `useBloc` and `watch` address a pre-resolved key here.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Pre-resolved instance key (defaults to 'default')\n * @param options - `canCreate` and `countRef` default to true; `refId` is\n * auto-generated when omitted; `dependent` is the `depend()`-owner, whose\n * edge is released on its disposal; `sweepIfUnowned` is for speculative\n * creates (see `_scheduleSweep`).\n */\n acquire<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey?: string,\n options: {\n canCreate?: boolean;\n countRef?: boolean;\n refId?: string;\n args?: unknown;\n dependent?: StateContainer<any, any, any>;\n sweepIfUnowned?: boolean;\n } = {},\n ): InstanceType<T> {\n const { canCreate = true, countRef = true } = options;\n const args = options.args;\n\n const resolvedKey = this.resolveKey(Type, instanceKey, args);\n\n const instances = this.ensureInstancesMap(Type);\n let entry = instances.get(resolvedKey);\n\n if (entry?.instance.$blac.disposed) {\n instances.delete(resolvedKey);\n entry = undefined;\n }\n\n if (entry) {\n if (IS_DEV && args !== undefined && entry.args !== undefined) {\n const incomingKey = structuralKey(args);\n const storedKey = (entry.argsKey ??= structuralKey(entry.args));\n if (incomingKey !== storedKey) {\n console.warn(\n `${BLAC_ERROR_PREFIX} ${getBlacName(Type)} instance key \"${resolvedKey}\" was acquired with different args. ` +\n `Existing args: ${storedKey}, new args: ${incomingKey}. ` +\n `The existing instance will be reused. If distinct args should produce distinct instances, ` +\n `either remove the explicit instanceKey or provide a \\`static key\\` function that reflects the difference.`,\n );\n }\n }\n\n if (countRef) {\n const refId = options.refId ?? `_auto_${this._autoRefIdCounter++}`;\n const count = entry.refs.get(refId) ?? 0;\n if (count === 0) {\n this.assertRefLimit(Type, resolvedKey, entry.refs.size + 1);\n }\n entry.refs.set(refId, count + 1);\n this.emit('refAcquired', entry.instance, refId);\n }\n\n if (options.dependent) {\n (entry.dependents ??= new Set()).add(options.dependent);\n this._recordDependentEdge(options.dependent, Type, resolvedKey);\n }\n\n this._syncActivation(entry);\n\n if (!options.sweepIfUnowned) {\n clearTimeout(entry.sweepTimer);\n entry.sweepTimer = undefined;\n } else if (entry.sweepTimer !== undefined) {\n this._scheduleSweep(Type, entry);\n }\n\n return entry.instance;\n }\n\n if (!canCreate) {\n throw new Error(\n `${BLAC_ERROR_PREFIX} ${getBlacName(Type)} instance \"${resolvedKey}\" not found and creation is disabled.`,\n );\n }\n\n this.assertInstanceLimit(Type, instances.size);\n\n const config: StateContainerConfig = {\n instanceId: resolvedKey,\n args,\n registry: this,\n };\n const instance = new Type() as InstanceType<T>;\n instance[INIT_CONFIG](config);\n const initialRefs = new Map<string, number>();\n let initialRefId: string | undefined;\n if (countRef) {\n initialRefId = options.refId ?? `_auto_${this._autoRefIdCounter++}`;\n initialRefs.set(initialRefId, 1);\n }\n const newEntry: InstanceEntry = {\n instance,\n key: resolvedKey,\n refs: initialRefs,\n args,\n };\n if (options.dependent) {\n (newEntry.dependents ??= new Set()).add(options.dependent);\n this._recordDependentEdge(options.dependent, Type, resolvedKey);\n }\n instances.set(resolvedKey, newEntry);\n this._indexEntry(newEntry);\n\n this.types.add(Type);\n\n if (initialRefId) {\n this.emit('refAcquired', instance, initialRefId);\n }\n\n this._syncActivation(newEntry);\n\n if (options.sweepIfUnowned && this._hasNoOwners(newEntry)) {\n this._scheduleSweep(Type, newEntry);\n }\n\n return instance;\n }\n\n /**\n * Dispose a speculative create (a render that never commits, SSR) that is\n * still unowned after `unownedSweepDelayMs`. The delay must outlast a\n * time-sliced render; a repeat speculative acquire restarts it. Opt-in, so a\n * bare `ensure()` stays usable across an `await`.\n */\n private _scheduleSweep(\n Type: StateContainerConstructor,\n entry: InstanceEntry,\n ): void {\n clearTimeout(entry.sweepTimer);\n entry.sweepTimer = setTimeout(() => {\n entry.sweepTimer = undefined;\n const instances = this.instancesByConstructor.get(Type);\n if (instances?.get(entry.key) !== entry) return;\n if (entry.instance.$blac.disposed) return;\n if (!this._isUnowned(Type, entry)) return;\n entry.instance.dispose();\n instances.delete(entry.key);\n }, getBlacConfig().unownedSweepDelayMs);\n (entry.sweepTimer as { unref?: () => void }).unref?.();\n }\n\n /**\n * Get an existing instance without adding a ref.\n *\n * @internal Internal key tier; public callers use the args-based `borrow`.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Pre-resolved 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 = DEFAULT_STRUCTURAL_KEY,\n ): InstanceType<T> {\n return this.acquire(Type, instanceKey, {\n canCreate: false,\n countRef: false,\n });\n }\n\n /**\n * Like `borrow`, but returns the error instead of throwing.\n *\n * @internal Internal key tier; public callers use the args-based `borrowSafe`.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Pre-resolved 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 = DEFAULT_STRUCTURAL_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 * Get or create an instance without adding a ref.\n *\n * @internal Internal key tier; public callers use the args-based `ensure`.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Pre-resolved instance key, or undefined to derive from `args`\n * (`static key(args)` / structural hash), matching `acquire`.\n * @param args - Construction args; used for keying when no explicit key is given\n * @returns The state container instance\n */\n ensure<T extends StateContainerConstructor = StateContainerConstructor>(\n Type: T,\n instanceKey?: string,\n args?: unknown,\n ): InstanceType<T> {\n return this.acquire(Type, instanceKey, {\n canCreate: true,\n countRef: false,\n args,\n });\n }\n\n /**\n * Remove a ref and dispose the instance once nothing owns it. Releasing a\n * ref that isn't held is a no-op.\n *\n * @internal Internal key tier; public callers use the args-based `release`.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Pre-resolved instance key (defaults to 'default')\n * @param forceDispose - Force immediate disposal regardless of refs\n * @param refId - The specific ref to remove; removes one arbitrary ref if omitted\n */\n release<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string = DEFAULT_STRUCTURAL_KEY,\n forceDispose = false,\n refId?: string,\n ): void {\n const instances = this.instancesByConstructor.get(Type);\n const entry = instances?.get(instanceKey);\n if (!instances || !entry) return;\n\n if (forceDispose) {\n if (!entry.instance.$blac.disposed) {\n entry.instance.dispose();\n }\n instances.delete(instanceKey);\n return;\n }\n\n const releasedRefId = refId ?? entry.refs.keys().next().value;\n if (releasedRefId === undefined) return;\n const count = entry.refs.get(releasedRefId) ?? 0;\n if (count === 0) return;\n if (count === 1) {\n entry.refs.delete(releasedRefId);\n } else {\n entry.refs.set(releasedRefId, count - 1);\n }\n this.emit('refReleased', entry.instance, releasedRefId);\n\n // Checked before activation so a disposing entry never also deactivates.\n if (this._isUnowned(Type, entry)) {\n if (!entry.instance.$blac.disposed) {\n entry.instance.dispose();\n }\n instances.delete(instanceKey);\n return;\n }\n\n this._syncActivation(entry);\n }\n\n /** Live instances of `Type`. */\n getAll<T extends StateContainerConstructor>(\n Type: T,\n ): InstanceReadonlyState<T>[] {\n const instances = this.getInstancesMap(Type);\n const result: InstanceReadonlyState<T>[] = [];\n for (const entry of instances.values()) {\n if (!entry.instance.$blac.disposed) {\n result.push(entry.instance);\n }\n }\n return result;\n }\n\n /** Iterate live instances of `Type`; callback errors are logged. */\n forEach<T extends StateContainerConstructor>(\n Type: T,\n callback: (instance: InstanceReadonlyState<T>) => void,\n ): void {\n const instances = this.getInstancesMap(Type);\n for (const entry of instances.values()) {\n const instance = entry.instance;\n if (!instance.$blac.disposed) {\n try {\n callback(instance);\n } catch (error) {\n console.error(\n `${BLAC_ERROR_PREFIX} forEach callback error for ${getBlacName(Type)}:`,\n error,\n );\n }\n }\n }\n }\n\n /** Dispose all instances of `Type`. */\n clear<T extends StateContainerConstructor>(Type: T): void {\n const instances = this.instancesByConstructor.get(Type);\n if (!instances) return;\n for (const entry of instances.values()) {\n if (!entry.instance.$blac.disposed) {\n entry.instance.dispose();\n }\n }\n instances.clear();\n }\n\n /** Dispose every live instance, keepAlive included, for which `predicate` is true. */\n clearWhere(\n predicate: (instance: StateContainer<any, any, any>) => boolean,\n ): void {\n const matches: StateContainer<any, any, any>[] = [];\n for (const Type of this.types) {\n for (const entry of this.getInstancesMap(Type).values()) {\n if (!entry.instance.$blac.disposed && predicate(entry.instance)) {\n matches.push(entry.instance);\n }\n }\n }\n for (const instance of matches) {\n if (!instance.$blac.disposed) instance.dispose();\n }\n }\n\n /**\n * Get reference count for an instance (number of active refs).\n *\n * @internal Internal key tier; public callers use the args-based `getRefCount`.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Pre-resolved 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 = DEFAULT_STRUCTURAL_KEY,\n ): number {\n return this.getInstancesMap(Type).get(instanceKey)?.refs.size ?? 0;\n }\n\n /**\n * Get all active reference IDs for an instance.\n *\n * @internal Internal key tier; public callers use the args-based `getRefIds`.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Pre-resolved instance key (defaults to 'default')\n * @returns Array of ref ID strings (empty if instance doesn't exist)\n */\n getRefIds<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string = DEFAULT_STRUCTURAL_KEY,\n ): string[] {\n const entry = this.getInstancesMap(Type).get(instanceKey);\n return entry ? Array.from(entry.refs.keys()) : [];\n }\n\n /** Ref ids by `$blac.id`, for `PluginContext.getRefIds`. */\n getRefIdsById(instanceId: string): string[] {\n const entry = this._entryById.get(instanceId);\n return entry ? Array.from(entry.refs.keys()) : [];\n }\n\n /**\n * Check if an instance exists.\n *\n * @internal Internal key tier; public callers use the args-based `hasInstance`.\n * @param Type - The StateContainer class constructor\n * @param instanceKey - Pre-resolved instance key (defaults to 'default')\n * @returns true if a live (not disposed) instance exists\n */\n hasInstance<T extends StateContainerConstructor>(\n Type: T,\n instanceKey: string = DEFAULT_STRUCTURAL_KEY,\n ): boolean {\n const entry = this.getInstancesMap(Type).get(instanceKey);\n return entry !== undefined && !entry.instance.$blac.disposed;\n }\n\n /** Dispose every instance and forget all types (for testing). */\n clearAll(): void {\n for (const Type of this.types) {\n this.clear(Type);\n }\n this.types.clear();\n }\n\n /** Instance counts, for debugging. */\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 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 /** All registered types (for plugins). */\n getTypes(): StateContainerConstructor[] {\n return Array.from(this.types);\n }\n\n /**\n * Subscribe to a lifecycle event.\n * @returns Unsubscribe function\n */\n on<E extends LifecycleEvent>(\n event: E,\n listener: LifecycleListener<E>,\n ): () => void {\n let instance = this.listeners.get(event);\n if (!instance) {\n instance = new Set();\n this.listeners.set(event, instance);\n }\n\n instance.add(listener as (...args: any[]) => void);\n\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: 'created', container: StateContainer<any, any, any>): void;\n emit(event: 'disposed', container: StateContainer<any, any, any>): void;\n emit(\n event: 'stateChanged',\n container: StateContainer<any, any, any>,\n previousState: any,\n currentState: any,\n ): void;\n emit(\n event: 'refAcquired',\n container: StateContainer<any, any, any>,\n refId: string,\n ): void;\n emit(\n event: 'refReleased',\n container: StateContainer<any, any, any>,\n refId: string,\n ): void;\n emit(\n event: 'depsChanged',\n container: StateContainer<any, any, any>,\n previousDeps: Readonly<Record<string, unknown>>,\n currentDeps: Readonly<Record<string, unknown>>,\n ): void;\n emit(\n event: 'hydrationChanged',\n container: StateContainer<any, any, any>,\n status: HydrationStatus,\n previousStatus: HydrationStatus,\n ): void;\n emit(\n event: 'activated',\n container: StateContainer<any, any, any>,\n signal: AbortSignal,\n ): void;\n emit(event: 'deactivated', container: StateContainer<any, any, any>): void;\n emit(event: LifecycleEvent, ...args: any[]): void {\n const listeners = this.listeners.get(event);\n if (!listeners || listeners.size === 0) return;\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 * Queue a microtask-deferred `stateChanged`.\n * @internal - Called by StateContainer.applyState\n */\n notifyStateChanged(\n container: StateContainer<any, any, any>,\n previousState: any,\n newState: any,\n ): void {\n if (!this.hasStateChangedListeners) return;\n\n if (!this._pendingStateChanges) {\n this._pendingStateChanges = [];\n queueMicrotask(() => this.flushStateChanged());\n }\n this._pendingStateChanges.push([container, previousState, newState]);\n }\n\n /**\n * One event per emit, deliberately not coalesced: devtools and time-travel\n * need every intermediate transition. Plugins get the coalesced lane.\n */\n private flushStateChanged(): void {\n const pending = this._pendingStateChanges;\n this._pendingStateChanges = null;\n if (!pending) return;\n\n for (const [container, prev, next] of pending) {\n this.emit('stateChanged', container, prev, next);\n }\n }\n}\n\n/**\n * The global default registry.\n * @public\n */\nexport const globalRegistry = new StateContainerRegistry();\n"],"mappings":"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"}
|
package/dist/constants.d.cts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
export declare const BLAC_STATIC_PROPS: {
|
|
3
3
|
/** Mark a bloc to never be auto-disposed (kept alive permanently). */
|
|
4
4
|
readonly KEEP_ALIVE: "keepAlive";
|
|
5
|
+
/** Give each React `useBloc` mount its own private instance. */
|
|
6
|
+
readonly ISOLATED: "isolated";
|
|
5
7
|
/** Exclude a bloc from DevTools reporting (prevents infinite loops). */
|
|
6
8
|
readonly EXCLUDE_FROM_DEVTOOLS: "__excludeFromDevTools";
|
|
7
9
|
/**
|
package/dist/constants.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
export declare const BLAC_STATIC_PROPS: {
|
|
3
3
|
/** Mark a bloc to never be auto-disposed (kept alive permanently). */
|
|
4
4
|
readonly KEEP_ALIVE: "keepAlive";
|
|
5
|
+
/** Give each React `useBloc` mount its own private instance. */
|
|
6
|
+
readonly ISOLATED: "isolated";
|
|
5
7
|
/** Exclude a bloc from DevTools reporting (prevents infinite loops). */
|
|
6
8
|
readonly EXCLUDE_FROM_DEVTOOLS: "__excludeFromDevTools";
|
|
7
9
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { StructuralContainer, type DeepPartial, type StructuralContainerOptions } from '@dirtytalk/structural';
|
|
2
2
|
import type { StateContainerRegistry } from './StateContainerRegistry';
|
|
3
3
|
import type { ExtractArgs, ExtractState, StateContainerConstructor } from '../types/utilities';
|
|
4
|
-
import { APPLY_DEPS, INIT_CONFIG, ON_DISPOSE, REMOVE_DEPS_OWNER, SET_ACTIVE, WITH_TRACKED_STATE } from './symbols';
|
|
4
|
+
import { APPLY_DEPS, INIT_CONFIG, ON_ACTIVATED, ON_DISPOSE, REMOVE_DEPS_OWNER, SET_ACTIVE, WITH_TRACKED_STATE } from './symbols';
|
|
5
5
|
import { BlacMeta } from './meta';
|
|
6
6
|
/**
|
|
7
7
|
* Brand symbol carried (non-enumerable) on every handle returned by
|
|
@@ -107,6 +107,11 @@ export declare abstract class StateContainer<S extends object = any, Args = void
|
|
|
107
107
|
* filtering the global registry `'disposed'` event.
|
|
108
108
|
*/
|
|
109
109
|
[ON_DISPOSE](handler: () => void): () => void;
|
|
110
|
+
/**
|
|
111
|
+
* @internal Run `handler` on every activation, and now if already active.
|
|
112
|
+
* Backs `onActivated()`.
|
|
113
|
+
*/
|
|
114
|
+
[ON_ACTIVATED](handler: (signal: AbortSignal) => void): () => void;
|
|
110
115
|
/**
|
|
111
116
|
* @internal Drive the 0↔1 ownership transition. Idempotent: repeated calls
|
|
112
117
|
* with the same value are no-ops, so the registry can call it from every
|
|
@@ -134,6 +139,7 @@ export declare abstract class StateContainer<S extends object = any, Args = void
|
|
|
134
139
|
private _config;
|
|
135
140
|
private _initCalled;
|
|
136
141
|
private _activation;
|
|
142
|
+
private _activationHandlers;
|
|
137
143
|
private _emitWindowStart;
|
|
138
144
|
private _emitCount;
|
|
139
145
|
private _emitRateWarned;
|
|
@@ -193,6 +193,8 @@ export declare class StateContainerRegistry {
|
|
|
193
193
|
forEach<T extends StateContainerConstructor>(Type: T, callback: (instance: InstanceReadonlyState<T>) => void): void;
|
|
194
194
|
/** Dispose all instances of `Type`. */
|
|
195
195
|
clear<T extends StateContainerConstructor>(Type: T): void;
|
|
196
|
+
/** Dispose every live instance, keepAlive included, for which `predicate` is true. */
|
|
197
|
+
clearWhere(predicate: (instance: StateContainer<any, any, any>) => boolean): void;
|
|
196
198
|
/**
|
|
197
199
|
* Get reference count for an instance (number of active refs).
|
|
198
200
|
*
|
package/dist/core/meta.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { HydrationStatus } from './StateContainer';
|
|
11
11
|
import type { StateContainerConstructor } from '../types/utilities';
|
|
12
|
+
import type { StateContainerRegistry } from './StateContainerRegistry';
|
|
12
13
|
/**
|
|
13
14
|
* Non-enumerable brand carried on every `$blac` object. Used by the clobber
|
|
14
15
|
* guard in `StateContainer` to detect a subclass class-field shadowing the
|
|
@@ -54,6 +55,8 @@ export declare class BlacMeta<S extends object = any> {
|
|
|
54
55
|
get debug(): boolean;
|
|
55
56
|
get createdAt(): number;
|
|
56
57
|
get disposed(): boolean;
|
|
58
|
+
/** The registry that owns this container (the global one for a bare `new`). */
|
|
59
|
+
get registry(): StateContainerRegistry;
|
|
57
60
|
get dependencies(): ReadonlyMap<StateContainerConstructor, string>;
|
|
58
61
|
/** Built on first access; identity-stable afterwards. */
|
|
59
62
|
get hydration(): BlacHydration<S>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StateContainer } from './StateContainer';
|
|
2
|
+
/**
|
|
3
|
+
* Run `handler` each time `container` goes from unowned to owned, and now if it
|
|
4
|
+
* is already owned. `signal` aborts on the matching deactivation and on
|
|
5
|
+
* dispose. Returns an unsubscribe function.
|
|
6
|
+
*
|
|
7
|
+
* Unlike the protected `onActivate`, this can be called from a field
|
|
8
|
+
* initializer or a helper that receives the container.
|
|
9
|
+
*/
|
|
10
|
+
export declare function onActivated(container: StateContainer<any, any, any>, handler: (signal: AbortSignal) => void): () => void;
|
package/dist/core/symbols.d.ts
CHANGED
|
@@ -14,6 +14,11 @@ export declare const REMOVE_DEPS_OWNER: unique symbol;
|
|
|
14
14
|
* API.
|
|
15
15
|
*/
|
|
16
16
|
export declare const ON_DISPOSE: unique symbol;
|
|
17
|
+
/**
|
|
18
|
+
* @internal Register a callback that runs on each activation with that
|
|
19
|
+
* activation's signal. Called by `onActivated()` — not public API.
|
|
20
|
+
*/
|
|
21
|
+
export declare const ON_ACTIVATED: unique symbol;
|
|
17
22
|
/**
|
|
18
23
|
* @internal Symbol-keyed configuration entry point on `StateContainer`.
|
|
19
24
|
* Writes the instance's identity fields (`_name`/`_debug`/`_instanceId`),
|
|
@@ -9,6 +9,13 @@ export interface BlacOptions {
|
|
|
9
9
|
* `keepAlive` inherited from a base class.
|
|
10
10
|
*/
|
|
11
11
|
keepAlive?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Give each `useBloc` mount its own private instance, disposed when that
|
|
14
|
+
* component unmounts. Applies to `useBloc` only; `ensure`/`acquire` still
|
|
15
|
+
* resolve the shared instance. `false` turns off an `isolated` inherited
|
|
16
|
+
* from a base class.
|
|
17
|
+
*/
|
|
18
|
+
isolated?: boolean;
|
|
12
19
|
/** Exclude bloc from DevTools tracking (prevents infinite loops) */
|
|
13
20
|
excludeFromDevTools?: true;
|
|
14
21
|
/**
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { i as getRegistry } from "./StateContainer-CwByTd5L.js";
|
|
2
|
+
//#region src/registry/acquire.ts
|
|
3
|
+
/**
|
|
4
|
+
* Acquire an instance with ref tracking (ownership semantics). Instance
|
|
5
|
+
* identity is derived purely from `args` (via the class's `static key(args)`,
|
|
6
|
+
* a structural hash of `args`, or the default sentinel when there are none).
|
|
7
|
+
*
|
|
8
|
+
* @param BlocClass - The StateContainer class constructor
|
|
9
|
+
* @param opts - `args` derives the instance key; `refId` names the reference
|
|
10
|
+
* for debugging and is auto-generated when omitted.
|
|
11
|
+
*/
|
|
12
|
+
function acquire(BlocClass, opts) {
|
|
13
|
+
const registry = getRegistry();
|
|
14
|
+
const key = registry.resolveKey(BlocClass, void 0, opts?.args);
|
|
15
|
+
return registry.acquire(BlocClass, key, {
|
|
16
|
+
canCreate: true,
|
|
17
|
+
countRef: true,
|
|
18
|
+
refId: opts?.refId,
|
|
19
|
+
args: opts?.args
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the storage key an instance would be acquired under, given its
|
|
24
|
+
* construction `args`. This is the canonical key-computation path. Callers that
|
|
25
|
+
* both acquire and release against the `@internal` registry tier (e.g.
|
|
26
|
+
* `@blac/react` `useBloc`) must use this once and pass the same resolved key to
|
|
27
|
+
* both, so the ref is dropped under the key it was taken.
|
|
28
|
+
*/
|
|
29
|
+
function resolveInstanceKey(BlocClass, args) {
|
|
30
|
+
return getRegistry().resolveKey(BlocClass, void 0, args);
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/registry/ensure.ts
|
|
34
|
+
/**
|
|
35
|
+
* Ensure an instance exists without taking ownership (no ref added). Instance
|
|
36
|
+
* identity is derived purely from `args`, matching `acquire`.
|
|
37
|
+
*/
|
|
38
|
+
function ensure(BlocClass, opts) {
|
|
39
|
+
const registry = getRegistry();
|
|
40
|
+
const key = registry.resolveKey(BlocClass, void 0, opts?.args);
|
|
41
|
+
return registry.ensure(BlocClass, key, opts?.args);
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { acquire as n, resolveInstanceKey as r, ensure as t };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=ensure-CwtQVTam.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-CwtQVTam.js","names":[],"sources":["../src/registry/acquire.ts","../src/registry/ensure.ts"],"sourcesContent":["import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Acquire an instance with ref tracking (ownership semantics). Instance\n * identity is derived purely from `args` (via the class's `static key(args)`,\n * a structural hash of `args`, or the default sentinel when there are none).\n *\n * @param BlocClass - The StateContainer class constructor\n * @param opts - `args` derives the instance key; `refId` names the reference\n * for debugging and is auto-generated when omitted.\n */\nexport function acquire<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.acquire(BlocClass, key, {\n canCreate: true,\n countRef: true,\n refId: opts?.refId,\n args: opts?.args,\n });\n}\n\n/**\n * Resolve the storage key an instance would be acquired under, given its\n * construction `args`. This is the canonical key-computation path. Callers that\n * both acquire and release against the `@internal` registry tier (e.g.\n * `@blac/react` `useBloc`) must use this once and pass the same resolved key to\n * both, so the ref is dropped under the key it was taken.\n */\nexport function resolveInstanceKey<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, args);\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Ensure an instance exists without taking ownership (no ref added). Instance\n * identity is derived purely from `args`, matching `acquire`.\n */\nexport function ensure<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.ensure(BlocClass, key, opts?.args);\n}\n"],"mappings":";;;;;;;;;;;AAeA,SAAgB,QACd,WACA,MACiB;CACjB,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,QAAQ,WAAW,KAAK;EACtC,WAAW;EACX,UAAU;EACV,OAAO,MAAM;EACb,MAAM,MAAM;CACd,CAAC;AACH;;;;;;;;AASA,SAAgB,mBACd,WACA,MACQ;CACR,OAAO,YAAY,EAAE,WAAW,WAAW,KAAA,GAAW,IAAI;AAC5D;;;;;;;AC/BA,SAAgB,OACd,WACA,MACiB;CACjB,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,OAAO,WAAW,KAAK,MAAM,IAAI;AACnD"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const require_StateContainer = require("./StateContainer-D2b10eR4.cjs");
|
|
2
|
+
//#region src/registry/acquire.ts
|
|
3
|
+
/**
|
|
4
|
+
* Acquire an instance with ref tracking (ownership semantics). Instance
|
|
5
|
+
* identity is derived purely from `args` (via the class's `static key(args)`,
|
|
6
|
+
* a structural hash of `args`, or the default sentinel when there are none).
|
|
7
|
+
*
|
|
8
|
+
* @param BlocClass - The StateContainer class constructor
|
|
9
|
+
* @param opts - `args` derives the instance key; `refId` names the reference
|
|
10
|
+
* for debugging and is auto-generated when omitted.
|
|
11
|
+
*/
|
|
12
|
+
function acquire(BlocClass, opts) {
|
|
13
|
+
const registry = require_StateContainer.getRegistry();
|
|
14
|
+
const key = registry.resolveKey(BlocClass, void 0, opts?.args);
|
|
15
|
+
return registry.acquire(BlocClass, key, {
|
|
16
|
+
canCreate: true,
|
|
17
|
+
countRef: true,
|
|
18
|
+
refId: opts?.refId,
|
|
19
|
+
args: opts?.args
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the storage key an instance would be acquired under, given its
|
|
24
|
+
* construction `args`. This is the canonical key-computation path. Callers that
|
|
25
|
+
* both acquire and release against the `@internal` registry tier (e.g.
|
|
26
|
+
* `@blac/react` `useBloc`) must use this once and pass the same resolved key to
|
|
27
|
+
* both, so the ref is dropped under the key it was taken.
|
|
28
|
+
*/
|
|
29
|
+
function resolveInstanceKey(BlocClass, args) {
|
|
30
|
+
return require_StateContainer.getRegistry().resolveKey(BlocClass, void 0, args);
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/registry/ensure.ts
|
|
34
|
+
/**
|
|
35
|
+
* Ensure an instance exists without taking ownership (no ref added). Instance
|
|
36
|
+
* identity is derived purely from `args`, matching `acquire`.
|
|
37
|
+
*/
|
|
38
|
+
function ensure(BlocClass, opts) {
|
|
39
|
+
const registry = require_StateContainer.getRegistry();
|
|
40
|
+
const key = registry.resolveKey(BlocClass, void 0, opts?.args);
|
|
41
|
+
return registry.ensure(BlocClass, key, opts?.args);
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
Object.defineProperty(exports, "acquire", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
get: function() {
|
|
47
|
+
return acquire;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(exports, "ensure", {
|
|
51
|
+
enumerable: true,
|
|
52
|
+
get: function() {
|
|
53
|
+
return ensure;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
Object.defineProperty(exports, "resolveInstanceKey", {
|
|
57
|
+
enumerable: true,
|
|
58
|
+
get: function() {
|
|
59
|
+
return resolveInstanceKey;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=ensure-DShrbIYY.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-DShrbIYY.cjs","names":["getRegistry","getRegistry"],"sources":["../src/registry/acquire.ts","../src/registry/ensure.ts"],"sourcesContent":["import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Acquire an instance with ref tracking (ownership semantics). Instance\n * identity is derived purely from `args` (via the class's `static key(args)`,\n * a structural hash of `args`, or the default sentinel when there are none).\n *\n * @param BlocClass - The StateContainer class constructor\n * @param opts - `args` derives the instance key; `refId` names the reference\n * for debugging and is auto-generated when omitted.\n */\nexport function acquire<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.acquire(BlocClass, key, {\n canCreate: true,\n countRef: true,\n refId: opts?.refId,\n args: opts?.args,\n });\n}\n\n/**\n * Resolve the storage key an instance would be acquired under, given its\n * construction `args`. This is the canonical key-computation path. Callers that\n * both acquire and release against the `@internal` registry tier (e.g.\n * `@blac/react` `useBloc`) must use this once and pass the same resolved key to\n * both, so the ref is dropped under the key it was taken.\n */\nexport function resolveInstanceKey<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, args);\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Ensure an instance exists without taking ownership (no ref added). Instance\n * identity is derived purely from `args`, matching `acquire`.\n */\nexport function ensure<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): InstanceType<T> {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.ensure(BlocClass, key, opts?.args);\n}\n"],"mappings":";;;;;;;;;;;AAeA,SAAgB,QACd,WACA,MACiB;CACjB,MAAM,WAAWA,uBAAAA,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,QAAQ,WAAW,KAAK;EACtC,WAAW;EACX,UAAU;EACV,OAAO,MAAM;EACb,MAAM,MAAM;CACd,CAAC;AACH;;;;;;;;AASA,SAAgB,mBACd,WACA,MACQ;CACR,OAAOA,uBAAAA,YAAY,EAAE,WAAW,WAAW,KAAA,GAAW,IAAI;AAC5D;;;;;;;AC/BA,SAAgB,OACd,WACA,MACiB;CACjB,MAAM,WAAWC,uBAAAA,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,OAAO,WAAW,KAAK,MAAM,IAAI;AACnD"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_StateContainerRegistry = require("./StateContainerRegistry-
|
|
3
|
-
const require_StateContainer = require("./StateContainer-
|
|
4
|
-
const require_ensure = require("./ensure-
|
|
2
|
+
const require_StateContainerRegistry = require("./StateContainerRegistry-B6O6cfJd.cjs");
|
|
3
|
+
const require_StateContainer = require("./StateContainer-D2b10eR4.cjs");
|
|
4
|
+
const require_ensure = require("./ensure-DShrbIYY.cjs");
|
|
5
5
|
let _dirtytalk_structural = require("@dirtytalk/structural");
|
|
6
|
+
//#region src/core/onActivated.ts
|
|
7
|
+
/**
|
|
8
|
+
* Run `handler` each time `container` goes from unowned to owned, and now if it
|
|
9
|
+
* is already owned. `signal` aborts on the matching deactivation and on
|
|
10
|
+
* dispose. Returns an unsubscribe function.
|
|
11
|
+
*
|
|
12
|
+
* Unlike the protected `onActivate`, this can be called from a field
|
|
13
|
+
* initializer or a helper that receives the container.
|
|
14
|
+
*/
|
|
15
|
+
function onActivated(container, handler) {
|
|
16
|
+
return container[require_StateContainerRegistry.ON_ACTIVATED](handler);
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
6
19
|
//#region src/core/Cubit.ts
|
|
7
20
|
/**
|
|
8
21
|
* `Cubit<S>` is a `StateContainer<S>` that exposes mutation publicly.
|
|
@@ -100,6 +113,9 @@ function clear(BlocClass) {
|
|
|
100
113
|
function clearAll() {
|
|
101
114
|
require_StateContainer.getRegistry().clearAll();
|
|
102
115
|
}
|
|
116
|
+
function clearWhere(predicate) {
|
|
117
|
+
require_StateContainer.getRegistry().clearWhere(predicate);
|
|
118
|
+
}
|
|
103
119
|
/**
|
|
104
120
|
* @public
|
|
105
121
|
*/
|
|
@@ -133,6 +149,7 @@ function register(BlocClass) {
|
|
|
133
149
|
function blac(options) {
|
|
134
150
|
return function(target, _context) {
|
|
135
151
|
if (options.keepAlive !== void 0) target[require_StateContainerRegistry.BLAC_STATIC_PROPS.KEEP_ALIVE] = options.keepAlive;
|
|
152
|
+
if (options.isolated !== void 0) target[require_StateContainerRegistry.BLAC_STATIC_PROPS.ISOLATED] = options.isolated;
|
|
136
153
|
if (options.excludeFromDevTools) target[require_StateContainerRegistry.BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS] = true;
|
|
137
154
|
if (typeof options.equality === "function") target[require_StateContainerRegistry.BLAC_STATIC_PROPS.EQUALITY] = options.equality;
|
|
138
155
|
if (typeof options.key === "function") target[require_StateContainerRegistry.BLAC_STATIC_PROPS.KEY] = options.key;
|
|
@@ -214,6 +231,8 @@ function watchImpl(blocsOrBloc, callback, options) {
|
|
|
214
231
|
const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;
|
|
215
232
|
const registry = require_StateContainer.getRegistry();
|
|
216
233
|
const create = options?.create ?? true;
|
|
234
|
+
const signal = options?.signal;
|
|
235
|
+
if (signal?.aborted) return () => {};
|
|
217
236
|
const targets = inputs.map((input) => toWatchTarget(registry, input));
|
|
218
237
|
const refIds = targets.map(() => `_watch_${watchRefSeq++}`);
|
|
219
238
|
const resolveAt = (index) => create ? resolveBloc(registry, targets[index], refIds[index]) : resolveBlocPassive(registry, targets[index]);
|
|
@@ -224,6 +243,7 @@ function watchImpl(blocsOrBloc, callback, options) {
|
|
|
224
243
|
const cleanup = () => {
|
|
225
244
|
if (disposed) return;
|
|
226
245
|
disposed = true;
|
|
246
|
+
signal?.removeEventListener("abort", cleanup);
|
|
227
247
|
for (const unsub of channelUnsubs) unsub?.();
|
|
228
248
|
for (const unsub of disposedUnsubs) unsub?.();
|
|
229
249
|
channelUnsubs.length = 0;
|
|
@@ -252,6 +272,7 @@ function watchImpl(blocsOrBloc, callback, options) {
|
|
|
252
272
|
queueMicrotask(() => resubscribeAt(index));
|
|
253
273
|
});
|
|
254
274
|
};
|
|
275
|
+
signal?.addEventListener("abort", cleanup, { once: true });
|
|
255
276
|
try {
|
|
256
277
|
for (let i = 0; i < targets.length; i++) instances.push(resolveAt(i));
|
|
257
278
|
for (let i = 0; i < instances.length; i++) subscribeAt(i);
|
|
@@ -285,6 +306,7 @@ exports.borrow = borrow;
|
|
|
285
306
|
exports.borrowSafe = borrowSafe;
|
|
286
307
|
exports.clear = clear;
|
|
287
308
|
exports.clearAll = clearAll;
|
|
309
|
+
exports.clearWhere = clearWhere;
|
|
288
310
|
exports.configureBlac = require_StateContainerRegistry.configureBlac;
|
|
289
311
|
exports.ensure = require_ensure.ensure;
|
|
290
312
|
exports.forEach = forEach;
|
|
@@ -300,7 +322,9 @@ exports.hasInstance = hasInstance;
|
|
|
300
322
|
exports.instance = instance;
|
|
301
323
|
exports.instanceId = instanceId;
|
|
302
324
|
exports.isExcludedFromDevTools = require_StateContainerRegistry.isExcludedFromDevTools;
|
|
325
|
+
exports.isIsolatedClass = require_StateContainerRegistry.isIsolatedClass;
|
|
303
326
|
exports.isKeepAliveClass = require_StateContainerRegistry.isKeepAliveClass;
|
|
327
|
+
exports.onActivated = onActivated;
|
|
304
328
|
exports.register = register;
|
|
305
329
|
exports.release = release;
|
|
306
330
|
exports.resetBlacConfig = require_StateContainerRegistry.resetBlacConfig;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["StateContainer","getRegistry","getRegistry","getRegistry","BLAC_STATIC_PROPS","resolveInstanceKey","getRegistry","ALL_PATHS","ON_DISPOSE"],"sources":["../src/core/Cubit.ts","../src/registry/borrow.ts","../src/registry/release.ts","../src/registry/queries.ts","../src/registry/management.ts","../src/decorators/blac.ts","../src/watch/watch.ts","../src/types/branded.ts"],"sourcesContent":["import { StateContainer } from './StateContainer';\nimport type { DeepPartial } from '@dirtytalk/structural';\n\n/**\n * `Cubit<S>` is a `StateContainer<S>` that exposes mutation publicly.\n *\n * That is the whole difference, and it is a real one: on `StateContainer`\n * `emit` / `patch` / `update` are `protected`, so a container mutates itself\n * from its own methods and callers go through the API it chooses to publish.\n * `Cubit` re-declares the three as `public` for the cases where a caller\n * legitimately drives state from outside — test helpers, devtools\n * time-travel, benchmarks.\n *\n * Reach for `StateContainer` when business logic should live in the class,\n * and `Cubit` when the caller owns the transitions.\n */\nexport abstract class Cubit<\n S extends object = any,\n Args = void,\n Deps extends object = Record<string, never>,\n> extends StateContainer<S, Args, Deps> {\n override emit(next: S): void {\n super.emit(next);\n }\n\n override patch(partial: DeepPartial<S>): void {\n super.patch(partial);\n }\n\n override update(fn: (state: S) => S): void {\n super.update(fn);\n }\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * How to identify the instance to borrow: the same `args` shape `useBloc`\n * accepts, resolved through the class's `static key(args)` so call sites use\n * the *same* shape they pass to `useBloc` instead of hand-deriving the key.\n *\n * `borrowSafe(ChannelBloc, { args: { channelId } })` and\n * `useBloc(ChannelBloc, { args: { channelId } })` therefore always agree.\n */\nexport type BorrowTarget<T extends StateContainerConstructor> = {\n args?: ExtractArgs<T>;\n};\n\nfunction resolveBorrowKey<T extends StateContainerConstructor>(\n BlocClass: T,\n target: BorrowTarget<T> | undefined,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, target?.args);\n}\n\nexport function borrow<T extends StateContainerConstructor>(\n BlocClass: T,\n target?: BorrowTarget<T>,\n): InstanceType<T> {\n return getRegistry().borrow(BlocClass, resolveBorrowKey(BlocClass, target));\n}\n\nexport function borrowSafe<T extends StateContainerConstructor>(\n BlocClass: T,\n target?: BorrowTarget<T>,\n):\n | { error: Error; instance: null }\n | { error: null; instance: InstanceType<T> } {\n return getRegistry().borrowSafe(\n BlocClass,\n resolveBorrowKey(BlocClass, target),\n );\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Release a reference to an instance. Instance identity is derived purely from\n * `args` (must match the `args` it was acquired with).\n *\n * @param opts - `args` derives the instance key (must match acquire);\n * `refId` picks the ref to drop, otherwise one arbitrary ref goes;\n * `forceDispose` disposes immediately regardless of remaining refs.\n */\nexport function release<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string; forceDispose?: boolean },\n): void {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n registry.release(BlocClass, key, opts?.forceDispose ?? false, opts?.refId);\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n InstanceReadonlyState,\n} from '../types/utilities';\n\n/**\n * @public\n */\nexport function hasInstance<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): boolean {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.hasInstance(BlocClass, key);\n}\n\n/**\n * @public\n */\nexport function getRefCount<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): number {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.getRefCount(BlocClass, key);\n}\n\n/**\n * @public\n */\nexport function getRefIds<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): string[] {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.getRefIds(BlocClass, key);\n}\n\n/**\n * @public\n */\nexport function getAll<T extends StateContainerConstructor>(\n BlocClass: T,\n): InstanceReadonlyState<T>[] {\n return getRegistry().getAll(BlocClass);\n}\n\n/**\n * @public\n */\nexport function forEach<T extends StateContainerConstructor>(\n BlocClass: T,\n callback: (instance: InstanceReadonlyState<T>) => void,\n): void {\n getRegistry().forEach(BlocClass, callback);\n}\n","import { getRegistry } from './config';\nimport type { StateContainerConstructor } from '../types/utilities';\n\nexport function clear<T extends StateContainerConstructor>(BlocClass: T): void {\n getRegistry().clear(BlocClass);\n}\n\nexport function clearAll(): void {\n getRegistry().clearAll();\n}\n\n/**\n * @public\n */\nexport function register<T extends StateContainerConstructor>(\n BlocClass: T,\n): void {\n getRegistry().register(BlocClass);\n}\n","import { BLAC_STATIC_PROPS } from '../constants';\nimport type { EqualityFn } from '../config';\n\n/**\n * Configuration options for the `@blac` decorator. Any combination may be\n * given at once.\n */\nexport interface BlacOptions {\n /**\n * Keep the bloc alive when its ref count reaches 0. `false` turns off a\n * `keepAlive` inherited from a base class.\n */\n keepAlive?: boolean;\n /** Exclude bloc from DevTools tracking (prevents infinite loops) */\n excludeFromDevTools?: true;\n /**\n * Override the global equality check for this bloc.\n * Return `true` to skip the emit (states considered equal).\n */\n equality?: EqualityFn;\n /**\n * Override the default structural-hash identity key.\n * The function receives `args` and returns the instance key string.\n * Distinct return values → distinct instances; identical values → shared instance.\n * Non-identity fields can be excluded so they don't fork new instances.\n */\n key?: (args: any) => string;\n /**\n * Explicit, minification-safe identity for this bloc class. Falls back to\n * `constructor.name` when unset, which collides across classes once a\n * minifier shortens class names.\n */\n name?: string;\n}\n\n/**\n * Decorator to configure StateContainer classes.\n *\n * @example Decorator syntax (requires experimentalDecorators or TC39 decorators)\n * ```ts\n * @blac({ keepAlive: true })\n * class AuthBloc extends Cubit<AuthState> {}\n *\n * @blac({ excludeFromDevTools: true })\n * class InternalBloc extends Cubit<InternalState> {}\n *\n * @blac({ keepAlive: true, key: (args) => args.userId })\n * class UserBloc extends Cubit<UserState> {}\n * ```\n *\n * @example Function syntax (no decorator support needed)\n * ```ts\n * const AuthBloc = blac({ keepAlive: true })(\n * class extends Cubit<AuthState> {}\n * );\n * ```\n */\nexport function blac(options: BlacOptions) {\n return function <T extends new (...args: any[]) => any>(\n target: T,\n _context?: ClassDecoratorContext,\n ): T {\n if (options.keepAlive !== undefined) {\n (target as any)[BLAC_STATIC_PROPS.KEEP_ALIVE] = options.keepAlive;\n }\n if (options.excludeFromDevTools) {\n (target as any)[BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS] = true;\n }\n if (typeof options.equality === 'function') {\n (target as any)[BLAC_STATIC_PROPS.EQUALITY] = options.equality;\n }\n if (typeof options.key === 'function') {\n (target as any)[BLAC_STATIC_PROPS.KEY] = options.key;\n }\n if (typeof options.name === 'string') {\n (target as any)[BLAC_STATIC_PROPS.BLAC_NAME] = options.name;\n }\n return target;\n };\n}\n","import { ALL_PATHS } from '@dirtytalk/structural';\nimport { ON_DISPOSE } from '../core/symbols';\nimport { getRegistry } from '../registry';\nimport { resolveInstanceKey } from '../registry/acquire';\nimport type { StateContainerRegistry } from '../core/StateContainerRegistry';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\n\nconst STOP: unique symbol = Symbol('watch.STOP');\ntype StopSymbol = typeof STOP;\n\nconst BLOC_REF_MARKER = Symbol('BlocRef');\n\n/**\n * Reference to a specific bloc instance, identified by class + the resolved\n * key derived from its `args`.\n */\nexport interface BlocRef<T extends StateContainerConstructor> {\n [BLOC_REF_MARKER]: true;\n blocClass: T;\n /** @internal The resolved instance key (derived from `args`). */\n instanceId: string;\n /**\n * @internal The `args` used to derive `instanceId`. Forwarded to\n * `registry.acquire` so a not-yet-created instance is initialized with\n * these args instead of `undefined`.\n */\n args?: unknown;\n}\n\n/**\n * Create a reference to a specific bloc instance, identified by its `args`.\n * The key is derived the same way `useBloc`/`acquire` derive it.\n *\n * @example\n * ```ts\n * watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n */\nexport function instance<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): BlocRef<T> {\n return {\n [BLOC_REF_MARKER]: true,\n blocClass: BlocClass,\n instanceId: resolveInstanceKey(BlocClass, args),\n args,\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\n/**\n * Options for `watch`.\n */\nexport interface WatchOptions {\n /**\n * When `false`, `watch` observes passively: it neither creates a missing\n * instance nor takes a real ownership ref on an existing one. If the\n * instance does not exist yet, the callback simply never fires — `watch`\n * does not poll; call it again once the instance exists.\n *\n * Defaults to `true`.\n */\n create?: boolean;\n}\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\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 options?: WatchOptions,\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 options?: WatchOptions,\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 options?: WatchOptions,\n ): () => void;\n}\n\n/**\n * Class + resolved key + args needed to (re-)acquire a specific instance.\n * `watch` keeps this around per input so it can re-acquire the same logical\n * instance if the underlying container is disposed elsewhere.\n */\ninterface WatchTarget {\n blocClass: StateContainerConstructor;\n key: string;\n args: unknown;\n}\n\nfunction toWatchTarget(\n registry: StateContainerRegistry,\n input: BlocInput,\n): WatchTarget {\n if (isBlocRef(input)) {\n return {\n blocClass: input.blocClass,\n key: input.instanceId,\n args: input.args,\n };\n }\n return {\n blocClass: input,\n key: registry.resolveKey(input, undefined, undefined),\n args: undefined,\n };\n}\n\nlet watchRefSeq = 0;\n\n/**\n * Acquire a real ref (countRef: true) for the target, carrying its `args`\n * through so a not-yet-created instance is initialized correctly. The\n * caller is responsible for releasing `refId` in cleanup.\n */\nfunction resolveBloc(\n registry: StateContainerRegistry,\n target: WatchTarget,\n refId: string,\n): StateContainerInstance {\n return registry.acquire(target.blocClass, target.key, {\n countRef: true,\n refId,\n args: target.args,\n });\n}\n\n/**\n * Passive lookup for `{ create: false }`: never creates the instance and\n * never takes a ref. Returns `undefined` when no instance currently exists.\n */\nfunction resolveBlocPassive(\n registry: StateContainerRegistry,\n target: WatchTarget,\n): StateContainerInstance | undefined {\n try {\n return registry.acquire(target.blocClass, target.key, {\n canCreate: false,\n countRef: false,\n args: target.args,\n });\n } catch {\n return undefined;\n }\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 *\n * Thin wrapper around `container.channel.subscribe(ALL_PATHS, ...)`. The\n * callback fires once immediately, then on every state change of any of the\n * passed blocs. Returning `watch.STOP` from the callback tears down all\n * subscriptions. Subscriptions are microtask-deferred, so callbacks land\n * asynchronously after `emit()`.\n *\n * By default `watch` creates the instance if it does not exist and holds a\n * real ownership ref until `unwatch`, matching `acquire`. Pass\n * `{ create: false }` to observe passively instead — see `WatchOptions`.\n *\n * @example Single bloc\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * console.log(userBloc.state.name);\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, { userId: '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 options?: WatchOptions,\n): () => void;\n\nfunction watchImpl<T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n options?: WatchOptions,\n): () => void;\n\nfunction watchImpl(\n blocsOrBloc: BlocInput | readonly BlocInput[],\n callback: (blocsOrBloc: any) => void | StopSymbol,\n options?: WatchOptions,\n): () => void {\n const isSingle = !isArray(blocsOrBloc);\n const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;\n const registry = getRegistry();\n const create = options?.create ?? true;\n\n const targets = inputs.map((input) => toWatchTarget(registry, input));\n const refIds = targets.map(() => `_watch_${watchRefSeq++}`);\n const resolveAt = (index: number) =>\n create\n ? resolveBloc(registry, targets[index], refIds[index])\n : resolveBlocPassive(registry, targets[index]);\n\n let disposed = false;\n const instances: Array<StateContainerInstance | undefined> = [];\n const channelUnsubs: Array<(() => void) | undefined> = [];\n const disposedUnsubs: Array<(() => void) | undefined> = [];\n\n const cleanup = () => {\n if (disposed) return;\n disposed = true;\n for (const unsub of channelUnsubs) unsub?.();\n for (const unsub of disposedUnsubs) unsub?.();\n channelUnsubs.length = 0;\n disposedUnsubs.length = 0;\n if (create) {\n for (let i = 0; i < instances.length; i++) {\n registry.release(\n targets[i].blocClass,\n targets[i].key,\n false,\n refIds[i],\n );\n }\n }\n };\n\n const runCallback = () => {\n if (disposed) return;\n if (instances.some((i) => i === undefined)) return;\n const arg = isSingle ? instances[0] : instances;\n const result = callback(arg);\n if (result === STOP) cleanup();\n };\n\n const subscribeAt = (index: number) => {\n channelUnsubs[index] = instances[index]?.channel.subscribe(\n () => ALL_PATHS,\n runCallback,\n );\n };\n\n // On external dispose, tear down the stale subscription and re-acquire +\n // resubscribe (microtask-deferred, so it never runs mid-mutation of the\n // registry that triggered the dispose, e.g. `clearAll()`), then notify.\n const resubscribeAt = (index: number) => {\n if (disposed) return;\n instances[index] = resolveAt(index);\n subscribeAt(index);\n subscribeDisposeAt(index);\n runCallback();\n };\n\n const subscribeDisposeAt = (index: number) => {\n disposedUnsubs[index] = instances[index]?.[ON_DISPOSE](() => {\n channelUnsubs[index]?.();\n channelUnsubs[index] = undefined;\n queueMicrotask(() => resubscribeAt(index));\n });\n };\n\n try {\n for (let i = 0; i < targets.length; i++) instances.push(resolveAt(i));\n for (let i = 0; i < instances.length; i++) subscribeAt(i);\n for (let i = 0; i < instances.length; i++) subscribeDisposeAt(i);\n // Fire once immediately so the consumer sees the current state.\n runCallback();\n } catch (error) {\n cleanup();\n throw error;\n }\n\n return cleanup;\n}\n\nexport const watch: WatchFn = Object.assign(watchImpl, { STOP }) as WatchFn;\n","declare const brand: unique symbol;\n\n/**\n * Nominal type helper, preventing accidental confusion between similar\n * primitive types.\n * @typeParam T - The base type\n * @typeParam B - The brand identifier\n */\nexport type Brand<T, B> = T & { [brand]: B };\n\n/**\n * Branded string type for type-safe IDs.\n * @typeParam B - The brand identifier\n */\nexport type BrandedId<B> = Brand<string, B>;\n\n/** Branded string type for state container instance IDs. */\nexport type InstanceId = Brand<string, 'InstanceId'>;\n\nexport function instanceId(id: string): InstanceId {\n return id as InstanceId;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["ON_ACTIVATED","StateContainer","getRegistry","getRegistry","getRegistry","BLAC_STATIC_PROPS","resolveInstanceKey","getRegistry","ALL_PATHS","ON_DISPOSE"],"sources":["../src/core/onActivated.ts","../src/core/Cubit.ts","../src/registry/borrow.ts","../src/registry/release.ts","../src/registry/queries.ts","../src/registry/management.ts","../src/decorators/blac.ts","../src/watch/watch.ts","../src/types/branded.ts"],"sourcesContent":["import { ON_ACTIVATED } from './symbols';\nimport type { StateContainer } from './StateContainer';\n\n/**\n * Run `handler` each time `container` goes from unowned to owned, and now if it\n * is already owned. `signal` aborts on the matching deactivation and on\n * dispose. Returns an unsubscribe function.\n *\n * Unlike the protected `onActivate`, this can be called from a field\n * initializer or a helper that receives the container.\n */\nexport function onActivated(\n container: StateContainer<any, any, any>,\n handler: (signal: AbortSignal) => void,\n): () => void {\n return container[ON_ACTIVATED](handler);\n}\n","import { StateContainer } from './StateContainer';\nimport type { DeepPartial } from '@dirtytalk/structural';\n\n/**\n * `Cubit<S>` is a `StateContainer<S>` that exposes mutation publicly.\n *\n * That is the whole difference, and it is a real one: on `StateContainer`\n * `emit` / `patch` / `update` are `protected`, so a container mutates itself\n * from its own methods and callers go through the API it chooses to publish.\n * `Cubit` re-declares the three as `public` for the cases where a caller\n * legitimately drives state from outside — test helpers, devtools\n * time-travel, benchmarks.\n *\n * Reach for `StateContainer` when business logic should live in the class,\n * and `Cubit` when the caller owns the transitions.\n */\nexport abstract class Cubit<\n S extends object = any,\n Args = void,\n Deps extends object = Record<string, never>,\n> extends StateContainer<S, Args, Deps> {\n override emit(next: S): void {\n super.emit(next);\n }\n\n override patch(partial: DeepPartial<S>): void {\n super.patch(partial);\n }\n\n override update(fn: (state: S) => S): void {\n super.update(fn);\n }\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * How to identify the instance to borrow: the same `args` shape `useBloc`\n * accepts, resolved through the class's `static key(args)` so call sites use\n * the *same* shape they pass to `useBloc` instead of hand-deriving the key.\n *\n * `borrowSafe(ChannelBloc, { args: { channelId } })` and\n * `useBloc(ChannelBloc, { args: { channelId } })` therefore always agree.\n */\nexport type BorrowTarget<T extends StateContainerConstructor> = {\n args?: ExtractArgs<T>;\n};\n\nfunction resolveBorrowKey<T extends StateContainerConstructor>(\n BlocClass: T,\n target: BorrowTarget<T> | undefined,\n): string {\n return getRegistry().resolveKey(BlocClass, undefined, target?.args);\n}\n\nexport function borrow<T extends StateContainerConstructor>(\n BlocClass: T,\n target?: BorrowTarget<T>,\n): InstanceType<T> {\n return getRegistry().borrow(BlocClass, resolveBorrowKey(BlocClass, target));\n}\n\nexport function borrowSafe<T extends StateContainerConstructor>(\n BlocClass: T,\n target?: BorrowTarget<T>,\n):\n | { error: Error; instance: null }\n | { error: null; instance: InstanceType<T> } {\n return getRegistry().borrowSafe(\n BlocClass,\n resolveBorrowKey(BlocClass, target),\n );\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n} from '../types/utilities';\n\n/**\n * Release a reference to an instance. Instance identity is derived purely from\n * `args` (must match the `args` it was acquired with).\n *\n * @param opts - `args` derives the instance key (must match acquire);\n * `refId` picks the ref to drop, otherwise one arbitrary ref goes;\n * `forceDispose` disposes immediately regardless of remaining refs.\n */\nexport function release<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T>; refId?: string; forceDispose?: boolean },\n): void {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n registry.release(BlocClass, key, opts?.forceDispose ?? false, opts?.refId);\n}\n","import { getRegistry } from './config';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n InstanceReadonlyState,\n} from '../types/utilities';\n\n/**\n * @public\n */\nexport function hasInstance<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): boolean {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.hasInstance(BlocClass, key);\n}\n\n/**\n * @public\n */\nexport function getRefCount<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): number {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.getRefCount(BlocClass, key);\n}\n\n/**\n * @public\n */\nexport function getRefIds<T extends StateContainerConstructor>(\n BlocClass: T,\n opts?: { args?: ExtractArgs<T> },\n): string[] {\n const registry = getRegistry();\n const key = registry.resolveKey(BlocClass, undefined, opts?.args);\n return registry.getRefIds(BlocClass, key);\n}\n\n/**\n * @public\n */\nexport function getAll<T extends StateContainerConstructor>(\n BlocClass: T,\n): InstanceReadonlyState<T>[] {\n return getRegistry().getAll(BlocClass);\n}\n\n/**\n * @public\n */\nexport function forEach<T extends StateContainerConstructor>(\n BlocClass: T,\n callback: (instance: InstanceReadonlyState<T>) => void,\n): void {\n getRegistry().forEach(BlocClass, callback);\n}\n","import { getRegistry } from './config';\nimport type { StateContainer } from '../core/StateContainer';\nimport type { StateContainerConstructor } from '../types/utilities';\n\nexport function clear<T extends StateContainerConstructor>(BlocClass: T): void {\n getRegistry().clear(BlocClass);\n}\n\nexport function clearAll(): void {\n getRegistry().clearAll();\n}\n\nexport function clearWhere(\n predicate: (instance: StateContainer<any, any, any>) => boolean,\n): void {\n getRegistry().clearWhere(predicate);\n}\n\n/**\n * @public\n */\nexport function register<T extends StateContainerConstructor>(\n BlocClass: T,\n): void {\n getRegistry().register(BlocClass);\n}\n","import { BLAC_STATIC_PROPS } from '../constants';\nimport type { EqualityFn } from '../config';\n\n/**\n * Configuration options for the `@blac` decorator. Any combination may be\n * given at once.\n */\nexport interface BlacOptions {\n /**\n * Keep the bloc alive when its ref count reaches 0. `false` turns off a\n * `keepAlive` inherited from a base class.\n */\n keepAlive?: boolean;\n /**\n * Give each `useBloc` mount its own private instance, disposed when that\n * component unmounts. Applies to `useBloc` only; `ensure`/`acquire` still\n * resolve the shared instance. `false` turns off an `isolated` inherited\n * from a base class.\n */\n isolated?: boolean;\n /** Exclude bloc from DevTools tracking (prevents infinite loops) */\n excludeFromDevTools?: true;\n /**\n * Override the global equality check for this bloc.\n * Return `true` to skip the emit (states considered equal).\n */\n equality?: EqualityFn;\n /**\n * Override the default structural-hash identity key.\n * The function receives `args` and returns the instance key string.\n * Distinct return values → distinct instances; identical values → shared instance.\n * Non-identity fields can be excluded so they don't fork new instances.\n */\n key?: (args: any) => string;\n /**\n * Explicit, minification-safe identity for this bloc class. Falls back to\n * `constructor.name` when unset, which collides across classes once a\n * minifier shortens class names.\n */\n name?: string;\n}\n\n/**\n * Decorator to configure StateContainer classes.\n *\n * @example Decorator syntax (requires experimentalDecorators or TC39 decorators)\n * ```ts\n * @blac({ keepAlive: true })\n * class AuthBloc extends Cubit<AuthState> {}\n *\n * @blac({ excludeFromDevTools: true })\n * class InternalBloc extends Cubit<InternalState> {}\n *\n * @blac({ keepAlive: true, key: (args) => args.userId })\n * class UserBloc extends Cubit<UserState> {}\n * ```\n *\n * @example Function syntax (no decorator support needed)\n * ```ts\n * const AuthBloc = blac({ keepAlive: true })(\n * class extends Cubit<AuthState> {}\n * );\n * ```\n */\nexport function blac(options: BlacOptions) {\n return function <T extends new (...args: any[]) => any>(\n target: T,\n _context?: ClassDecoratorContext,\n ): T {\n if (options.keepAlive !== undefined) {\n (target as any)[BLAC_STATIC_PROPS.KEEP_ALIVE] = options.keepAlive;\n }\n if (options.isolated !== undefined) {\n (target as any)[BLAC_STATIC_PROPS.ISOLATED] = options.isolated;\n }\n if (options.excludeFromDevTools) {\n (target as any)[BLAC_STATIC_PROPS.EXCLUDE_FROM_DEVTOOLS] = true;\n }\n if (typeof options.equality === 'function') {\n (target as any)[BLAC_STATIC_PROPS.EQUALITY] = options.equality;\n }\n if (typeof options.key === 'function') {\n (target as any)[BLAC_STATIC_PROPS.KEY] = options.key;\n }\n if (typeof options.name === 'string') {\n (target as any)[BLAC_STATIC_PROPS.BLAC_NAME] = options.name;\n }\n return target;\n };\n}\n","import { ALL_PATHS } from '@dirtytalk/structural';\nimport { ON_DISPOSE } from '../core/symbols';\nimport { getRegistry } from '../registry';\nimport { resolveInstanceKey } from '../registry/acquire';\nimport type { StateContainerRegistry } from '../core/StateContainerRegistry';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\n\nconst STOP: unique symbol = Symbol('watch.STOP');\ntype StopSymbol = typeof STOP;\n\nconst BLOC_REF_MARKER = Symbol('BlocRef');\n\n/**\n * Reference to a specific bloc instance, identified by class + the resolved\n * key derived from its `args`.\n */\nexport interface BlocRef<T extends StateContainerConstructor> {\n [BLOC_REF_MARKER]: true;\n blocClass: T;\n /** @internal The resolved instance key (derived from `args`). */\n instanceId: string;\n /**\n * @internal The `args` used to derive `instanceId`. Forwarded to\n * `registry.acquire` so a not-yet-created instance is initialized with\n * these args instead of `undefined`.\n */\n args?: unknown;\n}\n\n/**\n * Create a reference to a specific bloc instance, identified by its `args`.\n * The key is derived the same way `useBloc`/`acquire` derive it.\n *\n * @example\n * ```ts\n * watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n */\nexport function instance<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): BlocRef<T> {\n return {\n [BLOC_REF_MARKER]: true,\n blocClass: BlocClass,\n instanceId: resolveInstanceKey(BlocClass, args),\n args,\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\n/**\n * Options for `watch`.\n */\nexport interface WatchOptions {\n /**\n * When `false`, `watch` observes passively: it neither creates a missing\n * instance nor takes a real ownership ref on an existing one. If the\n * instance does not exist yet, the callback simply never fires — `watch`\n * does not poll; call it again once the instance exists.\n *\n * Defaults to `true`.\n */\n create?: boolean;\n /**\n * Stops the watch when aborted, equivalent to calling the returned stop\n * function. An already-aborted signal returns a no-op stop without\n * creating or acquiring anything.\n */\n signal?: AbortSignal;\n}\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\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 options?: WatchOptions,\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 options?: WatchOptions,\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 options?: WatchOptions,\n ): () => void;\n}\n\n/**\n * Class + resolved key + args needed to (re-)acquire a specific instance.\n * `watch` keeps this around per input so it can re-acquire the same logical\n * instance if the underlying container is disposed elsewhere.\n */\ninterface WatchTarget {\n blocClass: StateContainerConstructor;\n key: string;\n args: unknown;\n}\n\nfunction toWatchTarget(\n registry: StateContainerRegistry,\n input: BlocInput,\n): WatchTarget {\n if (isBlocRef(input)) {\n return {\n blocClass: input.blocClass,\n key: input.instanceId,\n args: input.args,\n };\n }\n return {\n blocClass: input,\n key: registry.resolveKey(input, undefined, undefined),\n args: undefined,\n };\n}\n\nlet watchRefSeq = 0;\n\n/**\n * Acquire a real ref (countRef: true) for the target, carrying its `args`\n * through so a not-yet-created instance is initialized correctly. The\n * caller is responsible for releasing `refId` in cleanup.\n */\nfunction resolveBloc(\n registry: StateContainerRegistry,\n target: WatchTarget,\n refId: string,\n): StateContainerInstance {\n return registry.acquire(target.blocClass, target.key, {\n countRef: true,\n refId,\n args: target.args,\n });\n}\n\n/**\n * Passive lookup for `{ create: false }`: never creates the instance and\n * never takes a ref. Returns `undefined` when no instance currently exists.\n */\nfunction resolveBlocPassive(\n registry: StateContainerRegistry,\n target: WatchTarget,\n): StateContainerInstance | undefined {\n try {\n return registry.acquire(target.blocClass, target.key, {\n canCreate: false,\n countRef: false,\n args: target.args,\n });\n } catch {\n return undefined;\n }\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 *\n * Thin wrapper around `container.channel.subscribe(() => ALL_PATHS, ...)`. The\n * callback fires once immediately, then on every state change of any of the\n * passed blocs. Returning `watch.STOP` from the callback tears down all\n * subscriptions. Subscriptions are microtask-deferred, so callbacks land\n * asynchronously after `emit()`.\n *\n * By default `watch` creates the instance if it does not exist and holds a\n * real ownership ref until `unwatch`, matching `acquire`. Pass\n * `{ create: false }` to observe passively instead — see `WatchOptions`.\n *\n * @example Single bloc\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * console.log(userBloc.state.name);\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, { userId: '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 options?: WatchOptions,\n): () => void;\n\nfunction watchImpl<T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n options?: WatchOptions,\n): () => void;\n\nfunction watchImpl(\n blocsOrBloc: BlocInput | readonly BlocInput[],\n callback: (blocsOrBloc: any) => void | StopSymbol,\n options?: WatchOptions,\n): () => void {\n const isSingle = !isArray(blocsOrBloc);\n const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;\n const registry = getRegistry();\n const create = options?.create ?? true;\n const signal = options?.signal;\n if (signal?.aborted) return () => {};\n\n const targets = inputs.map((input) => toWatchTarget(registry, input));\n const refIds = targets.map(() => `_watch_${watchRefSeq++}`);\n const resolveAt = (index: number) =>\n create\n ? resolveBloc(registry, targets[index], refIds[index])\n : resolveBlocPassive(registry, targets[index]);\n\n let disposed = false;\n const instances: Array<StateContainerInstance | undefined> = [];\n const channelUnsubs: Array<(() => void) | undefined> = [];\n const disposedUnsubs: Array<(() => void) | undefined> = [];\n\n const cleanup = () => {\n if (disposed) return;\n disposed = true;\n signal?.removeEventListener('abort', cleanup);\n for (const unsub of channelUnsubs) unsub?.();\n for (const unsub of disposedUnsubs) unsub?.();\n channelUnsubs.length = 0;\n disposedUnsubs.length = 0;\n if (create) {\n for (let i = 0; i < instances.length; i++) {\n registry.release(\n targets[i].blocClass,\n targets[i].key,\n false,\n refIds[i],\n );\n }\n }\n };\n\n const runCallback = () => {\n if (disposed) return;\n if (instances.some((i) => i === undefined)) return;\n const arg = isSingle ? instances[0] : instances;\n const result = callback(arg);\n if (result === STOP) cleanup();\n };\n\n const subscribeAt = (index: number) => {\n channelUnsubs[index] = instances[index]?.channel.subscribe(\n () => ALL_PATHS,\n runCallback,\n );\n };\n\n // On external dispose, tear down the stale subscription and re-acquire +\n // resubscribe (microtask-deferred, so it never runs mid-mutation of the\n // registry that triggered the dispose, e.g. `clearAll()`), then notify.\n const resubscribeAt = (index: number) => {\n if (disposed) return;\n instances[index] = resolveAt(index);\n subscribeAt(index);\n subscribeDisposeAt(index);\n runCallback();\n };\n\n const subscribeDisposeAt = (index: number) => {\n disposedUnsubs[index] = instances[index]?.[ON_DISPOSE](() => {\n channelUnsubs[index]?.();\n channelUnsubs[index] = undefined;\n queueMicrotask(() => resubscribeAt(index));\n });\n };\n\n signal?.addEventListener('abort', cleanup, { once: true });\n\n try {\n for (let i = 0; i < targets.length; i++) instances.push(resolveAt(i));\n for (let i = 0; i < instances.length; i++) subscribeAt(i);\n for (let i = 0; i < instances.length; i++) subscribeDisposeAt(i);\n // Fire once immediately so the consumer sees the current state.\n runCallback();\n } catch (error) {\n cleanup();\n throw error;\n }\n\n return cleanup;\n}\n\nexport const watch: WatchFn = Object.assign(watchImpl, { STOP }) as WatchFn;\n","declare const brand: unique symbol;\n\n/**\n * Nominal type helper, preventing accidental confusion between similar\n * primitive types.\n * @typeParam T - The base type\n * @typeParam B - The brand identifier\n */\nexport type Brand<T, B> = T & { [brand]: B };\n\n/**\n * Branded string type for type-safe IDs.\n * @typeParam B - The brand identifier\n */\nexport type BrandedId<B> = Brand<string, B>;\n\n/** Branded string type for state container instance IDs. */\nexport type InstanceId = Brand<string, 'InstanceId'>;\n\nexport function instanceId(id: string): InstanceId {\n return id as InstanceId;\n}\n"],"mappings":";;;;;;;;;;;;;;AAWA,SAAgB,YACd,WACA,SACY;CACZ,OAAO,UAAUA,+BAAAA,cAAc,OAAO;AACxC;;;;;;;;;;;;;;;;ACAA,IAAsB,QAAtB,cAIUC,uBAAAA,eAA8B;CACtC,KAAc,MAAe;EAC3B,MAAM,KAAK,IAAI;CACjB;CAEA,MAAe,SAA+B;EAC5C,MAAM,MAAM,OAAO;CACrB;CAEA,OAAgB,IAA2B;EACzC,MAAM,OAAO,EAAE;CACjB;AACF;;;ACdA,SAAS,iBACP,WACA,QACQ;CACR,OAAOC,uBAAAA,YAAY,EAAE,WAAW,WAAW,KAAA,GAAW,QAAQ,IAAI;AACpE;AAEA,SAAgB,OACd,WACA,QACiB;CACjB,OAAOA,uBAAAA,YAAY,EAAE,OAAO,WAAW,iBAAiB,WAAW,MAAM,CAAC;AAC5E;AAEA,SAAgB,WACd,WACA,QAG6C;CAC7C,OAAOA,uBAAAA,YAAY,EAAE,WACnB,WACA,iBAAiB,WAAW,MAAM,CACpC;AACF;;;;;;;;;;;AC5BA,SAAgB,QACd,WACA,MACM;CACN,MAAM,WAAWC,uBAAAA,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,SAAS,QAAQ,WAAW,KAAK,MAAM,gBAAgB,OAAO,MAAM,KAAK;AAC3E;;;;;;ACXA,SAAgB,YACd,WACA,MACS;CACT,MAAM,WAAWC,uBAAAA,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,YAAY,WAAW,GAAG;AAC5C;;;;AAKA,SAAgB,YACd,WACA,MACQ;CACR,MAAM,WAAWA,uBAAAA,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,YAAY,WAAW,GAAG;AAC5C;;;;AAKA,SAAgB,UACd,WACA,MACU;CACV,MAAM,WAAWA,uBAAAA,YAAY;CAC7B,MAAM,MAAM,SAAS,WAAW,WAAW,KAAA,GAAW,MAAM,IAAI;CAChE,OAAO,SAAS,UAAU,WAAW,GAAG;AAC1C;;;;AAKA,SAAgB,OACd,WAC4B;CAC5B,OAAOA,uBAAAA,YAAY,EAAE,OAAO,SAAS;AACvC;;;;AAKA,SAAgB,QACd,WACA,UACM;CACN,uBAAA,YAAY,EAAE,QAAQ,WAAW,QAAQ;AAC3C;;;ACxDA,SAAgB,MAA2C,WAAoB;CAC7E,uBAAA,YAAY,EAAE,MAAM,SAAS;AAC/B;AAEA,SAAgB,WAAiB;CAC/B,uBAAA,YAAY,EAAE,SAAS;AACzB;AAEA,SAAgB,WACd,WACM;CACN,uBAAA,YAAY,EAAE,WAAW,SAAS;AACpC;;;;AAKA,SAAgB,SACd,WACM;CACN,uBAAA,YAAY,EAAE,SAAS,SAAS;AAClC;;;;;;;;;;;;;;;;;;;;;;;;;ACuCA,SAAgB,KAAK,SAAsB;CACzC,OAAO,SACL,QACA,UACG;EACH,IAAI,QAAQ,cAAc,KAAA,GACxB,OAAgBC,+BAAAA,kBAAkB,cAAc,QAAQ;EAE1D,IAAI,QAAQ,aAAa,KAAA,GACvB,OAAgBA,+BAAAA,kBAAkB,YAAY,QAAQ;EAExD,IAAI,QAAQ,qBACV,OAAgBA,+BAAAA,kBAAkB,yBAAyB;EAE7D,IAAI,OAAO,QAAQ,aAAa,YAC9B,OAAgBA,+BAAAA,kBAAkB,YAAY,QAAQ;EAExD,IAAI,OAAO,QAAQ,QAAQ,YACzB,OAAgBA,+BAAAA,kBAAkB,OAAO,QAAQ;EAEnD,IAAI,OAAO,QAAQ,SAAS,UAC1B,OAAgBA,+BAAAA,kBAAkB,aAAa,QAAQ;EAEzD,OAAO;CACT;AACF;;;AC9EA,MAAM,OAAsB,OAAO,YAAY;AAG/C,MAAM,kBAAkB,OAAO,SAAS;;;;;;;;;;;;AA8BxC,SAAgB,SACd,WACA,MACY;CACZ,OAAO;GACJ,kBAAkB;EACnB,WAAW;EACX,YAAYC,eAAAA,mBAAmB,WAAW,IAAI;EAC9C;CACF;AACF;AAEA,SAAS,UACP,OAC6C;CAC7C,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,mBAAmB;AAEtE;AAoFA,SAAS,cACP,UACA,OACa;CACb,IAAI,UAAU,KAAK,GACjB,OAAO;EACL,WAAW,MAAM;EACjB,KAAK,MAAM;EACX,MAAM,MAAM;CACd;CAEF,OAAO;EACL,WAAW;EACX,KAAK,SAAS,WAAW,OAAO,KAAA,GAAW,KAAA,CAAS;EACpD,MAAM,KAAA;CACR;AACF;AAEA,IAAI,cAAc;;;;;;AAOlB,SAAS,YACP,UACA,QACA,OACwB;CACxB,OAAO,SAAS,QAAQ,OAAO,WAAW,OAAO,KAAK;EACpD,UAAU;EACV;EACA,MAAM,OAAO;CACf,CAAC;AACH;;;;;AAMA,SAAS,mBACP,UACA,QACoC;CACpC,IAAI;EACF,OAAO,SAAS,QAAQ,OAAO,WAAW,OAAO,KAAK;GACpD,WAAW;GACX,UAAU;GACV,MAAM,OAAO;EACf,CAAC;CACH,QAAQ;EACN;CACF;AACF;AAEA,SAAS,QAAQ,OAA+C;CAC9D,OAAO,MAAM,QAAQ,KAAK;AAC5B;AA+DA,SAAS,UACP,aACA,UACA,SACY;CACZ,MAAM,WAAW,CAAC,QAAQ,WAAW;CACrC,MAAM,SAAS,WAAW,CAAC,WAAW,IAAI;CAC1C,MAAM,WAAWC,uBAAAA,YAAY;CAC7B,MAAM,SAAS,SAAS,UAAU;CAClC,MAAM,SAAS,SAAS;CACxB,IAAI,QAAQ,SAAS,aAAa,CAAC;CAEnC,MAAM,UAAU,OAAO,KAAK,UAAU,cAAc,UAAU,KAAK,CAAC;CACpE,MAAM,SAAS,QAAQ,UAAU,UAAU,eAAe;CAC1D,MAAM,aAAa,UACjB,SACI,YAAY,UAAU,QAAQ,QAAQ,OAAO,MAAM,IACnD,mBAAmB,UAAU,QAAQ,MAAM;CAEjD,IAAI,WAAW;CACf,MAAM,YAAuD,CAAC;CAC9D,MAAM,gBAAiD,CAAC;CACxD,MAAM,iBAAkD,CAAC;CAEzD,MAAM,gBAAgB;EACpB,IAAI,UAAU;EACd,WAAW;EACX,QAAQ,oBAAoB,SAAS,OAAO;EAC5C,KAAK,MAAM,SAAS,eAAe,QAAQ;EAC3C,KAAK,MAAM,SAAS,gBAAgB,QAAQ;EAC5C,cAAc,SAAS;EACvB,eAAe,SAAS;EACxB,IAAI,QACF,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACpC,SAAS,QACP,QAAQ,GAAG,WACX,QAAQ,GAAG,KACX,OACA,OAAO,EACT;CAGN;CAEA,MAAM,oBAAoB;EACxB,IAAI,UAAU;EACd,IAAI,UAAU,MAAM,MAAM,MAAM,KAAA,CAAS,GAAG;EAG5C,IADe,SADH,WAAW,UAAU,KAAK,SAE7B,MAAM,MAAM,QAAQ;CAC/B;CAEA,MAAM,eAAe,UAAkB;EACrC,cAAc,SAAS,UAAU,QAAQ,QAAQ,gBACzCC,sBAAAA,WACN,WACF;CACF;CAKA,MAAM,iBAAiB,UAAkB;EACvC,IAAI,UAAU;EACd,UAAU,SAAS,UAAU,KAAK;EAClC,YAAY,KAAK;EACjB,mBAAmB,KAAK;EACxB,YAAY;CACd;CAEA,MAAM,sBAAsB,UAAkB;EAC5C,eAAe,SAAS,UAAU,SAASC,+BAAAA,kBAAkB;GAC3D,cAAc,SAAS;GACvB,cAAc,SAAS,KAAA;GACvB,qBAAqB,cAAc,KAAK,CAAC;EAC3C,CAAC;CACH;CAEA,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAEzD,IAAI;EACF,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,UAAU,KAAK,UAAU,CAAC,CAAC;EACpE,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,YAAY,CAAC;EACxD,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,mBAAmB,CAAC;EAE/D,YAAY;CACd,SAAS,OAAO;EACd,QAAQ;EACR,MAAM;CACR;CAEA,OAAO;AACT;AAEA,MAAa,QAAiB,OAAO,OAAO,WAAW,EAAE,KAAK,CAAC;;;ACtV/D,SAAgB,WAAW,IAAwB;CACjD,OAAO;AACT"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
export { configureBlac, getBlacConfig, resetBlacConfig, shallowEqualState, type BlacConfig, type EqualityFn, } from './config';
|
|
2
2
|
export { StateContainer } from './core/StateContainer';
|
|
3
|
+
export { onActivated } from './core/onActivated';
|
|
3
4
|
export type { HydrationStatus, StateContainerConfig, SystemEvent, SystemEventPayloads, DepHandle, } from './core/StateContainer';
|
|
4
5
|
export { Cubit } from './core/Cubit';
|
|
5
6
|
export type { BlacMeta, BlacHydration } from './core/meta';
|
|
6
7
|
export { ALL_PATHS } from '@dirtytalk/structural';
|
|
7
8
|
export type { PathSet } from '@dirtytalk/structural';
|
|
8
|
-
export { acquire, resolveInstanceKey, borrow, borrowSafe, ensure, release, clear, clearAll, register, hasInstance, getRefCount, getRefIds, getAll, forEach, getRegistry, setRegistry, getStats, } from './registry';
|
|
9
|
+
export { acquire, resolveInstanceKey, borrow, borrowSafe, ensure, release, clear, clearAll, clearWhere, register, hasInstance, getRefCount, getRefIds, getAll, forEach, getRegistry, setRegistry, getStats, } from './registry';
|
|
9
10
|
export type { BorrowTarget } from './registry';
|
|
10
11
|
export { globalRegistry, StateContainerRegistry, } from './core/StateContainerRegistry';
|
|
11
12
|
export type { LifecycleEvent, LifecycleListener, InstanceEntry, } from './core/StateContainerRegistry';
|
|
12
13
|
export { blac, type BlacOptions } from './decorators';
|
|
13
|
-
export { isKeepAliveClass, isExcludedFromDevTools, getBlacName, } from './utils/static-props';
|
|
14
|
+
export { isKeepAliveClass, isIsolatedClass, isExcludedFromDevTools, getBlacName, } from './utils/static-props';
|
|
14
15
|
export type { BlacPlugin, BlacPluginWithInit, PluginContext, PluginConfig, InstanceMetadata, } from './plugin/BlacPlugin';
|
|
15
16
|
export { watch, instance, type WatchFn, type WatchOptions, type BlocRef, } from './watch';
|
|
16
17
|
export type { StateContainerConstructor, DeepReadonly, ExtractState, ExtractStateMutable, ExtractArgs, ExtractDeps, InstanceReadonlyState, WithState, InstanceState, StateContainerInstance, } from './types/utilities';
|