@tanstack/offline-transactions
Version:
Offline-first transaction capabilities for TanStack DB
122 lines (121 loc) • 4.23 kB
text/typescript
import { Collection, MutationFnParams, PendingMutation, Transaction } from '@tanstack/db';
export type OfflineMutationFnParams<T extends object = Record<string, unknown>> = MutationFnParams<T> & {
idempotencyKey: string;
};
export type OfflineMutationFn<T extends object = Record<string, unknown>> = (params: OfflineMutationFnParams<T>) => Promise<any>;
export interface SerializedMutation {
globalKey: string;
type: string;
modified: any;
original: any;
changes: any;
collectionId: string;
}
export interface SerializedError {
name: string;
message: string;
stack?: string;
}
export interface SerializedSpanContext {
traceId: string;
spanId: string;
traceFlags: number;
traceState?: string;
}
export interface OfflineTransaction {
id: string;
mutationFnName: string;
mutations: Array<PendingMutation>;
keys: Array<string>;
idempotencyKey: string;
createdAt: Date;
retryCount: number;
nextAttemptAt: number;
lastError?: SerializedError;
metadata?: Record<string, any>;
spanContext?: SerializedSpanContext;
version: 1;
}
export interface SerializedOfflineTransaction {
id: string;
mutationFnName: string;
mutations: Array<SerializedMutation>;
keys: Array<string>;
idempotencyKey: string;
createdAt: string;
retryCount: number;
nextAttemptAt: number;
lastError?: SerializedError;
metadata?: Record<string, any>;
spanContext?: SerializedSpanContext;
version: 1;
}
export type OfflineMode = `offline` | `online-only`;
export type StorageDiagnosticCode = `STORAGE_AVAILABLE` | `INDEXEDDB_UNAVAILABLE` | `LOCALSTORAGE_UNAVAILABLE` | `STORAGE_BLOCKED` | `QUOTA_EXCEEDED` | `UNKNOWN_ERROR`;
export interface StorageDiagnostic {
code: StorageDiagnosticCode;
mode: OfflineMode;
message: string;
error?: Error;
}
export interface OfflineConfig {
collections: Record<string, Collection<any, any, any, any, any>>;
mutationFns: Record<string, OfflineMutationFn>;
storage?: StorageAdapter;
maxConcurrency?: number;
jitter?: boolean;
beforeRetry?: (transactions: Array<OfflineTransaction>) => Array<OfflineTransaction>;
onUnknownMutationFn?: (name: string, tx: OfflineTransaction) => void;
onLeadershipChange?: (isLeader: boolean) => void;
onStorageFailure?: (diagnostic: StorageDiagnostic) => void;
leaderElection?: LeaderElection;
/**
* Custom online detector implementation.
* Defaults to WebOnlineDetector for browser environments.
* The '@tanstack/offline-transactions/react-native' entry point uses ReactNativeOnlineDetector automatically.
*/
onlineDetector?: OnlineDetector;
}
export interface StorageAdapter {
get: (key: string) => Promise<string | null>;
set: (key: string, value: string) => Promise<void>;
delete: (key: string) => Promise<void>;
keys: () => Promise<Array<string>>;
clear: () => Promise<void>;
}
export interface RetryPolicy {
calculateDelay: (retryCount: number) => number;
shouldRetry: (error: Error, retryCount: number) => boolean;
}
export interface LeaderElection {
requestLeadership: () => Promise<boolean>;
releaseLeadership: () => void;
isLeader: () => boolean;
onLeadershipChange: (callback: (isLeader: boolean) => void) => () => void;
}
export interface TransactionSignaler {
resolveTransaction: (transactionId: string, result: any) => void;
rejectTransaction: (transactionId: string, error: Error) => void;
registerRestorationTransaction: (offlineTransactionId: string, restorationTransaction: Transaction) => void;
isOnline: () => boolean;
}
export interface OnlineDetector {
subscribe: (callback: () => void) => () => void;
notifyOnline: () => void;
isOnline: () => boolean;
dispose: () => void;
}
export interface CreateOfflineTransactionOptions {
id?: string;
mutationFnName: string;
autoCommit?: boolean;
idempotencyKey?: string;
metadata?: Record<string, any>;
}
export interface CreateOfflineActionOptions<T> {
mutationFnName: string;
onMutate: (variables: T) => void;
}
export declare class NonRetriableError extends Error {
constructor(message: string);
}