import { Ref } from 'vue'; export type RequestSyncSuccessKind = 'load' | 'save' | 'run'; /** * The unit of work `run()` drives. * * It receives an `AbortSignal` that fires when the run is superseded by a * newer `run()` or by `cancel()`. Zero-argument operations stay valid and * simply ignore it. */ export type RequestSyncOperation = (signal: AbortSignal) => Promise; export interface RequestSyncRunOptions { success?: RequestSyncSuccessKind; errorMessage?: string; /** * Abort the previously started run when this one starts. Default `true`; * pass `false` to let overlapping runs finish their own work (the stale * guard on shared state still applies either way). */ abortPrevious?: boolean; /** Caller-owned signal; aborting it aborts this run's signal too. */ signal?: AbortSignal; } export interface UseRequestSyncStateReturn { /** Whether a request is in progress. */ loading: Ref; /** Message from the last failed request, or null. */ error: Ref; /** Timestamp of the last successful load operation, or null. */ lastLoadedAt: Ref; /** Timestamp of the last successful save operation, or null. */ lastSavedAt: Ref; /** Timestamp of the last successful run operation, or null. */ lastRunAt: Ref; /** Clear the current error without changing loading or timestamps. */ clearError: () => void; /** Convert thrown values into a developer-facing error message. */ readErrorMessage: (value: unknown, fallback?: string) => string; /** Store and return a normalized error message. */ setError: (value: unknown, fallback?: string) => string; /** Mark the resource as successfully loaded. */ markLoaded: (date?: Date) => void; /** Mark the resource as successfully saved. */ markSaved: (date?: Date) => void; /** Mark the operation as successfully run. */ markRun: (date?: Date) => void; /** * Run a request with shared loading/error handling and optional sync marking. * * ## Stale-response semantics * * Every call takes a monotonically increasing token. Starting a run * supersedes any run started before it, and a superseded run writes **no** * shared state when it finally settles: it does not clear `loading`, does not * set `error`, and does not move `lastLoadedAt` / `lastSavedAt` / `lastRunAt`. * Only the newest run owns those. * * The caller's own promise is untouched by the guard — a superseded run still * resolves with its value or rejects with its own error, exactly as the * operation did. The guard never invents a rejection, so a caller awaiting * `run()` never sees a "superseded" error it did not cause. * * The operation additionally receives an `AbortSignal` that fires when its * run is superseded or `cancel()` is called, so an operation that forwards * the signal (`fetch(url, { signal })`) stops work instead of racing. */ run: (operation: RequestSyncOperation, options?: RequestSyncRunOptions) => Promise; /** * Abort the in-flight run and drop `loading`. The aborted run's completion * is treated as stale and writes no state. */ cancel: () => void; } /** Shared loading/error/timestamp state for generated plugin request helpers. */ export declare function useRequestSyncState(defaultErrorMessage?: string): UseRequestSyncStateReturn;