/** * Server schema IR (SPEC.md §2.4, §3.1). * * The server is configured with a schema IR: tables, columns with the six * §2.4 column types, scope patterns per §3.1, and a schema version. Codegen * Typegen emits this shape; tests hand-write it. */ import { type RowColumn } from '@syncular/core'; /** `'prefix:{variable}'` shorthand (column name = variable) or explicit. */ export type ScopePatternSpec = string | { pattern: string; column: string; }; /** * A user-declared index (the migration subset's CREATE INDEX). Relational * server storage applies the same declaration the client materializes. */ export interface IndexSchema { readonly name: string; readonly columns: readonly string[]; readonly unique?: boolean; } export interface TableSchema { readonly name: string; /** Columns in schema-IR declaration order (the row-codec order, §2.4). */ readonly columns: readonly RowColumn[]; /** Primary-key column; its value renders as the change `rowId` (§2.2). */ readonly primaryKey: string; /** Scope patterns (§3.1). Every synced table declares at least one. */ readonly scopes: readonly ScopePatternSpec[]; /** User indexes (optional) — created on the server's relational tables. */ readonly indexes?: readonly IndexSchema[]; /** * Server-side column materialization * "optional materialization"). When `true` (the usual default) the server's * row table carries the app's typed columns as a queryable projection; * when `false` it carries only the `_sync_*` meta columns — same storage * layout, same serve path, no decode on the push path, but no server-side * SQL over the app's columns (and user indexes are skipped). * * Unset defaults to `true`, EXCEPT for tables whose every non-PK, * non-scope column is encrypted (§5.11): their projection would be * columns of ciphertext, so they default to `false`. Explicit values * always win. Changing the value later requires a schemaVersion bump * (flipping on backfills the projection from stored payloads). */ readonly materialize?: boolean; } export interface ServerSchema { /** The generated schema version this server serves (§2.4, §9). */ readonly version: number; /** Tables in handler-declared bootstrap order (§4.7). */ readonly tables: readonly TableSchema[]; } export interface CompiledScopePattern { readonly variable: string; /** Literal prefix; the scope key is `prefix + ':' + value` (§3.1). */ readonly prefix: string; readonly column: string; readonly columnIndex: number; } export interface CompiledTable { readonly name: string; readonly columns: readonly RowColumn[]; readonly primaryKeyIndex: number; readonly scopePatterns: readonly CompiledScopePattern[]; /** User indexes (validated: unique names, existing columns). */ readonly indexes: readonly IndexSchema[]; /** Resolved materialization (see `TableSchema.materialize`). */ readonly materialize: boolean; readonly columnIndex: ReadonlyMap; readonly declaredVariables: ReadonlySet; /** Column indices declared `blob_ref` (§2.4 tag 7, §5.9) — the columns * whose non-NULL values reference blobs (existence check, reference * index). */ readonly blobRefColumnIndices: readonly number[]; /** `crdt` columns (§2.4 tag 8, §5.10) — index + the `crdtType` name that * selects the merger. Empty when the table has no crdt columns. */ readonly crdtColumns: readonly { readonly index: number; readonly crdtType: string; }[]; /** §5.11: column indices marked `encrypted`. The server never decrypts; * this only excludes the table from sqlite-image eligibility (§5.3) — an * image copies ciphertext wholesale with no per-row decrypt pass, so an * encrypted table MUST be served via the rows lane. Empty ⇒ no restriction. */ readonly encryptedColumnIndices: readonly number[]; } export interface CompiledSchema { readonly version: number; readonly tables: ReadonlyMap; /** Union of scope variables declared by any table (§3.2 resolver check). */ readonly declaredVariables: ReadonlySet; } export declare function compileSchema(schema: ServerSchema): CompiledSchema;