{"version":3,"file":"use-offline-mutation.cjs","names":[],"sources":["../../src/query/use-offline-mutation.ts"],"sourcesContent":["import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport type { QueryKey, UseMutationResult } from \"@tanstack/react-query\";\nimport type { OfflineSync, OutboxOp, SyncTrigger } from \"../offline\";\n\n/** The outbox entry a mutation's variables map to. */\nexport interface OutboxDraft<TPayload> {\n    /** The mutation kind. */\n    op: OutboxOp;\n    /** Primary key of the affected record. */\n    recordId: string;\n    /** Record snapshot for `create`/`update` (omit for `delete`). */\n    payload?: TPayload;\n}\n\n/**\n * Configuration for {@link useOfflineMutation}.\n *\n * @typeParam TVariables - The `mutate(variables)` input shape.\n * @typeParam TData - The cached query data optimistically patched.\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n */\nexport interface UseOfflineMutationOptions<TVariables, TData, TPayload> {\n    /** The engine the mutation enqueues into. */\n    sync: OfflineSync<TPayload>;\n    /** Map `mutate` variables into an outbox entry. */\n    toEntry: (variables: TVariables) => OutboxDraft<TPayload>;\n    /**\n     * Query key to optimistically patch and (optionally) invalidate. Omit to\n     * only enqueue without touching the React Query cache.\n     */\n    queryKey?: QueryKey;\n    /**\n     * Produce the next cached value from the current one and the variables.\n     * Runs in `onMutate`; the previous value is restored automatically if the\n     * enqueue throws. Requires `queryKey`.\n     */\n    applyOptimistic?: (current: TData | undefined, variables: TVariables) => TData;\n    /**\n     * Trigger a flush after enqueueing. `true` (default) uses\n     * `\"after-mutation\"`; pass a custom {@link SyncTrigger} string, or `false`\n     * to leave flushing to the caller / auto-flush hooks.\n     */\n    flush?: boolean | SyncTrigger;\n    /** Invalidate `queryKey` in `onSettled` so a later read refetches. Default `false`. */\n    invalidate?: boolean;\n}\n\ninterface MutationContext<TData> {\n    previous: TData | undefined;\n}\n\n/**\n * Optimistic mutation that writes to an {@link OfflineSync} outbox instead of\n * hitting the network directly, bridging the sync engine and TanStack Query.\n *\n * On `mutate` it enqueues the entry, optimistically patches the given query\n * cache key and kicks a flush; if the enqueue itself throws, the cache is\n * rolled back to its previous value. Server delivery happens later inside the\n * engine's flush loop, so the UI updates instantly and survives reloads and\n * offline periods.\n *\n * @typeParam TVariables - The `mutate(variables)` input shape.\n * @typeParam TData - The cached query data optimistically patched.\n * @typeParam TPayload - Record snapshot carried by outbox entries.\n * @param options - Engine, variables→entry mapping and cache wiring.\n * @returns The TanStack {@link UseMutationResult}; the mutation resolves to the\n *   generated outbox entry id.\n *\n * @example\n * const addNote = useOfflineMutation({\n *     sync: notesSync,\n *     queryKey: [\"notes\"],\n *     toEntry: (note: Note) => ({ op: \"create\", recordId: note.id, payload: note }),\n *     applyOptimistic: (current: Note[] = [], note) => [...current, note],\n * });\n * addNote.mutate(newNote);\n */\nexport function useOfflineMutation<TVariables, TData = unknown, TPayload = unknown>(\n    options: UseOfflineMutationOptions<TVariables, TData, TPayload>,\n): UseMutationResult<string, Error, TVariables, MutationContext<TData>> {\n    const { sync, toEntry, queryKey, applyOptimistic, flush = true, invalidate = false } = options;\n    const client = useQueryClient();\n\n    return useMutation<string, Error, TVariables, MutationContext<TData>>({\n        mutationFn: async (variables) => {\n            const draft = toEntry(variables);\n            const id = await sync.enqueue(draft.op, draft.recordId, draft.payload);\n            if (flush !== false) {\n                const trigger: SyncTrigger = flush === true ? \"after-mutation\" : flush;\n                void sync.flush(trigger);\n            }\n            return id;\n        },\n        onMutate: async (variables) => {\n            if (!queryKey || !applyOptimistic) return { previous: undefined };\n            await client.cancelQueries({ queryKey });\n            const previous = client.getQueryData<TData>(queryKey);\n            client.setQueryData<TData>(queryKey, (current) => applyOptimistic(current, variables));\n            return { previous };\n        },\n        onError: (_error, _variables, context) => {\n            if (queryKey && context) client.setQueryData(queryKey, context.previous);\n        },\n        onSettled: () => {\n            if (invalidate && queryKey) void client.invalidateQueries({ queryKey });\n        },\n    });\n}\n"],"mappings":"uCA6EA,SAAgB,EACZ,EACoE,CACpE,GAAM,CAAE,OAAM,UAAS,WAAU,kBAAiB,QAAQ,GAAM,aAAa,IAAU,EACjF,GAAA,EAAS,EAAA,eAAA,CAAe,EAE9B,OAAA,EAAO,EAAA,YAAA,CAA+D,CAClE,WAAY,KAAO,IAAc,CAC7B,IAAM,EAAQ,EAAQ,CAAS,EACzB,EAAK,MAAM,EAAK,QAAQ,EAAM,GAAI,EAAM,SAAU,EAAM,OAAO,EACrE,GAAI,IAAU,GAAO,CACjB,IAAM,EAAuB,IAAU,GAAO,iBAAmB,EACjE,EAAU,MAAM,CAAO,CAC3B,CACA,OAAO,CACX,EACA,SAAU,KAAO,IAAc,CAC3B,GAAI,CAAC,GAAY,CAAC,EAAiB,MAAO,CAAE,SAAU,IAAA,EAAU,EAChE,MAAM,EAAO,cAAc,CAAE,UAAS,CAAC,EACvC,IAAM,EAAW,EAAO,aAAoB,CAAQ,EAEpD,OADA,EAAO,aAAoB,EAAW,GAAY,EAAgB,EAAS,CAAS,CAAC,EAC9E,CAAE,UAAS,CACtB,EACA,SAAU,EAAQ,EAAY,IAAY,CAClC,GAAY,GAAS,EAAO,aAAa,EAAU,EAAQ,QAAQ,CAC3E,EACA,cAAiB,CACT,GAAc,GAAU,EAAY,kBAAkB,CAAE,UAAS,CAAC,CAC1E,CACJ,CAAC,CACL"}