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 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 derives the instance key; refId names the reference
for debugging and is auto-generated when omitted.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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 derives the instance key; refId names the reference
for debugging and is auto-generated when omitted.
acquire(
classCounterCubit
CounterCubit);
const counter:CounterCubit
counter.
CounterCubit.increment: ()=>void
increment();
var console:Console
console.
Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
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> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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 derives the instance key; refId names the reference
for debugging and is auto-generated when omitted.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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 derives the instance key; refId names the reference
for debugging and is auto-generated when omitted.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
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 derives the instance key; refId names the reference
for debugging and is auto-generated when omitted.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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 derives the instance key; refId names the reference
for debugging and is auto-generated when 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 derives the instance key; refId names the reference
for debugging and is auto-generated when omitted.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
Identity precedence: own args (via static key(args), else structural hash of args) > <BlocProvider> context args > 'default'.
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> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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 derives the instance key; refId names the reference
for debugging and is auto-generated when omitted.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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 derives the instance key; refId names the reference
for debugging and is auto-generated when omitted.
acquire(
classCounterCubit
CounterCubit);
const counter:CounterCubit
counter.
CounterCubit.increment: ()=>void
increment();
var console:Console
console.
Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
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:
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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 derives the instance key; refId names the reference
for debugging and is auto-generated when omitted.
Release a reference to an instance. Instance identity is derived purely from
args (must match the args it was acquired with).
@param ― opts - args derives the instance key (must match acquire);
refId picks the ref to drop, otherwise one arbitrary ref goes;
forceDispose disposes immediately regardless of remaining refs.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
Cubit<S> is a StateContainer<S> that exposes mutation publicly.
That is the whole difference, and it is a real one: on StateContaineremit / patch / update are protected, so a container mutates itself
from its own methods and callers go through the API it chooses to publish.
Cubit re-declares the three as public for the cases where a caller
legitimately drives state from outside — test helpers, devtools
time-travel, benchmarks.
Reach for StateContainer when business logic should live in the class,
and Cubit when the caller owns the transitions.
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 derives the instance key; refId names the reference
for debugging and is auto-generated when 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.