/** * Persist before push: the segment outbox (journal spec §2.8 "Building * segments", "Persist before push"; T12343 O-1). * * Sealed local transactions are packed, in local commit order, into a * segment of one stream: `deflate-raw(canonical JSON of LedgerTxn[])` with * its plaintext metadata (op count, HLC range, per-table and per-transaction * deltas, schema version). The caller's sealer encrypts it (the journal * client's `sealSegment`, under the stream key), and ONE local transaction * then: * - first makes any pre-T13222 partial-group op whole (T13233, T13287), so * no segment ever carries one; * - inserts the `_sync_segment` row with the exact sealed bytes and their * hash, at the next `replicaSeq` of (stream, replica), state `sealed`, and * raises the store's persisted replicaSeq high-water mark; * - maps every packed transaction to it (`_sync_segment_txn`) and marks it * `segmented` (it stays unsequenced until its echo, §3.5); * - sets `_sync_row_meta.sent` for every row it carries; * - writes the `row_identity_synced` marker if absent (§3.4: uids are about * to leave the device). * * A push sends the persisted bytes, never re-sealed: re-encrypting would * change the hash and defeat the server's (replica, hash) idempotency, so a * crash at any point resends the same segment or finds it stored. * * @task T12343 * @module store/sync/segments */ import type { DatabaseSync } from 'node:sqlite'; import type { TableScope } from '@cleocode/contracts'; import type { TableDeltas, TxnDelta } from '@cleocode/contracts/cloud'; import { LedgerOp, type LedgerTxn } from '@cleocode/contracts/ledger'; import type { SegmentMetaFields } from '../../cloud/signing.js'; /** Encrypts a segment for one stream (the journal client's `sealSegment`). */ export type SegmentSealer = (replicaSeq: number, plaintext: Uint8Array, meta: SegmentMetaFields) => Buffer; /** What {@link buildSegment} needs. */ export interface BuildSegmentOptions { /** The stream (`project:` or `home:`). */ readonly stream: string; /** This store's bound replica (the segment's author); only its own transactions are packed. */ readonly replica: string; /** The store's scope (the legacy group pass reads its capture tables). */ readonly scope: TableScope; /** The merge key's project, or null on a home stream. */ readonly project: string | null; readonly sealer: SegmentSealer; /** Signs each packed transaction for the stream (§2.8: `signTxn` of txn-signing.ts, with the device key). */ readonly signTxn: (stream: string, txn: LedgerTxn) => LedgerTxn; readonly nowIso: string; /** Stop packing once the canonical JSON passes this many bytes (one txn always goes in). */ readonly maxPlaintextBytes?: number; } /** A persisted segment, as push reads it. */ export interface PersistedSegment { readonly stream: string; readonly replica: string; readonly replicaSeq: number; readonly meta: SegmentMetaFields; readonly sealed: Buffer; readonly segmentHash: string; readonly state: 'sealed' | 'pushed'; readonly serverSeq: number | null; /** The transactions it carries, in order. */ readonly txns: readonly string[]; } /** Default plaintext budget: comfortably under the 1 MiB inline ciphertext limit once deflated. */ export declare const SEGMENT_PLAINTEXT_BUDGET: number; /** * Per-table created/deleted counts of ops (an I creates, a D deletes; U and K * count as neither): a transaction's declared deltas (journal spec §2.11 §1). * * @param ops - The transaction's ops. * @returns Its declared deltas. */ export declare function deltasOf(ops: readonly LedgerOp[]): TableDeltas; /** * The segment metadata of `txns` (§2.8): op count, HLC range over every * transaction and op, per-table deltas and per-transaction deltas * (segment/v3), at this build's sync schema version. * * @param txns - The transactions, in segment order. * @returns The metadata. */ export declare function segmentMetaOf(txns: readonly LedgerTxn[]): SegmentMetaFields & { txnDeltas: TxnDelta[]; }; /** * The plaintext of a segment: `deflate-raw` of the canonical JSON of its * transactions (§2.8). * * @param txns - The transactions, in segment order. * @returns The bytes the stream key encrypts. */ export declare function segmentPlaintext(txns: readonly LedgerTxn[]): Buffer; /** * Pack the next sealed transactions into one segment of `stream`, seal it, * and persist it before any push (§2.8). Opens its own `BEGIN IMMEDIATE`, so * it must run outside a transaction and outside any frame. Only `replica`'s * own transactions are packed, and packing stops before a transaction that * still carries a partial merge group. The caller advances the device * registry's high-water mark after this commits. * * @param db - The store. * @param o - Stream, replica, project, sealer and clock. * @returns The persisted segment, or null when nothing is waiting. */ export declare function buildSegment(db: DatabaseSync, o: BuildSegmentOptions): PersistedSegment | null; /** * The persisted segments of `stream` not yet acknowledged by the server, in * `replicaSeq` order (push sends the lowest first, one at a time). * * @param db - The store. * @param stream - The stream. * @param replica - This store's replica. * @returns The unpushed segments. */ export declare function unpushedSegments(db: DatabaseSync, stream: string, replica: string): PersistedSegment[]; /** * Record that the server stored a segment (a new append or a duplicate): * its stream `seq`. * * @param db - The store. * @param s - The segment and the server's seq. */ export declare function markSegmentPushed(db: DatabaseSync, s: { readonly stream: string; readonly replica: string; readonly replicaSeq: number; readonly serverSeq: number; readonly nowIso: string; }): void; //# sourceMappingURL=segments.d.ts.map