{"_id":"@autarcgmbh/offline-transactions","_rev":"3-afa2cbeb7cbd5a7773e100806d902644","name":"@autarcgmbh/offline-transactions","dist-tags":{"beta":"0.0.1","latest":"0.1.0"},"versions":{"0.0.1":{"name":"@autarcgmbh/offline-transactions","version":"0.0.1","keywords":["tanstack","database","offline","transactions","persistence","sync"],"author":{"name":"Autarc GmbH"},"license":"MIT","_id":"@autarcgmbh/offline-transactions@0.0.1","maintainers":[{"name":"autarctomasgonzalez","email":"tomas@autarc.energy"}],"homepage":"https://github.com/autarcgmbh/db#readme","bugs":{"url":"https://github.com/autarcgmbh/db/issues"},"dist":{"shasum":"2149c705f23d541a2c9262f05894d53ad1cbb2ad","tarball":"https://registry.npmjs.org/@autarcgmbh/offline-transactions/-/offline-transactions-0.0.1.tgz","fileCount":29,"integrity":"sha512-fJEPj7QLlZugb0OEIO0rXQ0lB9J6/3oFBuJJi4MjgG6LH+aKvcTU84r+YkETkM/JdDPCRbsB4X4LBIeisngi7w==","signatures":[{"sig":"MEUCIQCmespwJtS+R9kGHs/worbbH7Iln50Xdv2x8aYTj27WYAIgZa0iBwHoE1aeLUJffJhRjP6qcK1OIi1XXR1iT14AZCM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":324255},"main":"./dist/index.cjs","type":"module","_from":"file:autarcgmbh-offline-transactions-0.0.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"lint":"eslint src","test":"vitest","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest --watch"},"_npmUser":{"name":"autarctomasgonzalez","email":"tomas@autarc.energy"},"_resolved":"/private/var/folders/qq/9wpb40ps6wn4262qdf8n37d00000gn/T/0a9e6c432bfe0cb0783cede75a1ca3b8/autarcgmbh-offline-transactions-0.0.1.tgz","_integrity":"sha512-fJEPj7QLlZugb0OEIO0rXQ0lB9J6/3oFBuJJi4MjgG6LH+aKvcTU84r+YkETkM/JdDPCRbsB4X4LBIeisngi7w==","repository":{"url":"git+https://github.com/autarcgmbh/db.git","type":"git","directory":"packages/offline-transactions"},"_npmVersion":"11.5.1","description":"Offline-first transaction capabilities for TanStack DB","directories":{},"sideEffects":false,"_nodeVersion":"24.5.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"^8.57.0","vitest":"^2.0.0","typescript":"^5.5.4","@types/node":"^20.0.0"},"peerDependencies":{"@tanstack/db":"^0.3.1"},"_npmOperationalInternal":{"tmp":"tmp/offline-transactions_0.0.1_1758186452868_0.5613724071800126","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@autarcgmbh/offline-transactions","version":"0.1.0","description":"Offline-first transaction capabilities for TanStack DB","author":{"name":"Autarc GmbH"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/autarcgmbh/db.git","directory":"packages/offline-transactions"},"publishConfig":{"access":"public"},"keywords":["tanstack","database","offline","transactions","persistence","sync"],"type":"module","sideEffects":false,"exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.cts","default":"./dist/cjs/index.cjs"}},"./package.json":"./package.json"},"main":"dist/cjs/index.cjs","module":"dist/esm/index.js","types":"dist/esm/index.d.ts","scripts":{"build":"vite build","dev":"vite build --watch","test":"vitest","test:watch":"vitest --watch","typecheck":"tsc --noEmit","lint":"eslint src"},"peerDependencies":{"@tanstack/db":"workspace:*"},"devDependencies":{"@types/node":"^20.0.0","eslint":"^8.57.0","typescript":"^5.5.4","vitest":"^3.2.4"},"_id":"@autarcgmbh/offline-transactions@0.1.0","gitHead":"fab63f0e150270e3eb057065a1abff9839955690","bugs":{"url":"https://github.com/autarcgmbh/db/issues"},"homepage":"https://github.com/autarcgmbh/db#readme","_nodeVersion":"24.5.0","_npmVersion":"11.5.1","dist":{"integrity":"sha512-4NXPI8KplQAoGmr1poaNGQqDZoUINm4Zt77clwA29F6kk+5lhVg0WZ6YJkO6eoNAc0lcsaKMpgDlppFjhJ7zSg==","shasum":"d69fbbb2192c40306d25af1c3addbe92b1bb53c3","tarball":"https://registry.npmjs.org/@autarcgmbh/offline-transactions/-/offline-transactions-0.1.0.tgz","fileCount":131,"unpackedSize":325447,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD/udKTr6FUAifW4kG/AptrgEpj+rnuWgxNuLnXGI/bagIhAJBeDuoaMopBVwVft1vDqhsTf98ur+St1n4prK0IHO19"}]},"_npmUser":{"name":"autarctomasgonzalez","email":"tomas@autarc.energy"},"directories":{},"maintainers":[{"name":"autarctomasgonzalez","email":"tomas@autarc.energy"},{"name":"marius-autarc","email":"marius@autarc.energy"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/offline-transactions_0.1.0_1758704018120_0.9147514086535897"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-18T09:07:32.775Z","modified":"2025-09-24T08:53:38.545Z","0.0.1":"2025-09-18T09:07:33.087Z","0.1.0":"2025-09-24T08:53:38.327Z"},"bugs":{"url":"https://github.com/autarcgmbh/db/issues"},"author":{"name":"Autarc GmbH"},"license":"MIT","homepage":"https://github.com/autarcgmbh/db#readme","keywords":["tanstack","database","offline","transactions","persistence","sync"],"repository":{"type":"git","url":"git+https://github.com/autarcgmbh/db.git","directory":"packages/offline-transactions"},"description":"Offline-first transaction capabilities for TanStack DB","maintainers":[{"name":"autarctomasgonzalez","email":"tomas@autarc.energy"},{"name":"marius-autarc","email":"marius@autarc.energy"}],"readme":"# @tanstack/offline-transactions\n\nOffline-first transaction capabilities for TanStack DB that provides durable persistence of mutations with automatic retry when connectivity is restored.\n\n## Features\n\n- **Outbox Pattern**: Persist mutations before dispatch for zero data loss\n- **Automatic Retry**: Exponential backoff with jitter for failed transactions\n- **Multi-tab Coordination**: Leader election ensures safe storage access\n- **FIFO Sequential Processing**: Transactions execute one at a time in creation order\n- **Flexible Storage**: IndexedDB with localStorage fallback\n- **Type Safe**: Full TypeScript support with TanStack DB integration\n\n## Installation\n\n```bash\nnpm install @tanstack/offline-transactions\n```\n\n## Quick Start\n\n```typescript\nimport { startOfflineExecutor } from \"@tanstack/offline-transactions\"\n\n// Setup offline executor\nconst offline = startOfflineExecutor({\n  collections: { todos: todoCollection },\n  mutationFns: {\n    syncTodos: async ({ transaction, idempotencyKey }) => {\n      await api.saveBatch(transaction.mutations, { idempotencyKey })\n    },\n  },\n  onLeadershipChange: (isLeader) => {\n    if (!isLeader) {\n      console.warn(\"Running in online-only mode (another tab is the leader)\")\n    }\n  },\n})\n\n// Create offline transactions\nconst offlineTx = offline.createOfflineTransaction({\n  mutationFnName: \"syncTodos\",\n  autoCommit: false,\n})\n\nofflineTx.mutate(() => {\n  todoCollection.insert({\n    id: crypto.randomUUID(),\n    text: \"Buy milk\",\n    completed: false,\n  })\n})\n\n// Execute with automatic offline support\nawait offlineTx.commit()\n```\n\n## Core Concepts\n\n### Outbox-First Persistence\n\nMutations are persisted to a durable outbox before being applied, ensuring zero data loss during offline periods:\n\n1. Mutation is persisted to IndexedDB/localStorage\n2. Optimistic update is applied locally\n3. When online, mutation is sent to server\n4. On success, mutation is removed from outbox\n\n### Multi-tab Coordination\n\nOnly one tab acts as the \"leader\" to safely manage the outbox:\n\n- **Leader tab**: Full offline support with outbox persistence\n- **Non-leader tabs**: Online-only mode for safety\n- **Leadership transfer**: Automatic failover when leader tab closes\n\n### FIFO Sequential Processing\n\nTransactions are processed one at a time in the order they were created:\n\n- **Sequential execution**: All transactions execute in FIFO order\n- **Dependency safety**: Avoids conflicts between transactions that may reference each other\n- **Predictable behavior**: Transactions complete in the exact order they were created\n\n## API Reference\n\n### startOfflineExecutor(config)\n\nCreates and starts an offline executor instance.\n\n```typescript\ninterface OfflineConfig {\n  collections: Record<string, Collection>\n  mutationFns: Record<string, MutationFn>\n  storage?: StorageAdapter\n  maxConcurrency?: number\n  jitter?: boolean\n  beforeRetry?: (transactions: OfflineTransaction[]) => OfflineTransaction[]\n  onUnknownMutationFn?: (name: string, tx: OfflineTransaction) => void\n  onLeadershipChange?: (isLeader: boolean) => void\n}\n```\n\n### OfflineExecutor\n\n#### Properties\n\n- `isOfflineEnabled: boolean` - Whether this tab can persist offline transactions\n\n#### Methods\n\n- `createOfflineTransaction(options)` - Create a manual offline transaction\n- `waitForTransactionCompletion(id)` - Wait for a specific transaction to complete\n- `removeFromOutbox(id)` - Manually remove transaction from outbox\n- `peekOutbox()` - View all pending transactions\n- `notifyOnline()` - Manually trigger retry execution\n- `dispose()` - Clean up resources\n\n### Error Handling\n\nUse `NonRetriableError` for permanent failures:\n\n```typescript\nimport { NonRetriableError } from \"@tanstack/offline-transactions\"\n\nconst mutationFn = async ({ transaction }) => {\n  try {\n    await api.save(transaction.mutations)\n  } catch (error) {\n    if (error.status === 422) {\n      throw new NonRetriableError(\"Invalid data - will not retry\")\n    }\n    throw error // Will retry with backoff\n  }\n}\n```\n\n## Advanced Usage\n\n### Custom Storage Adapter\n\n```typescript\nimport {\n  IndexedDBAdapter,\n  LocalStorageAdapter,\n} from \"@tanstack/offline-transactions\"\n\nconst executor = startOfflineExecutor({\n  // Use custom storage\n  storage: new IndexedDBAdapter(\"my-app\", \"transactions\"),\n  // ... other config\n})\n```\n\n### Custom Retry Policy\n\n```typescript\nconst executor = startOfflineExecutor({\n  maxConcurrency: 5,\n  jitter: true,\n  beforeRetry: (transactions) => {\n    // Filter out old transactions\n    const cutoff = Date.now() - 24 * 60 * 60 * 1000 // 24 hours\n    return transactions.filter((tx) => tx.createdAt.getTime() > cutoff)\n  },\n  // ... other config\n})\n```\n\n### Manual Transaction Control\n\n```typescript\nconst tx = executor.createOfflineTransaction({\n  mutationFnName: \"syncData\",\n  autoCommit: false,\n})\n\ntx.mutate(() => {\n  collection.insert({ id: \"1\", text: \"Item 1\" })\n  collection.insert({ id: \"2\", text: \"Item 2\" })\n})\n\n// Commit when ready\nawait tx.commit()\n```\n\n## Migration from TanStack DB\n\nThis package uses explicit offline transactions to provide offline capabilities:\n\n```typescript\n// Before: Standard TanStack DB (online only)\ntodoCollection.insert({ id: \"1\", text: \"Buy milk\" })\n\n// After: Explicit offline transactions\nconst offline = startOfflineExecutor({\n  collections: { todos: todoCollection },\n  mutationFns: {\n    syncTodos: async ({ transaction }) => {\n      await api.sync(transaction.mutations)\n    },\n  },\n})\n\nconst tx = offline.createOfflineTransaction({ mutationFnName: \"syncTodos\" })\ntx.mutate(() => todoCollection.insert({ id: \"1\", text: \"Buy milk\" }))\nawait tx.commit() // Works offline!\n```\n\n## Browser Support\n\n- **IndexedDB**: Modern browsers (primary storage)\n- **localStorage**: Fallback for limited environments\n- **Web Locks API**: Chrome 69+, Firefox 96+ (preferred leader election)\n- **BroadcastChannel**: All modern browsers (fallback leader election)\n\n## License\n\nMIT\n","readmeFilename":"README.md"}