-
Notifications
You must be signed in to change notification settings - Fork 159
Restore offline transactions to optimistic store upon restart the app #1169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Restore offline transactions to optimistic store upon restart the app #1169
Conversation
🦋 Changeset detectedLatest commit: 1eda746 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
More templates
@tanstack/angular-db
@tanstack/db
@tanstack/db-ivm
@tanstack/electric-db-collection
@tanstack/offline-transactions
@tanstack/powersync-db-collection
@tanstack/query-db-collection
@tanstack/react-db
@tanstack/rxdb-db-collection
@tanstack/solid-db
@tanstack/svelte-db
@tanstack/trailbase-db-collection
@tanstack/vue-db
commit: |
…refresh Add a failing test that demonstrates the issue where offline transactions do not restore optimistic state to the collection when the page is refreshed while offline. Users have to manually handle this in beforeRetry by replaying all transactions into the collection. The test asserts the expected behavior (optimistic data should be present after page refresh) and currently fails, demonstrating the bug.
c618c2c to
72f94f9
Compare
|
Size Change: 0 B Total Size: 90.8 kB ℹ️ View Unchanged
|
|
Size Change: 0 B Total Size: 3.7 kB ℹ️ View Unchanged
|
When the page is refreshed while offline with pending transactions, the optimistic state was not being restored to collections. Users had to manually replay transactions in `beforeRetry` to restore UI state. This fix: 1. In `loadPendingTransactions()`, creates restoration transactions that hold the deserialized mutations and registers them with the collection's state manager to display optimistic data immediately 2. Properly reconstructs the mutation `key` during deserialization using the collection's `getKeyFromItem()` method, which is needed for optimistic state lookup 3. Cleans up restoration transactions when the offline transaction completes or fails, allowing sync data to take over 4. Adds `waitForInit()` method to allow waiting for full initialization including pending transaction loading 5. Updates `loadAndReplayTransactions()` to not block on execution, so initialization completes as soon as optimistic state is restored
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Consolidate restorationTransactions.delete() to single point - Improve comments on restoration transaction purpose Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add try-catch isolation in restoreOptimisticState to prevent one bad transaction from breaking all restoration - Add defensive null check for mutation.collection in cleanup methods - Add test for rollback of restored optimistic state on permanent failure Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… cleanup Add catch handler to restoration transaction's isPersisted promise to prevent unhandled rejection when rollback() is called during cleanup. The rollback calls reject(undefined) which would otherwise cause an unhandled rejection error.
|
I reported this bug and just tested this PR build locally. After refreshing while offline, the optimistic state is now restored correctly and pending changes show up immediately on page load. |
Summary
Fixes offline transactions not restoring optimistic state when the page is refreshed while offline. Users now see their pending changes immediately on page load, providing a seamless offline UX.
Root Cause
When the
OfflineExecutorloaded pending transactions from storage on startup, it only scheduled them for execution—it never re-applied the mutations to the collection's state manager. The optimistic state lived only in memory and was lost on page refresh.Approach
Created "restoration transactions" that shadow the persisted offline transactions:
When pending transactions are loaded from storage, we:
Key Invariants
keypopulated for optimistic state to workNon-goals
Trade-offs
Alternative considered: Storing the optimistic state separately from the transaction data.
Why this approach: Reusing the existing transaction/mutation infrastructure is simpler and leverages the collection's built-in optimistic state management. No new storage schema or state reconciliation logic needed.
Verification
The new test
should restore optimistic state to collection on startupverifies the complete flow:Files Changed
OfflineExecutor.tsrestorationTransactionsmap,registerRestorationTransaction(),cleanupRestorationTransaction(), andwaitForInit()helperTransactionExecutor.tsrestoreOptimisticState()that creates restoration transactions on loadTransactionSerializer.tskeyfrom modified data during deserializationoffline-e2e.test.tsharness.ts