@langchain/langgraph-sdk
Version:
Client library for interacting with the LangGraph API
103 lines (102 loc) • 4.35 kB
text/typescript
import { ThreadStream } from "../client/stream/index.cjs";
import { AcquiredProjection, ProjectionSpec, RootEventBus } from "./types.cjs";
//#region src/stream/channel-registry.d.ts
/**
* Ref-counted, thread-aware projection registry.
*
* Owns the `spec.key → (store, runtime)` mapping for one
* {@link StreamController}. Lifecycle:
*
* - `acquire(spec)` → +1 ref, returns `{ store, release }`. The
* first acquire opens the projection's runtime; subsequent
* acquires for the same key share both the store and the
* runtime.
* - `release()` → -1 ref. When the last consumer releases,
* the entry is removed and its runtime disposed.
* - `bind(thread)` → swap or detach the underlying thread; every
* live entry's runtime is recreated against the new thread,
* keeping the same store identity.
* - `dispose()` → tear everything down (idempotent). Safe to
* call multiple times.
*
* The registry is intentionally not generic over a state shape —
* different consumers can hold projections producing different
* snapshot types, so the registry keys everything as `unknown` and
* lets {@link acquire} reapply the caller's `T` at the boundary.
*/
declare class ChannelRegistry {
#private;
/**
* Construct a registry bound to the controller's root event bus.
*
* The bus is forwarded to every projection's `open()` so root-scoped
* projections can avoid opening a second server subscription when
* their channel set is already covered by the root pump.
*
* @param rootBus - Read-only fan-out of the root subscription.
*/
constructor(rootBus: RootEventBus);
/**
* Rebind every live entry to a new {@link ThreadStream} (or detach
* when `thread == null`).
*
* Each live entry has its current runtime disposed (best-effort)
* and its store reset to `entry.initial` so consumers see a clean
* slate during the swap. When `thread != null`, a fresh runtime is
* opened against the new thread.
*
* Critically the {@link StreamStore} *instance* is preserved across
* the rebind: framework subscribers (e.g. React's
* `useSyncExternalStore`) keep observing the same store reference,
* so their subscriptions survive the swap.
*
* No-op when called with the currently bound thread.
*
* @param thread - The thread stream to bind, or `undefined` to detach.
*/
bind(thread: ThreadStream | undefined): void;
/** Currently bound thread (may be `undefined` pre-mount). */
get thread(): ThreadStream | undefined;
/**
* Acquire a ref-counted projection.
*
* If no entry exists for `spec.key`, one is created (allocating a
* {@link StreamStore} seeded with `spec.initial`) and — when a
* thread is currently bound — its runtime is opened immediately.
* If an entry already exists, its ref count is incremented and the
* existing store is returned.
*
* The returned `release()` is idempotent: calling it more than once
* is a no-op. When the ref count drops to zero, the entry is removed
* and its runtime disposed (best-effort, never throws into callers).
*
* Safe to call from any framework lifecycle hook. Subsequent calls
* for the same `spec.key` always return the same `store` reference
* for the lifetime of the controller, so consumers can rely on store
* identity.
*
* @typeParam T - Snapshot type produced by this projection.
* @param spec - Projection contract; the registry keys off `spec.key`.
* @returns A `{ store, release }` handle.
*/
acquire<T>(spec: ProjectionSpec<T>): AcquiredProjection<T>;
/**
* Tear everything down.
*
* Detaches the bound thread (so no further `bind()` calls reopen
* runtimes) and disposes every live runtime in parallel. Safe to
* call multiple times — subsequent calls find an empty registry
* and resolve immediately.
*/
dispose(): Promise<void>;
/**
* Number of actively-held entries. Diagnostic-only — callers should
* not branch on this value at runtime; it exists for tests asserting
* that consumers properly release their projections. Entries waiting
* on cancellable microtask disposal do not count as active.
*/
get size(): number;
}
//#endregion
export { ChannelRegistry };
//# sourceMappingURL=channel-registry.d.cts.map