The registry is a global singleton that manages the lifecycle of state container instances. It handles creation, sharing, ref counting, and disposal. Every signature on this page is quoted from the @blac/core source.
Think of the registry as a lending library for bloc instances:
Each (class, instanceKey) pair is one book on the shelf. Ask for the same pair twice and you get the same physical book — that is how two components share state without prop-drilling.
A consumer that needs a book checks it out (acquire) and returns it (release) when done. Every checkout is a reference (a “ref”).
The library keeps a count of who has each book checked out. When the count drops to zero, the book is discarded (dispose) — its state is gone and any timers or subscriptions it set up are torn down.
keepAlive marks a book as a permanent reference copy: it stays on the shelf even at zero checkouts.
Two consequences fall straight out of this model:
Sharing is automatic. The first acquire of a key creates the instance; every later acquire of the same key reuses it. You never wire instances together by hand.
Cleanup is automatic — but only if every checkout is returned. A missing release is like never returning a library book: the count never reaches zero, the instance never disposes, and its memory (and subscriptions) leak.
The functions below (acquire, ensure, borrow, release, …) are the app-author tier: every parameter is an opts object keyed by args, never a positional string key. Underneath them sits a lower-level tier — globalRegistry (a StateContainerRegistry instance) — whose methods take an already-resolved instanceKey: string instead of args. @blac/react’s useBloc and watch() are built on that lower tier; application code should reach for the args-based functions above it.
The state-container class to acquire an instance of.
opts.args
ExtractArgs<T>
no
Serializable construction data passed to init(args). Derives the instance key.
opts.refId
string
no
Caller-supplied ref identifier. Used by useBloc to pair with release. Rarely set manually.
Returns:InstanceType<T> — the live instance (newly created or existing).
Behavior. The instance key is derived from opts.args (static key if declared, else the structural hash, else 'default'). If no instance exists for the resolved key, acquire creates one, calls init(args), and fires the internal 'created' event. If an instance already exists, it is returned as-is. The ref count is always incremented. Every acquire must have a matching release — a missing release is the canonical instance leak. In React, useBloc owns this pair; call acquire directly only in server-side or scripting contexts.
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
acquire(
classCounterCubit
CounterCubit);
constcounter: CounterCubit
counter.
CounterCubit.increment: ()=>void
increment();
varconsole: Console
console.
Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
Returns:string — the same key acquire/ensure/borrow/release would derive for these args (static key(args) if declared, else the structural hash, else 'default').
Behavior. Pure — it does not create, look up, or ref any instance. Use it when you need to know ahead of time whether two args values will collide on the same instance (e.g. deduping a batch of acquire calls, or building a cache keyed the same way the registry keys instances).
Resolve the storage key an instance would be acquired under, given its
construction args. This is the canonical key-computation path. Callers that
both acquire and release against the @internal registry tier (e.g.
@blac/reactuseBloc) must use this once and pass the same resolved key to
both, so the ref is dropped under the key it was taken.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Resolve the storage key an instance would be acquired under, given its
construction args. This is the canonical key-computation path. Callers that
both acquire and release against the @internal registry tier (e.g.
@blac/reactuseBloc) must use this once and pass the same resolved key to
both, so the ref is dropped under the key it was taken.
Construction data for init(args) and key derivation.
Returns:InstanceType<T> — the live instance.
Behavior. Like acquire, but takes no ref — the instance can be disposed by another caller while you hold the returned reference. Use ensure inside other cubits (via depend()) or in tooling that only needs the instance to exist without pinning its lifecycle. Because no ref is taken, no matching release is needed.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<{
userId:string|null
userId: string | null }>{
constructor(){
super({
userId:string|null
userId:null});
}
}
// ensure creates AuthCubit if it's not alive yet, but does not keep it alive
Args identifying the instance. Defaults to the 'default' key.
Returns:InstanceType<T> — the live instance.
Behavior. Does not create the instance if it is absent; throws an Error instead. Use borrow when the absence of an instance is a programming error — it makes the failure loud and immediate rather than silently returning undefined. No ref is taken, so no release is needed.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<{
count:number
count: number }>{
constructor(){
super({
count:number
count:0});
}
}
// Safe read-only access — no acquire/release pair needed
Args identifying the instance. Defaults to the 'default' key.
Returns:{ error: null; instance: InstanceType<T> } when the instance exists, or { error: Error; instance: null } when it does not.
Behavior. Identical to borrow but returns a discriminated union instead of throwing. Prefer borrowSafe in code paths where absence is expected (e.g. optional integrations) and borrow where absence is always a bug.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
The args used when acquire was called. Must resolve to the same key.
opts.refId
string
no
The ref identifier passed to acquire. Rarely set manually.
opts.forceDispose
boolean
no
When true, dispose immediately even if keepAlive is set. Default false.
Returns:void.
Behavior.release is idempotent for an already-dropped ref — releasing more times than you acquired won’t throw, it just no-ops once the count is gone. The args you release with must resolve to the same key you acquired with; a mismatch leaves the original ref dangling forever. At ref count zero, the instance is disposed synchronously (unless keepAlive is set or forceDispose is false).
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
Release a reference using the instance as the identity, for callers that hold a container but not the args it was acquired with.
functionreleaseInstance(
instance: StateContainerInstance,
opts?:{forceDispose?: boolean;refId?: string },
): void;
Parameter
Type
Required
Description
instance
StateContainerInstance
yes
The container instance to release. Safe to call with an unknown/foreign one.
opts.forceDispose
boolean
no
When true, dispose immediately even if keepAlive is set. Default false.
opts.refId
string
no
The ref identifier to drop. Rarely set manually.
Returns:void.
Behavior.release is keyed by args; releaseInstance is keyed by the instance itself, for teardown loops that only hold a reference (e.g. “close this workspace, dispose everything it owns”) and never learned the args an instance was acquired with. It never throws — safe to call on an unknown instance, a transient one created with new outside the registry, or an already-disposed instance. It is idempotent: once the instance is gone from the registry, a second call is a no-op. forceDispose semantics are identical to release.
Release a reference using the INSTANCE as the identity, for callers that
hold a container but not the args it was acquired with (teardown loops).
Never throws — safe on an unknown, transient, already-disposed, or
non-registry instance, and idempotent. Teardown loops depend on this.
Idempotence is structural, not guarded here: once the instance is gone from
the registry registry.release returns early on its own missing-entry check
(StateContainerRegistry.ts:636), so a second call is a no-op. Do not add a
redundant guard.
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<{
open:boolean
open: boolean }>{
constructor(){
super({
open:boolean
open:true});
}
}
// A teardown loop holding only instances, not the args they were acquired with
Release a reference using the INSTANCE as the identity, for callers that
hold a container but not the args it was acquired with (teardown loops).
Never throws — safe on an unknown, transient, already-disposed, or
non-registry instance, and idempotent. Teardown loops depend on this.
Idempotence is structural, not guarded here: once the instance is gone from
the registry registry.release returns early on its own missing-entry check
(StateContainerRegistry.ts:636), so a second call is a no-op. Do not add a
redundant guard.
releaseInstance(
constinstance: WorkspaceCubit
instance);// never throws, even on an already-disposed instance
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
To manage distinct named instances, declare an Args shape and pass args to any registry function. The instance key is derived from those args — a static key if the class declares one, otherwise the structural hash of the args:
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
args are the only way to get distinct instances — the meaningful value keys the instance and feeds init(args), so you never pass the same id twice:
// The meaningful value keys the instance AND feeds init(args)
const[s]=useBloc(UserCardCubit,{ args:{userId}});
Identity precedence (own args vs <BlocProvider> args vs no args) is canonical at useBloc: Identity and keying — this page and that one must agree.
The resolved key is the registry’s single source of truth — acquire and release both run their args through the same resolution, so a ref taken under a given args key is dropped under the same key. See Passing Inputs for the full model and Configuration for static key.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
acquire(
classCounterCubit
CounterCubit);
constcounter: CounterCubit
counter.
CounterCubit.increment: ()=>void
increment();
varconsole: Console
console.
Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
Symptom: A component unmounts and remounts and finds the bloc in its initial state — any previous state is gone.
Cause: When the last consumer releases, the instance is disposed immediately (ref count 0 → dispose). The next consumer acquires a brand-new instance with fresh state.
Fix: If state must persist across unmounts, mark the class keepAlive:
import{
functionblac(options: BlacOptions):<T extendsnew(...args: any[])=> any>(target: T,_context?: ClassDecoratorContext)=> T
Decorator to configure StateContainer classes.
@example
Decorator syntax (requires experimentalDecorators or TC39 decorators)
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit}from'@blac/core';
interface
interfaceSessionState
SessionState{
SessionState.token: string|null
token: string | null;
}
@
functionblac(options: BlacOptions):<T extendsnew(...args: any[])=> any>(target: T,_context?: ClassDecoratorContext)=> T
Decorator to configure StateContainer classes.
@example
Decorator syntax (requires experimentalDecorators or TC39 decorators)
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<
interfaceSessionState
SessionState>{
constructor(){
super({
SessionState.token: string|null
token:null});
}
}
keepAlive instances are never auto-disposed at ref count 0 — tear them down explicitly with release(Class, { forceDispose: true }) or clear(Class) in teardown. See Configuration.
Symptom: DevTools shows an instance that should have been disposed is still alive, or ref count never returns to 0.
Cause: An acquire outside React has no matching release. Every call to acquire increments the ref count; without a matching release the count never reaches zero.
Fix: Pair every acquire with a release, ideally in a try/finally. If you only need to read without owning the lifecycle, use borrow or ensure — neither takes a ref:
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
Symptom:acquire throws with a message like “exceeded the maximum live instances” or “exceeded the maximum refs.”
Cause: Almost always a leak — an unstable instance key (non-serializable args) spawning endless instances, or a missing release accumulating refs. The limit is not too low; the leak is real.
Fix: Find and fix the leak before raising the limit. Common causes: non-serializable values in args (fix: move to deps), acquire without release (fix: pair them), args that differ structurally each render (fix: normalise types). See Configuration: circuit breakers and Troubleshooting.