import type { SignedEvent } from '@kokuin/controller'; export type ProviderTransport = 'none' | 'direct' | 'networked'; /** One root chain, or several candidates. The ingest boundary wraps each as a ControllerLog. */ export type ControllerLogReply = Array | Array>; /** * The `controller-log-source` capability: given a `did:kokuin:` controller and * its known log, yield remote candidate logs (unverified: the controller head * folds them) or undefined. The controller resolver consults the ordered * providers of this kind on a store miss/expiry; folding, TTL and the * write-through cache stay resolver-owned. p2p registers a * `networked` provider. Property syntax (not a method) so the type satisfies the * `Record` provider-impl constraint via its implicit index * signature. Lives here (not engine.ts) so plugin-p2p can import it from * `@kubun/engine` without the reverse dep that would cycle. */ export type ControllerLogSource = { fetch: (did: string, known?: Array) => Promise; }; /** * A registered provider: the engine-owned envelope fields plus the * kind-specific implementation the registrant supplies. */ export type Provider = Record> = { name: string; kind: string; transport?: ProviderTransport; priority?: number; } & Impl; /** * What a registrant hands `registerProvider`: the provider without `kind`, * which is passed separately as the registry key. */ export type ProviderImpl = Record> = Omit, 'kind'>; /** Options for consulting an ordered provider list. */ export type ConsultOptions = { /** * Per-remote-provider timeout in milliseconds. Only remote (`direct`/ * `networked`) invocations are wrapped; a timeout is treated as an error and * falls through to the next provider. Local (`none`) providers are never * timed. Defaults to {@link DEFAULT_PROVIDER_TIMEOUT_MS}. */ timeoutMS?: number; /** * Classify a thrown invoke error as fatal. A fatal error aborts consultation * and re-throws unchanged — no fall-through to a later provider. Use it when a * throw carries a decision the caller must act on (e.g. a controller-log fork) * rather than a recoverable "this provider is unavailable". Absent (the * default), every throw is non-fatal and falls through. */ isFatal?: (err: unknown) => boolean; /** * Called for each caught (non-fatal) invoke error before consultation falls * through, so no swallowed throw is silent. A provider resolving `undefined` * is a normal "no answer" and does NOT call this. Errors thrown here are * ignored so a faulty reporter cannot break failover. */ onError?: (err: unknown, provider: Provider) => void; }; /** * Default per-remote-provider consultation timeout. Chosen as a conservative * ceiling for a single cross-engine round trip — long enough for a networked * provider under load, short enough that a stalled remote yields to the next * candidate rather than hanging the whole consultation. */ export declare const DEFAULT_PROVIDER_TIMEOUT_MS = 5000; /** * Thrown at startup when a capability kind declared **single** has more than one * registered provider. Single kinds admit at most one provider; ambiguity is a * construction-time error, not a lazy read-time one. */ export declare class ProviderCardinalityError extends Error { #private; constructor(kind: string, count: number); get kind(): string; get count(): number; } /** * Thrown when `registerProvider` runs after `closeGate` has already validated * cardinality. Registration is legitimate only during synchronous plugin-factory * construction (pre-gate); a factory that retains its callback and registers * later would silently defeat the single-kind check that already ran. */ export declare class ProviderRegistrationClosedError extends Error { constructor(); } /** * Order providers by cost tier (`none` < `direct` < `networked`) then by * `priority` (higher first) within a tier. `Array.sort` is stable, so providers * equal on both keys keep their registration order. Returns a new array. */ export declare function sortProviders = Record>(providers: Array>): Array>; /** * Consult an already-ordered provider list, returning the first defined result. * * Local (`none`) providers are invoked directly. Remote (`direct`/`networked`) * providers are wrapped in a timeout ({@link ConsultOptions.timeoutMS}); a * timeout counts as an error. On an invoke throwing OR resolving `undefined`, * consultation falls through to the next provider. Returns `undefined` when * every provider falls through. * * This carries the "local preferred, remote failover" invariant. Ordering is * the caller's responsibility (the engine passes `getProviders` output, which is * already tier/priority sorted); the name reflects that precondition. */ export declare function consultOrderedProviders, R>(providers: Array>, invoke: (provider: Provider) => Promise, opts?: ConsultOptions): Promise; export type ProviderRegistry = { registerProvider = Record>(kind: string, impl: ProviderImpl): void; closeGate(): void; getProviders = Record>(kind: string): Promise>>; /** * Synchronous snapshot of an ordered kind, for callers that run strictly after * the gate closes (every `.serve()` is post-construction, since `closeGate()` * runs inside the synchronous engine constructor). Throws if called before the * gate closes — a defensive invariant, never hit in practice. */ getProvidersSync = Record>(kind: string): Array>; getProvider = Record>(kind: string): Promise | undefined>; }; export type ProviderRegistryOptions = { /** * Capability kinds that admit at most one provider. Validated when the gate * closes: any single kind with more than one registered provider throws * {@link ProviderCardinalityError}. A kind absent from this set is ordered * (many providers allowed). Declared by the capability owner (the engine), * not at registration. */ singleKinds?: Iterable; }; export declare function createProviderRegistry(options?: ProviderRegistryOptions): ProviderRegistry;