API index and search · Build metadata
Supporting declarations
packages/api-server/src/rooms.ts. These declarations explain referenced types. Only package-page symbols are package exports.
RoomProfile
/**
* One NAMED room profile (§2.1). Rooms are document-scoped, not query-scoped: a profile is what
* stands up and feeds a room — the flat `resolveFootprint` promoted to a named, reusable unit.
* Labeled queries opt into a profile; the wire room key for a named profile is minted SERVER-side
* as `"<profile>/<key>"`, and `/room-boot` splits it back to resolve the footprint.
*/
export interface RoomProfile<User = unknown> {
/** Derive the profile-local room key from the (label-mapped) query args. Runs server-side under
* authoritative inputs — the client learns the key from the lease, it never computes one. */
key: (args: any) => string;
/** Build the room's canonical footprint — the replica boundary the room loads and follows —
* from the profile-local doc key (this profile's `key` output; what `/room-boot` receives
* after the prefix split). MUST be unwindowed (§2.3): no `limit`/`start`/`one` anywhere in the
* AST — enforced loudly at construction when statically resolvable, and again at every boot.
* Should be a TOTAL builder over any key (a shape constructor, not an authorizer). */
footprint: (docKey: string, ctx: ApiContext<User>) => MaybePromise<ApiQueryResult>;
/** Loaded-but-never-room-written tables (§2.2 — the "followed" set: real external writers, the
* daemon stays write-authoritative for them). Must be a subset of the footprint's tables; the
* room's writable scope is footprint minus context. Defaults to `[]`. */
context?: readonly string[];
}queryResultToAst
export declare function queryResultToAst(result: ApiQueryResult): Ast;ROOM_DOC_SEPARATOR
/** The wire room-key delimiter: a named profile's doc is `"<profile>/<key>"`; a doc with no known
* profile prefix belongs to the legacy anonymous profile (`resolveFootprint`, bare-key form). */
export declare const ROOM_DOC_SEPARATOR = "/";mintRoomDoc
/** Mint the wire room doc for a named profile (the lease path — G-iv-b — mints these). */
export declare function mintRoomDoc(profile: string, key: string): string;splitRoomDoc
/** Split a wire room doc at the FIRST separator. `undefined` for a bare doc (no separator, or an
* empty would-be profile name). The CALLER decides whether the prefix actually names a profile —
* a legacy doc may itself contain `/`, and then falls through to the legacy resolver whole. */
export declare function splitRoomDoc(doc: string): {
profile: string;
key: string;
} | undefined;assertUnwindowedFootprint
/**
* §2.3 "profile footprints are unwindowed", enforced: throw loudly (with the offending AST path)
* if `limit` / `start` (cursor paging — the skip lowering) / `one` appears ANYWHERE in the
* footprint tree — the root, a related subquery, or an EXISTS child. A window computed over an
* unwindowed superset equals the window over the full store, which is what makes room-serving of
* windowed *queries* sound; a windowed *footprint* would silently break that, so it is rejected
* by construction. Windows belong on the labeled queries a room serves, never on the footprint.
*/
export declare function assertUnwindowedFootprint(ast: Ast, profile: string): void;FootprintScan
export interface FootprintScan {
tables: Set<string>;
joinKeys: Map<string, Set<string>>;
}scanFootprint
/** Walk the footprint: every base table it draws rows from, and — per table — the correlation
* (join-key) columns every related/EXISTS edge binds on it. These are §3.2's routing metadata
* and slice H's "room mutators never write join keys" enforcement input; G-iv-b ships them to
* the room engine as part of the RoomTableSpec compilation ({@link compileRoomTableSpecs}). */
export declare function scanFootprint(ast: Ast): FootprintScan;RoomTableSpec
/**
* One footprint table's spec on the lease wire (`QueryLeaseResponse.realtime.tables`): the §2.2
* owned/followed split plus §3.2's per-table routing metadata, compiled from the RESOLVED
* footprint AST at lease time (so key-dependent and non-static profiles compile too).
*
* `writable`:
* - `none` — a context table (§2.2 "followed"): loaded by the room, never room-written; the
* daemon stays write-authoritative.
* - `predicate` — a writable table. `where` is the ROW-LOCAL part of the footprint's predicate
* for this table (simple column-vs-literal conditions composed with and/or); an ABSENT `where`
* means no row-local constraint — every row the room holds for this table is in the writable
* scope. `joinKeyCols` are the correlation columns the footprint binds on this table (slice
* H's "room mutators never write join keys" enforcement input).
*
* Dropping the non-row-local parts (correlated/EXISTS conditions, column-vs-column comparisons)
* only ever WIDENS the predicate, which is sound here: the room only relays rows the footprint
* materialized, so the held-row set — not this predicate — is the real outer bound; `where` is a
* row-local refinement of it, and a wider refinement can never mark a held footprint row
* non-writable that the full predicate would have allowed. (An OR with any non-row-local
* disjunct is dropped WHOLE — keeping only some disjuncts would narrow, which is not sound.)
*
* `footprintWhere` (H-iii — the lease-wire flip): the EXACT footprint-membership predicate,
* identical to {@link RoomScopeSpec.footprintWhere} (ONE compiler feeds both wires — the lease's
* table specs and the boot wire's scopes are now the SAME objects). The client's §3 router
* consumes it for the pk-membership read proof; it is advisory routing metadata, never a
* credential (the room gate re-proves engine-side, H-iv).
*/
export type RoomTableSpec = {
table: string;
footprintWhere?: Condition;
writable: {
kind: "none";
} | {
kind: "predicate";
where?: Condition;
joinKeyCols: string[];
};
};RoomScopeSpec
/**
* One footprint table's FULL scope spec (slice H-iv-b): byte-compatible with
* `rindle-room-core`'s `TableScopeSpec` (scope.rs), the wasm room's `enableWritesV2` input. It
* rides the boot wire (`RoomBootResponse.scopes`); since slice H-iii the LEASE wire's
* {@link RoomTableSpec} carries `footprintWhere` too (the client-side routing proof), so the two
* shapes are now structurally IDENTICAL — kept as two names because they are two wires with two
* consumers (the room gate vs the client router).
*
* `footprintWhere` is computed for EVERY footprint table — context (`kind: "none"`) ones
* included, because the gate proves ABSENT READS on any readable table with it (§3.1: an absent
* read is covered only when the footprint predicate is decidable from the pk columns alone and
* evaluates true on the read key). ABSENT (no exact membership predicate exists) ⇒ no absent
* read on that table is provable — the room gate fails closed to a deopt.
*
* **`footprintWhere` is EXACT-only — the opposite discipline from the writable `where`.** The
* writable side ships the WIDENING extraction ({@link tablePredicate}) and that is sound (the
* held-row set is the real outer bound). The absent-read proof points the other way: it uses
* `footprintWhere` to conclude "a row with this pk would have been IN the footprint, so the
* room's absence is truth's absence" — a WIDENED predicate over-claims exactly there (a root
* `where` mixing pk-column conjuncts with a dropped EXISTS, or a correlated child whose own
* `where` reads only its pk, would prove an absence the dropped part can contradict). So
* `footprintWhere` is emitted ONLY when the membership predicate is exact
* ({@link exactMembershipPredicate}): every node reading the table is the footprint ROOT (a
* child node's implicit correlation to its parent is itself a dropped, non-row-local constraint)
* and the root's `where` extraction dropped nothing. An unconstrained exact root (the whole
* table rides the footprint) emits the vacuous-true `{type:"and",conditions:[]}` — the gate's
* combinator pins empty-AND = true — so whole-table footprints keep provable absent reads.
* Child/correlated tables get NO `footprintWhere` and their absent reads deopt (fail closed);
* propagating a parent constraint through a pk-covering correlation is a future refinement.
*/
export type RoomScopeSpec = {
table: string;
footprintWhere?: Condition;
writable: RoomTableSpec["writable"];
};compileRoomScopeSpecs
/** Compile the per-table {@link RoomScopeSpec}s from a RESOLVED footprint AST + the profile's
* context set — the ONE compiler both wires derive from (the boot wire ships it whole; the
* lease wire serializes the {@link RoomTableSpec} projection via {@link compileRoomTableSpecs}).
* Deterministic output order (tables sorted by name). */
export declare function compileRoomScopeSpecs(footprint: Ast, context: ReadonlySet<string>): RoomScopeSpec[];compileRoomTableSpecs
/** Compile the per-table {@link RoomTableSpec}s from a RESOLVED footprint AST + the profile's
* context set — since H-iii the lease wire carries `footprintWhere` exactly where the boot wire
* does, so this IS {@link compileRoomScopeSpecs} (one compiler, two wires; the identity is
* pinned by serve-proof.test.ts). Kept as a named entry point for the lease call site. */
export declare function compileRoomTableSpecs(footprint: Ast, context: ReadonlySet<string>): RoomTableSpec[];PROBE_DOC_KEY
/** The symbolic doc key construction-time validation resolves each footprint with. A profile
* footprint should be a TOTAL builder over any key; one that throws on this key (or is async /
* ctx-dependent) simply defers its unwindowed check to boot, with a loud warning. */
export declare const PROBE_DOC_KEY = "__rindle-room-profile-probe__";CompileRoomProfilesInput
export interface CompileRoomProfilesInput<User> {
rooms: Record<string, RoomProfile<User>> | undefined;
/** The typed schema, when configured — enables the context-table existence check. */
schema: Schema | undefined;
/** Loud-diagnostics sink (defaults to `console.warn`); injectable for tests. */
warn?: (message: string) => void;
}compileRoomProfiles
/**
* Compile + validate the named room profiles — §2.3 "loud at registration". Rules enforced here:
* the profile name is wire-key-safe (no `/`); (b) the footprint is UNWINDOWED (throw, with the
* offending AST path); (c) context tables exist in the schema and are a subset of the footprint's
* tables (throw); (d) per-table join-key columns are derived and RECORDED on the compiled profile
* (a loud WARNING when the footprint isn't statically resolvable and they can't be).
*/
export declare function compileRoomProfiles<User>(input: CompileRoomProfilesInput<User>): Map<string, CompiledRoomProfile<User>>;queryRealtimeLabel
/** The realtime label a registered query carries (stamped by `registerQueries` from its
* `defineQuery` options), or `undefined` for an unlabeled query. The lease path uses this to
* derive `(room profile, args mapping)` for a named query. */
export declare function queryRealtimeLabel(query: ApiQuery<any, any> | undefined): RealtimeQueryLabel | undefined;assertLabeledProfilesExist
/** Rule (a) of the §2.3 "loud at registration" checks: every labeled registered query must name
* an existing room profile — a label pointing at nothing is config drift that would otherwise
* surface as a query that silently never room-serves. */
export declare function assertLabeledProfilesExist<User>(queries: Record<string, ApiQuery<User, any>> | undefined, profiles: ReadonlyMap<string, CompiledRoomProfile<User>>): void;