1/**2 * Package-owned durable-write settlement.3 *4 * One implementation of the local→global settlement ladder and its5 * diagnostics accounting — pending counters, wait counts, and mutation-error6 * counts — previously triplicated across table stores, mutation stores, and7 * access operations (where drift left access writes invisible to the8 * inspector). Snapshot state such as durability labels, error text, and9 * write-generation guards stays caller-owned through hooks.10 *11 * @module12 */1314import type { RuntimeDiagnostics } from "./diagnostics.ts";1516/** A vendor write handle that can await local and global durability tiers. */17export type DurableWrite<T> = {18 wait(options: { tier: "local" | "global" }): Promise<T>;19};2021/**22 * How the global tier is handled once local durability settles: not at all23 * (`none`, sync unconfigured), tracked without blocking the caller24 * (`background`, UI stores), or awaited inline (`await`, access operations).25 */26export type GlobalTierMode = "none" | "background" | "await";2728/** Caller hooks projecting settlement outcomes into caller-owned state. */29export type SettlementHooks = {30 /** Runs after local durability settles, before any global handling. */31 onLocal?: () => void;32 /** Runs when the global tier settles successfully. */33 onGlobal?: () => void;34 /** Runs when the global tier rejects; the rejection is already counted. */35 onGlobalError?: (error: unknown) => void;36};3738/**39 * Settles one durable write with shared diagnostics accounting. Resolves with40 * the write's value after local durability (`none`/`background`) or after41 * global durability (`await`). Rejects on local-tier failure in every mode42 * and on global-tier failure in `await` mode; a `background` global rejection43 * reaches {@link SettlementHooks.onGlobalError} only.44 */45export async function settleDurableWrite<T>(46 write: DurableWrite<T>,47 updateDiagnostics: (update: (diagnostics: RuntimeDiagnostics) => void) => void,48 globalTier: GlobalTierMode,49 hooks: SettlementHooks = {},50): Promise<T> {51 updateDiagnostics((diagnostics) => diagnostics.pendingLocalWrites += 1);52 let result: T;53 try {54 result = await write.wait({ tier: "local" });55 } catch (error) {56 updateDiagnostics((diagnostics) => {57 diagnostics.pendingLocalWrites -= 1;58 diagnostics.mutationErrors += 1;59 });60 throw error;61 }62 updateDiagnostics((diagnostics) => {63 diagnostics.pendingLocalWrites -= 1;64 diagnostics.localWaitCalls += 1;65 });66 hooks.onLocal?.();67 if (globalTier === "none") return result;68 updateDiagnostics((diagnostics) => diagnostics.pendingGlobalWrites += 1);69 const globalSettled = write.wait({ tier: "global" }).then(70 () => {71 hooks.onGlobal?.();72 },73 (error) => {74 updateDiagnostics((diagnostics) => diagnostics.mutationErrors += 1);75 hooks.onGlobalError?.(error);76 // Background rejections are fully handled here; only inline waiters77 // observe the rejection.78 if (globalTier === "await") throw error;79 },80 ).finally(() => updateDiagnostics((diagnostics) => diagnostics.pendingGlobalWrites -= 1));81 if (globalTier === "await") await globalSettled;82 else void globalSettled;83 return result;84}