/** * Preflight and observation-target operations for the Google Sheets API * sync provider. * * `readPreflight` performs the paced transport calls every outbound effect * operation needs (range-less sheet enumeration for hidden receipt tab * discovery, plus the bounded data read of the target and receipt tabs — * one reassembled logical read that the unified read engine expands into * sequential paced band requests when a tab's authoritative row bound * forces chunking). * `observationTargetFor` validates one observation request and derives its * snapshot build target, failing closed on unknown read modes. */ import type { ReadSyncSnapshotRequest } from "../../../../contracts/sheets/syncSheets.js"; import type { SyncMissingTabOperation } from "../../../../contracts/sheets/errors.js"; import type { RegisteredSyncProjectionDefinition } from "../../../../contracts/sheets/sheetsProvisioning.js"; import type { Presence } from "../../../../contracts/state/index.js"; import type { ParsedSheet, PreflightContext } from "../model/preflightTypes.js"; import type { SnapshotBuildTarget } from "../model/observation.js"; import { type GoogleSheetsApiProviderDeps, type RequestStartPacing } from "./shared.js"; /** * Reads the target and receipt tabs for one route. Paced on the PREFLIGHT read * class by default; pass `pacing: "write"` for a postcondition/verify read * that serializes against writes. */ export declare function readPreflight(deps: GoogleSheetsApiProviderDeps, request: { readonly sheetName: string; readonly registeredRange: string; }, definition: RegisteredSyncProjectionDefinition, routeOptions: { readonly identityField: Presence; readonly checkboxHeaders: readonly string[]; }, pacing?: RequestStartPacing, fields?: string, /** * `scoped`: steady-state fast-append base read — target tabs contribute * only the header row and the tab-wide key columns (identity/anchor * bands). `receiptCursor`: read the receipt tab through this provider's * tail-band cursor (same paced request, never an extra call). Defaults to * the historical whole-table full-evidence shape WITH the receipt cursor; * the postcondition-recovery probe rides the cursor too, and every * whole-table fallback/evidence gap answers with an explicit * `receiptCursor: false` full read (see `readEffectPostconditions`). */ options?: { readonly scoped?: boolean; readonly receiptCursor?: boolean; }): Promise; /** * One route's read inputs for the shared (multi-route) preflight and for the * scoped verification pass's whole-table recovery read. */ export interface PreflightRouteInput { readonly sheetName: string; readonly registeredRange: string; readonly definition: RegisteredSyncProjectionDefinition; readonly routeOptions: { readonly identityField: Presence; readonly checkboxHeaders: readonly string[]; }; } /** * The paced, range-less sheet enumeration ONE preflight dispatch shares. * * The base data read and any whole-table full-evidence recovery read are * built from this same sheet list, so a verification-overflow fallback can * never stack a second enumeration onto the leased request budget. */ export declare function enumeratePreflightSheets(deps: GoogleSheetsApiProviderDeps, pacing?: RequestStartPacing): Promise; /** * Reads the target and receipt tabs for MANY routes from an ALREADY * ENUMERATED sheet list with ONE ranged data call (see * `enumeratePreflightSheets` for why callers hold onto the enumeration). * Same contract and defaults as `readPreflightForRoutes`, minus its * enumeration call. */ export declare function readPreflightDataForEnumeratedRoutes(deps: GoogleSheetsApiProviderDeps, sheets: readonly ParsedSheet[], routes: readonly PreflightRouteInput[], operation?: SyncMissingTabOperation, pacing?: RequestStartPacing, fields?: string, options?: { readonly scoped?: boolean; readonly receiptCursor?: boolean; }): Promise>; /** * Reads the target and receipt tabs for MANY routes with ONE enumeration and * ONE ranged read covering all needed tabs, then builds a PreflightContext per * route keyed by its sheetName. Paced on the PREFLIGHT read class by default; * pass `pacing: "write"` for a postcondition/verify read that serializes * against writes. * * `operation` classifies an invalid provider state (such as a missing tab) * detected during the read; it defaults to the preflight step. The * postcondition-recovery path passes its own operation so a missing tab there * is reported as `postcondition_read` rather than `preflight`. */ export declare function readPreflightForRoutes(deps: GoogleSheetsApiProviderDeps, routes: readonly PreflightRouteInput[], operation?: SyncMissingTabOperation, pacing?: RequestStartPacing, fields?: string, /** Scoped/cursor read-shape options (see `readPreflight`). */ options?: { readonly scoped?: boolean; readonly receiptCursor?: boolean; }): Promise>; /** * One route's scoped verification pass over a base (values-only) preflight * context. * * `targetRowNumbers` are the existing rows whose CAS/replay hashes the * planner or the fast-append path will compute, collected against the base * indexes as an over-approximation. Bands of every pass are packed and * executed together by `verifyPreflightContexts` through the unified read * engine (an over-budget plan expands into additional sequential band * requests; correctness never depends on the packing). */ export interface PreflightVerifyPass { readonly context: PreflightContext; readonly targetRowNumbers: readonly number[]; } /** * Runs the scoped verification reads for one or more routes through the * unified read engine (row bands + conditional identity-column band, values * plus BOTH number-format sources), then patches each base context from its * sheet's per-range grid list. * * Every banded row's value and formats come from ONE band request (one * server snapshot), so a verification hash is never a mixed base/overlay * snapshot. The pre-engine "ANY route overflows the range budget → skip the * bands and resolve EVERYTHING through ONE uncapped whole-table * full-evidence read" fallback is REMOVED: all routes' bands are packed * into as FEW sequential paced requests as the 40-range and byte-estimate * budget allows, each request individually bounded, so an oversized plan * costs additional slots on the lane instead of a guaranteed-timeout 16 MB * single request. Correctness never depends on the packing: every hashed * cell still sits in exactly one band, and `patchPreflightContext`'s anchor * revalidation blanks rows shifted between snapshots fail-closed exactly * like a shift between the base and a single verification read. */ export declare function verifyPreflightContexts(deps: GoogleSheetsApiProviderDeps, passes: readonly PreflightVerifyPass[], pacing?: RequestStartPacing): Promise; /** Single-route convenience wrapper around `verifyPreflightContexts`. */ export declare function verifyPreflightContext(deps: GoogleSheetsApiProviderDeps, context: PreflightContext, targetRowNumbers: readonly number[], pacing?: RequestStartPacing): Promise; /** Validates one observation request and derives its snapshot target. */ export declare function observationTargetFor(deps: GoogleSheetsApiProviderDeps, request: ReadSyncSnapshotRequest): SnapshotBuildTarget; /** * Re-validates the shared receipt tab when a preflight observed it absent. * * A read-ahead preflight can run concurrently with another route's write and * observe the shared receipt tab before that write creates it. Two such * preflights would both build a batch containing a duplicate `addSheet`, and * the second write would fail with a 400 that could permanently fail its * effects. The write stage calls this under the mutation lane (via the * coordinator's `runSerializedInner`) so only the first write creates the tab; * a later write sees it present and appends instead. The re-read is paced on * the WRITE lane so it serializes against competing writes. Returns the * original context unchanged when the tab is still absent (the caller creates * it atomically with the target+receipt batch). * * The refresh is exactly ONE paced write-lane ranged `spreadsheets.get` of the * receipt tab by title: a tab that now exists returns its properties * (sheetId) and grid data together, and a still-absent tab is proven by an * empty intersection or by the API's proven missing-range 400 rejection, * which is classified as still-absent so the caller creates the tab. The * single read keeps the complete stale-receipt-refresh branch (two preflight * reads + this read + the write, one bounded admission wait each) inside the * leased fast-append/legacy bound that `validateEffectLeaseHeadroom` counts; * a separate range-less enumeration here would add one more paced request * and let the branch outlive the default effect lease. */ export declare function refreshReceiptForWrite(deps: GoogleSheetsApiProviderDeps, context: PreflightContext): Promise; //# sourceMappingURL=preflightOp.d.ts.map