/** * Server KV store (docs/design/kv.md): wire constants, message builders, * record codecs, and the client-side mirror reducer. * * A host-local key→value store with CAS writes and prefix-watch * subscriptions. Keys are raw UTF-8 (≤ {@link KV_MAX_KEY} bytes, no NUL, * non-empty); values are opaque bytes, LZ4 on the wire. CAS is BLAKE3-128 * over value bytes with the zero-hash absent sentinel — fs-write's * conflict model verbatim (docs/design/fs-write.md). * * All integers little-endian, tightly packed, as everywhere in the protocol. */ /** Subscribe to a prefix: [0x70][nonce:2][flags:1][inline_max:4][prefix_len:2][prefix:N] * The prefix is a literal byte prefix (no glob); empty = whole store. */ export declare const C2S_KV_OPEN = 112; /** Close a subscription: [0x71][kv_id:2] */ export declare const C2S_KV_STOP = 113; /** Cumulative acknowledgement: [0x72][kv_id:2][update_id:4] */ export declare const C2S_KV_ACK = 114; /** CAS put/delete: [0x73][nonce:2][flags:1][base:16][key_len:2][key:N][value:LZ4] */ export declare const C2S_KV_PUT = 115; /** Fetch one value: [0x74][nonce:2][key_len:2][key:N] */ export declare const C2S_KV_FETCH = 116; /** Subscription accepted or refused: [0x70][nonce:2][kv_id:2][status:1][detail_len:2][detail:N] */ export declare const S2C_KV_OPENED = 112; /** Snapshot/live records: [0x71][kv_id:2][update_id:4][flags:1][records:LZ4] */ export declare const S2C_KV_UPDATE = 113; /** Put result: [0x72][nonce:2][status:1][hash:16][mtime_ns:8] */ export declare const S2C_KV_DONE = 114; /** Fetch result: [0x73][nonce:2][status:1][hash:16][data:LZ4] */ export declare const S2C_KV_VALUE = 115; /** Server-initiated close: [0x74][kv_id:2][reason:1]. The subscription is * gone server-side — the `kv_id` is dead, a late `KV_ACK` for it is * ignored, and recovery is a fresh `KV_OPEN` (the snapshot is the * recovery: updates carry state, not events; docs/design/kv.md * "Retention"). */ export declare const S2C_KV_CLOSED = 116; /** `S2C_HELLO` feature bit: server supports the `KV_*` family. `BLIT_KV=0` * refuses every `KV_*` at dispatch with `PERMISSION` instead of * un-advertising. */ export declare const FEATURE_KV: number; /** `kv_id` reported by a failed `KV_OPENED`. */ export declare const KV_ID_INVALID = 65535; /** Maximum key length in bytes (fixed, not an env knob). */ export declare const KV_MAX_KEY = 256; /** Ignore `base`; unconditional put/delete. */ export declare const KV_PUT_NO_CAS: number; /** Remove the entry (value must be empty). A delete is a put of absence; * `base` zero with DELETE is INVALID (delete-iff-absent is meaningless). */ export declare const KV_PUT_DELETE: number; /** fsync the store before replying; default trades durability for latency. */ export declare const KV_PUT_DURABLE: number; /** This batch completes the initial snapshot; subsequent updates are live. */ export declare const KV_UPDATE_SNAPSHOT_END: number; /** Queued-unacked bytes breached `BLIT_KV_UNACKED_MAX`: the client * stalled its acks and the server dropped the subscription. */ export declare const KV_CLOSED_RESOURCE_LIMIT = 4; /** Human-readable `S2C_KV_CLOSED` reason. */ export declare function kvClosedText(reason: number): string; export declare const KV_STATUS_OK = 0; export declare const KV_STATUS_NOT_FOUND = 2; export declare const KV_STATUS_PERMISSION = 4; export declare const KV_STATUS_TOO_LARGE = 5; export declare const KV_STATUS_BUDGET = 6; export declare const KV_STATUS_INVALID = 7; export declare const KV_STATUS_OTHER = 9; /** A CAS precondition failed; `KvDone.hash` carries the current value hash. */ export declare const KV_STATUS_CONFLICT = 11; /** Human-readable `KV_*` status. */ export declare function kvStatusText(status: number): string; /** Wire-key validity: non-empty, ≤ {@link KV_MAX_KEY} UTF-8 bytes, no NUL. */ export declare function kvKeyValid(key: string): boolean; export declare const KV_RECORD_UPSERT = 1; export declare const KV_RECORD_DELETE = 2; export declare const KV_CONTENT_NONE = 0; export declare const KV_CONTENT_FULL = 1; export declare function buildKvOpenMessage(nonce: number, flags: number, inlineMax: number, prefix: string): Uint8Array; export declare function buildKvStopMessage(kvId: number): Uint8Array; export declare function buildKvAckMessage(kvId: number, updateId: number): Uint8Array; export interface KvPutArgs { nonce: number; flags: number; /** CAS precondition hash (0n = create-exclusive; ignored under NO_CAS). */ base: bigint; key: string; value: Uint8Array; } export declare function buildKvPutMessage(a: KvPutArgs): Uint8Array; export declare function buildKvFetchMessage(nonce: number, key: string): Uint8Array; export interface KvOpened { nonce: number; kvId: number; status: number; detail: string; } /** Parse an `S2C_KV_OPENED`; null = malformed or wrong opcode. */ export declare function parseKvOpenedMessage(msg: Uint8Array): KvOpened | null; export interface KvDone { nonce: number; status: number; /** New value hash on success (0n for a delete); current hash on CONFLICT. */ hash: bigint; mtimeNs: bigint; } /** Parse an `S2C_KV_DONE`; null = malformed or wrong opcode. */ export declare function parseKvDoneMessage(msg: Uint8Array): KvDone | null; export interface KvValue { nonce: number; status: number; hash: bigint; data: Uint8Array; } /** Parse an `S2C_KV_VALUE` (decompression guarded); null = malformed. */ export declare function parseKvValueMessage(msg: Uint8Array): KvValue | null; /** One decoded record from a `KV_UPDATE` payload. */ export type KvRecord = { kind: "upsert"; key: string; /** BLAKE3-128 of the value bytes. */ hash: bigint; size: number; mtimeNs: bigint; /** Inline value iff `size` ≤ the subscription's `inline_max`; * null = fetch on demand. */ value: Uint8Array | null; } | { kind: "delete"; key: string; }; /** Encode records into an uncompressed `KV_UPDATE` buffer (tests and mock * servers; real servers use the Rust encoder). */ export declare function encodeKvRecords(records: readonly KvRecord[]): Uint8Array; /** Build a `KV_UPDATE` from records (tests and mock servers). */ export declare function buildKvUpdateMessage(kvId: number, updateId: number, flags: number, records: readonly KvRecord[]): Uint8Array; /** Decode an uncompressed records buffer. Unknown kinds are skipped via * `record_len`; a malformed record ends decoding (the fs rule). */ export declare function decodeKvRecords(data: Uint8Array): KvRecord[]; export interface KvUpdate { kvId: number; updateId: number; flags: number; records: KvRecord[]; } /** Parse a `KV_UPDATE` (decompression guarded); null = malformed. */ export declare function parseKvUpdateMessage(msg: Uint8Array): KvUpdate | null; /** One mirrored entry. */ export interface KvEntry { /** BLAKE3-128 of the value bytes. */ hash: bigint; size: number; mtimeNs: bigint; /** Present iff the value arrived inline; null = fetch on demand. */ value: Uint8Array | null; } /** Options for a prefix-watch subscription. */ export interface KvWatchOptions { /** Values at or under this size arrive inline in updates; larger ones * are metadata-only (fetch on demand). 0 = server default (inline all * under the value cap). */ inlineMax?: number; /** Fires after each applied update (snapshot batches included). */ onUpdate?: (mirror: KvMirror) => void; /** The subscription died: the connection dropped, or the server closed * it (`S2C_KV_CLOSED` — the error message carries * {@link kvClosedText}, e.g. "resource limit" when stalled acks * breached the unacked budget). Either way the `kv_id` and mirror are * dead; recovery is re-`watchKv` (the fs-family rule — the fresh * snapshot is the recovery). */ onClosed?: (error: Error) => void; } /** A live prefix subscription: read `mirror.live`, `close()` to stop. */ export interface KvWatchHandle { readonly kvId: number; readonly mirror: KvMirror; close(): void; } /** A fetched value. */ export interface KvFetchResult { hash: bigint; value: Uint8Array; } /** Options for `kvPut` — `writeFile`'s mapping exactly: `ifHash` → CAS, * `create` → create-exclusive, neither → unconditional (`NO_CAS`). */ export interface KvPutOptions { ifHash?: bigint; create?: boolean; durable?: boolean; } /** * The complete watcher obligation: apply updates, read `live`. One mirror * per subscription; a re-established connection means a new `KV_OPEN`, a * new `kv_id`, and a fresh mirror (nothing survives, the fs-family rule). */ export declare class KvMirror { readonly live: Map; /** True once the initial snapshot is complete (`KV_UPDATE_SNAPSHOT_END`). */ snapshotDone: boolean; /** Apply one `KV_UPDATE` message (starting at the opcode byte). * Returns the `update_id` to acknowledge, or null if malformed. */ applyUpdate(msg: Uint8Array): number | null; } //# sourceMappingURL=kv.d.ts.map