/** * Atomic batch builder for the direct Sheets provider. * * All applicable target mutations (appends, scattered field updates, physical * row deletes) and their receipt writes are combined into ONE * `spreadsheets.batchUpdate`, which is atomic: any invalid request aborts the * whole batch. The builder also owns the transport byte budget: a batch that * would exceed the budget is trimmed to the largest order-preserving effect * prefix, and an effect that alone exceeds the budget becomes a schema_error * result instead of a mutation. */ import type { GoogleSheetsApiWriteRequest } from "../transport/googleSheetsApiTransport.js"; import type { PreflightContext } from "./preflightTypes.js"; import type { EffectPlan, PlannedReceipt, WorkingRow } from "./plannerContracts.js"; /** One built batch plus its serialized byte size. */ export interface BuiltApplyBatch { readonly requests: readonly GoogleSheetsApiWriteRequest[]; readonly bytes: number; } /** Inputs shared by the apply and append batch builders. */ export interface BatchBuildOptions { readonly context: PreflightContext; readonly updatedAt: string; } /** How much of the plan is included: prefix length plus schema-error effects. */ export interface BatchResolution { /** Number of leading effects whose mutations are included in the batch. */ readonly includeCount: number; /** Indices of effects excluded because one effect alone exceeds the budget. */ readonly schemaErrorIndices: readonly number[]; /** True when effects beyond the included prefix must be deferred. */ readonly hasMore: boolean; } /** * Resolves how many leading effects fit in one atomic batch. * * The byte budget is measured on the phase-ordered request list serialized * exactly as the transport sends it (SDK-wrapped request shapes), so the * check is exact for the bytes that would actually hit the wire. When the * very first effect alone exceeds the budget it becomes a schema_error * result and the remaining effects are re-tried, so a single pathological * payload cannot block the rest of the batch. */ export declare function resolveApplyBatchBudget(context: PreflightContext, plans: readonly EffectPlan[], options: { readonly maxBatchBytes: number; readonly includeReceipts: boolean; readonly updatedAt: string; }): BatchResolution; /** * Binary-searches the largest count in `[minCount, total]` whose built prefix fits * the byte budget (upper-mid, so the search converges upward). Apply prefix * searches pass 0 so an over-budget first effect yields 0 (schema_error); * fast-append resolvers pass 1 so a single over-budget row is still included * and fails deterministically at the API instead of deferring forever. */ export declare function largestFittingCount(total: number, build: (count: number) => { readonly bytes: number; }, maxBatchBytes: number, minCount: number): number; /** * Builds one atomic batchUpdate request list for a prefix of the plan. * * Requests are emitted in phase order: receipt-tab creation, append row * inserts/values/anchors, scattered field updates, physical deletes (in * descending row order so an earlier delete never shifts a later target), * then receipt rows. Appended rows are written with their full header cells * (all effects that touched a created row merge into one write); date cells * keep the canonical number format through a separate format-masked request. */ export declare function buildApplyBatchRequests(context: PreflightContext, plans: readonly EffectPlan[], options: { readonly updatedAt: string; readonly includeReceipts: boolean; }): BuiltApplyBatch; /** Measures the serialized batchUpdate body with the transport serializer. */ export declare function measureRequestBytes(requests: readonly GoogleSheetsApiWriteRequest[]): number; /** One route group's plans for a combined (multi-tab) batch. */ export interface CombinedApplyRoute { readonly context: PreflightContext; readonly plans: readonly EffectPlan[]; } /** * Builds ONE atomic batchUpdate request list across several tabs, targeting * each tab's sheetId, and appending ALL routes' receipts to the single shared * receipt sheet once (created if absent). Preserves per-tab target rows. */ export declare function buildCombinedApplyRequests(routes: readonly CombinedApplyRoute[], options: { readonly updatedAt: string; readonly includeReceipts: boolean; }): BuiltApplyBatch; /** * Resolves how many leading effects fit across all route groups in one * combined atomic batch. Binary-searches the shared prefix length over the * flattened (route-ordered) plan list and marks effects that alone exceed the * budget as schema-error indices, mirroring `resolveApplyBatchBudget`. */ export declare function resolveCombinedApplyBudget(routes: readonly CombinedApplyRoute[], options: { readonly maxBatchBytes: number; readonly includeReceipts: boolean; readonly updatedAt: string; }): { readonly includeCount: number; readonly schemaErrorIndices: readonly number[]; }; /** * Builds ONE atomic fast-append batch across multiple tabs: each tab's rows * target its own sheetId, receipts are appended once to the shared receipt * sheet, and the shared byte budget is respected. */ export declare function buildCombinedAppendRequests(routes: ReadonlyArray<{ readonly context: PreflightContext; readonly rows: readonly WorkingRow[]; readonly receipts: readonly PlannedReceipt[]; }>, options: { readonly updatedAt: string; }): BuiltApplyBatch; /** Combined append route inputs for the multi-tab fast-append builder. */ export interface CombinedAppendRoute { readonly context: PreflightContext; readonly rows: readonly WorkingRow[]; readonly receipts: readonly PlannedReceipt[]; } /** * Resolves the append row prefix for one fast-append request. * * Unlike regular effects there is no per-row schema_error status, so a single * row that alone exceeds the budget is still included: the API's own limits * reject it deterministically (a proven explicit failure) instead of leaving * the effect in an infinite defer loop. */ export declare function resolveAppendBudget(rows: readonly { readonly rowNumber: number; }[], build: (count: number) => BuiltApplyBatch, maxBatchBytes: number): { readonly includeCount: number; readonly hasMore: boolean; }; /** Builds one atomic fast-append batch for a prefix of pending rows. */ export declare function buildAppendBatchRequests(context: PreflightContext, rows: readonly WorkingRow[], receipts: readonly PlannedReceipt[], options: { readonly updatedAt: string; }): BuiltApplyBatch; //# sourceMappingURL=batchBuilder.d.ts.map