/** * A typed registry of extensions, keyed by `kind:name`. Implementations * **self-register** their extensions (connectors, commands …) as a side-effect of * import; composition roots just import the packages they want and then resolve. * * Core stays ignorant of which extensions exist: they plug into the registry, not * the other way round. An unknown extension throws; no silent fallback. * * Materializing an installed package must be TRANSACTIONAL and INVISIBLE: a package that registers a * key and then throws (a rejected top-level await) must leave NO resolvable keys, and a package that * imports cleanly but never advertises the requested key must leave NONE of its registrations live. * {@link runStaged} scopes an import's registrations to a per-import stage via `AsyncLocalStorage`: * they are invisible to {@link resolve}/{@link all} until {@link commitStaged} publishes them * atomically. Registrations made in OTHER async contexts during the import's awaits go straight to * live and are never captured (so a rollback never discards an unrelated registration). */ export interface Extension { readonly kind: string; readonly name: string; } /** A registry key used by commands that need an operator-installed provider before they run. */ export interface ExtensionRef { readonly kind: string; readonly name: string; } export declare class Registry { #private; /** Register one or more extensions, all-or-nothing. A duplicate `kind:name` (already live, already * staged, or repeated within this call) throws BEFORE any of the batch is applied. During a * {@link runStaged} import the batch lands in the per-import stage (invisible); otherwise it lands * live. */ register(...exts: Extension[]): void; /** Remove one extension by kind + name; returns whether it was registered. Generic teardown; it * knows nothing about what a kind means. */ unregister(kind: string, name: string): boolean; /** * Run `load` (typically a self-registering `import()`) with the registrations it makes STAGED * (invisible to {@link resolve}/{@link all}) and return them for the caller to validate against the * manifest-advertised keys, then {@link commitStaged}. A throw/rejection propagates and the stage is * DISCARDED: those registrations never touched the live registry, and no unrelated live registration * is affected. Callers still SERIALIZE loads so two imports never share a validation window. */ runStaged(load: () => Promise): Promise<{ value: T; staged: Extension[]; }>; /** Publish previously-staged registrations to the live registry, atomically (all-or-nothing, * re-checked against the live map, which may have changed since staging). */ commitStaged(staged: readonly Extension[]): void; /** Whether a committed extension exists for kind + name (staged registrations are invisible here, * like {@link resolve}). A boolean probe that never throws. */ has(kind: string, name: string): boolean; /** Resolve one extension by kind + name. Unknown throws. Staged (uncommitted) registrations are * invisible here; only committed ones resolve. */ resolve(kind: T["kind"], name: string): T; /** Every registered (committed) extension, optionally narrowed to one kind. */ all(): Extension[]; all(kind: T["kind"]): T[]; } /** The process-wide registry. Implementations self-register into it on import. */ export declare const registry: Registry; //# sourceMappingURL=registry.d.ts.map