Rindle

API index and search · Build metadata

Supporting declarations

packages/room/src/shell.ts. These declarations explain referenced types. Only package-page symbols are package exports.

Exact source

UpstreamOptions

/** The upstream half of the shell's config: where rindled lives and what to follow. */
export interface UpstreamOptions {
    /** rindled's public subscription plane, e.g. `ws://127.0.0.1:7601`. */
    wsUrl: string;
    /** rindled's private control plane, e.g. `http://127.0.0.1:7600` (lease minting). */
    controlUrl: string;
    /** Bearer token for the control plane (required unless rindled runs unauthenticated). */
    authToken?: string;
    /** The document footprint — a wire `Ast` (§3.1). What this room follows and serves from. */
    footprintAst: unknown;
    /** Lease TTL passed to `/materialize` (rindled's default when omitted). */
    leaseTtlMs?: number;
    /** The `init` clientID on the upstream socket (diagnostic identity). */
    clientId?: string;
}

DownstreamOptions

/** The downstream half: how clients are authorized and served (§4/§10.1). */
export interface DownstreamOptions {
    /** This room's document id — lease tokens for any other doc are refused. */
    docId: string;
    /** Token key ring: `kid` → shared secret (the API server signs with the same ring). */
    tokenKeys: Record<string, string>;
    /** Idle grace before an unsubscribed query's pipeline is reclaimed (default 30s). */
    idleTtlMs?: number;
    /** Lease-expiry / idle-sweep cadence (default 1s). */
    sweepIntervalMs?: number;
    /** How long a revocation keeps refusing pre-revocation tokens (default 30min — set
     *  it ≥ the longest token TTL the API server mints). */
    revocationWindowMs?: number;
    /** The room's private control plane (`POST /revoke`, `GET /stats`). Omit to run
     *  without one (no revocation surface). */
    control?: {
        authToken: string;
        port?: number;
    };
    /** The write plane (§5.1). Omit to run read-only (writes are refused). */
    writes?: WritesOptions;
    /** Per-socket downstream send budget in bytes (§9; default 4 MiB). A socket whose
     *  queued bytes would exceed it is terminated with a gap — re-subscribing is the
     *  repair. */
    sendBudgetBytes?: number;
}

RoomScopeSpec

/** One table's §3.3 scope spec (H-iv-b): an element of the api-server's
 *  `RoomBootResponse.scopes`, passed VERBATIM to the wasm room's `enableWritesV2`.
 *  Structurally identical to `@rindle/api-server`'s `RoomScopeSpec` (declared locally —
 *  the shell must not depend on the api-server package; TS structural typing keeps the
 *  two in lockstep at the host's threading site). */
export interface RoomScopeSpec {
    table: string;
    /** The footprint's row-local predicate for this table (a wire `Condition`) — drives
     *  the commit gate's absent-read proof. Absent ⇒ absent reads on this table always
     *  deopt (fail closed). */
    footprintWhere?: unknown;
    writable: {
        kind: "none";
    } | {
        kind: "predicate";
        where?: unknown;
        joinKeyCols: string[];
    };
}

WritesOptions

/** The §5.1 write plane: the room's own mutator registry over its owned tables. */
export interface WritesOptions {
    /** The server registry (§4.2): named mutators run against the shared head. PLAIN
     *  synchronous `(tx, args, ctx)` functions only — a `shared(...)` GENERATOR registry
     *  does NOT register verbatim (nothing drives it here; the shell rejects a mutator
     *  that returns a generator/promise — see `assertSyncMutatorReturn`). */
    mutators: Record<string, RoomMutator>;
    /** §3.2's owned set — the only tables mutators may write. Must all be in the
     *  upstream footprint; followed tables and the ledger are never writable. */
    ownedTables: string[];
    /** The §3.3 per-table scope specs from the boot wire (`RoomBootResponse.scopes` —
     *  H-iv-b). Present ⇒ the write plane enables in v2 GATED mode (`enableWritesV2`):
     *  staged writes validate against the writable predicates, join-key edits refuse,
     *  absent reads must prove against `footprintWhere`, context (`kind:"none"`) tables
     *  become txGet-READABLE, and a violating commit returns a structured DEOPT instead
     *  of applying. The scopes' writable tables must be a SUBSET of {@link ownedTables}
     *  (the host's own declaration) — a wider server scope throws at construction, so a
     *  self-hoster's owned set can never be extended from the wire. Absent ⇒ the v1
     *  table-granular write plane, byte-identical to before. */
    scopes?: RoomScopeSpec[];
    /** The durable sidecar an ack means (§8.1). Defaults to `memoryJournal()` — the
     *  "survives nothing beyond the process" class; hosts bring their own. */
    journal?: RoomJournal;
    /** The journal group-commit window (default 5ms): mutations arriving within it
     *  share one append, and their acks ride one ledger commit. */
    groupCommitMs?: number;
    /** The write authority (§5.3.1) — the API server's `/apply-row-change-txn` host
     *  (or the P3 gate's mock). Omit to run journal-only (P2 semantics: nothing is
     *  ever durable upstream). With an authority, the shell claims a placement epoch
     *  at boot, probes durable lmids before replay, and write-behinds on the flush
     *  cadence (§5.3). */
    authority?: RoomAuthority;
    /** The flush debounce (§5.3; default 250ms, within the design's ≤1s budget). */
    flushDebounceMs?: number;
    /** Flush immediately once this many keys are dirty (default 512). */
    flushDirtyMax?: number;
}

RoomShellOptions

export interface RoomShellOptions {
    upstream: UpstreamOptions;
    downstream: DownstreamOptions;
    /** Downstream ws port (default 0 = ephemeral; bound on 127.0.0.1). */
    port?: number;
    /** Diagnostic sink (default: silent). */
    log?: (line: string) => void;
}

RoomShell

export interface RoomShell {
    /** The bound downstream port. */
    readonly port: number;
    /** The bound control-plane port (0 when no control plane was configured). */
    readonly controlPort: number;
    /** Resolves when the CURRENT incarnation is live (seq-0 snapshot applied);
     *  immediately if it already is. */
    awaitLive(): Promise<void>;
    /** The last-applied upstream commit version, if live. */
    cv(): number | undefined;
    /** The upstream subscription epoch of the current incarnation, if any. */
    upstreamEpoch(): number | undefined;
    /** This incarnation's downstream bootId (rotates on every re-subscribe). */
    bootId(): string;
    /** Fire the write-behind flush now (instead of the debounce) and await its
     *  settlement — deterministic flushing for tests and drain-before-close. No-op
     *  without an authority. */
    flushNow(): Promise<void>;
    close(): Promise<void>;
}

createRoomShell

/** Boot a room shell: init the wasm, mint the upstream lease, connect the upstream leg,
 *  and serve the downstream ws (+ the private control plane, if configured). Returns
 *  once the ports are bound and the upstream connection is underway — await
 *  `shell.awaitLive()` for the seed. */
export declare function createRoomShell(opts: RoomShellOptions): Promise<RoomShell>;