feat: offline-first capabilities — transaction queue, SW caching, background sync (#483) - #617
Merged
Topmatrixmor2014 merged 3 commits intoSep 4, 2026
Conversation
The moduleNameMapper pointed at lib/index.js, which no longer exists in @stellar/stellar-sdk v16 (entries now live under lib/cjs and lib/esm). Point it at lib/cjs/index.js so Jest can resolve the SDK.
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements Issue #483 — Offline-First Capabilities Enhancement: offline transaction queuing with IndexedDB persistence, strategic service-worker caching, an offline transaction composer, background sync, and connectivity-aware UI.
What was built — mapped to the acceptance criteria
Transactions composed offline are queued in IndexedDB and survive page reloads
frontend/lib/offlineQueue.tsis rewritten around a generic, fully-typed IndexedDB-backed queue. Entry shape is{ id, type, payload, createdAt, status: 'pending' | 'processing' | 'failed', retryCount }, with the APIenqueue(type, payload),dequeue(),peek(),remove(id),getAll(),getFailed(). Persistence across reloads is covered by unit tests that reset the module and re-read from IndexedDB.Service worker caches static assets and serves them offline
frontend/public/sw.jsuses a cache-first strategy for static assets (app shell: JS/CSS/images/fonts) with cache versioning (CACHE_VERSION) and cleanup of stale caches onactivate.API responses (balance, transactions) are cached and served offline
Network-first with cache fallback for balance and transactions API responses; stale-while-revalidate for price feeds.
Background sync automatically processes the queue when online
A
syncevent listener on theprocess-transaction-queuetag drains the queue in FIFO order.registerQueueSync()registers the tag, anduseNetworkStatusre-registers sync and triggers processing on reconnection (with a main-thread fallback for browsers without the Background Sync API).Failed transactions show in queue with retry status
Max 3 retries per entry with exponential backoff (
backoffDelayMs).getFailed()plus per-item status in the composer surface failures and retry state.OfflineBanner shows pending queue count
getQueueCount()is unified to include the new generic queue, so the existingOfflineBanner(which already consumedgetQueueCount()) reflects pending generic entries with no props-contract change.e2e tests cover the offline → online transition
frontend/e2e/offline.spec.tsextended with an offline → compose → queue → online → auto-submit flow.Tests
frontend/__tests__/offlineQueue.test.tsextended to 31 tests covering enqueue/dequeue ordering, retry + backoff, persistence across simulated reloads, malformed legacy entries, and failure states. All 31 pass locally.Files changed
frontend/lib/offlineQueue.tsfrontend/public/sw.js/offlinefallback,process-transaction-queuesync drainfrontend/components/OfflineTransactionComposer.tsxfrontend/components/TransactionList.tsxfrontend/hooks/useNetworkStatus.tsfrontend/pages/offline.tsxfrontend/__tests__/offlineQueue.test.tsfrontend/e2e/offline.spec.tsfrontend/jest.config.ts@stellar/stellar-sdkmapping to its v16 CJS entry (lib/cjs/index.js)Scope exclusions
Per the issue's Out of Scope: no offline transaction signing (requires Freighter) and no offline contract interactions. Legacy signed-XDR queue behavior (
submit-payments) is preserved unchanged.How to test (manual)
npm run devand open the app.Screenshots / GIF
CI notes (pre-existing, unrelated to #483)
The following checks fail on the current
mainbaseline (verified locally) and are not introduced by this PR:npm run type-check— 223 pre-existing TS errors across many files (stale APIs, renamed exports, type drift).npm test— ~29 pre-existing failing suites:@stellar/stellar-sdkv16 depends on ESM-only@noble/*packages that Jest (CommonJS) can't parse, plus stale test mocks/fixtures. (This PR includes the correctlib/cjs/index.jsmapping fix; the remaining@nobleESM transform requires a separate babel/jest config change.)npm run build-storybook— Storybook's Next.js plugin can't findnext/dist/build/webpack/plugins/define-env-plugin.js(Next 16 incompatibility).What passes:
npm run lint(0 errors),npm run i18n:check,npm run build, and the 31 new/extendedofflineQueueunit tests.Closes #483