Repository navigation
Persist browser exposure deduplication in IndexedDB - #188
Conversation
…tToken Replace the localStorage-based assignment cache (exposure deduplication) with IndexedDB, consistent with the flags cache. Storage is now scoped by clientToken via buildStorageKeySuffix(), so different apps on the same origin no longer share state. - New IndexedDBAssignmentCache: same dd-flagging DB / configurations store, in-memory Map mirror for fast synchronous set(), fire-and-forget persistence to IndexedDB. - Simplified factory: IndexedDB → memory-only (Chrome storage and localStorage dropped). - Updated provider to pass clientToken instead of hardcoded key.
c40284b to
9998cf0
Compare
There was a problem hiding this comment.
Pull request overview
This PR changes the browser SDK’s exposure/assignment deduplication cache persistence to use IndexedDB (shared with the flags cache) and scopes the persisted data by clientToken, preventing cross-app collisions on the same origin.
Changes:
- Introduces
IndexedDBAssignmentCacheand updatesassignmentCacheFactoryto use IndexedDB (or fall back to memory-only). - Updates the OpenFeature provider to pass
clientTokeninto the assignment cache factory. - Updates/adds tests to use
fake-indexeddband to reset IndexedDB between test runs; removes Chrome storage assignment cache code.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/browser/src/cache/indexeddb-assignment-cache.ts | Adds new IndexedDB-backed assignment cache with an in-memory mirror and fire-and-forget persistence. |
| packages/browser/src/cache/assignment-cache-factory.ts | Simplifies factory to choose between IndexedDB-backed hybrid cache and memory-only cache. |
| packages/browser/src/openfeature/provider.ts | Switches provider to create the exposure cache using clientToken. |
| packages/browser/src/cache/helpers.ts | Removes Chrome storage helpers; keeps localStorage + IndexedDB availability helpers. |
| packages/browser/src/cache/chrome-storage-async-map.ts | Removes Chrome storage async map implementation. |
| packages/browser/src/cache/chrome-storage-assignment-cache.ts | Removes Chrome storage assignment cache implementation. |
| packages/browser/test/openfeature/exposures.spec.ts | Resets IndexedDB between tests instead of clearing localStorage; adds fake-indexeddb setup. |
| packages/browser/test/cache/indexeddb-assignment-cache.spec.ts | Adds coverage for IndexedDBAssignmentCache behavior and token isolation. |
| packages/browser/test/cache/hybrid-assignment-cache.spec.ts | Updates hybrid cache test to hydrate serving cache from persistent IndexedDB store. |
| packages/browser/test/cache/assignment-cache-factory.spec.ts | Updates factory tests for IndexedDB availability and memory-only fallback. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Delete orphaned localStorage and Chrome storage cache files and helpers. - Extract shared openDB() and IndexedDB constants into indexeddb-store.ts. - Batch persist() writes via queueMicrotask so rapid set() calls coalesce into a single IDB transaction per tick. - Move structuredClone polyfill and fake-indexeddb setup to shared jest setup file. - Replace inline require() with top-level import in exposures spec. - Add cross-instance persistence test for the page-reload scenario.
greghuels
left a comment
There was a problem hiding this comment.
Nothing major, but one thing to note is that the local exposure deduplication cache might be wiped out after users upgrade. I don't think that's blocking though, and a migration from localStorage to indexeddb might be overkill.
Yes we're starting fresh. |
OpenFeature Browser Provider Bundle SizesMeasured from the Vite production output after installing packed Both scenarios initialize an OpenFeature provider, evaluate a boolean flag, change context, and evaluate again. Telemetry is disabled for DatadogProvider; no tracking hooks are registered for DatadogCoreProvider. DatadogProvider fetches precomputed assignments for each context; DatadogCoreProvider receives rules from fetchRulesConfiguration once and evaluates locally. Sizes include OpenFeature and the same small scenario harness. Configuration responses are supplied by Playwright and are not bundled. These are complete scenario JS sizes, not configuration payload sizes or isolated provider/Protobuf costs; the difference between rows is not a decoder-only delta.
Dependency checks passed: no Protobuf markers in default/precomputed scenarios; markers present in rules-based scenarios. OpenFeature Browser Tracking Hook Bundle SizesSynthetic entrypoints import and call tracking hook factories from the packed
OpenFeature Node Server Bundle SizesIndependent Webpack production builds of the installed core and Node SDK tarballs, targeting Node 18 with ESM (
Adding SSR helpers to the provider adds 79.7 KiB raw / 22.1 KiB gzip in this build. This includes fetching, parsing, and serialization, not just the decoder. SSR helpers fetch rules for the browser, not for configuring that provider (which uses its existing JSON API). These are bundler sizes, not npm install sizes, unbundled Node require/import costs, payload sizes, or latency. Gzip compares compressed artifacts. The browser scenarios include OpenFeature and a different harness, so their sizes are not directly comparable. Dependency checks passed: no Protobuf runtime or generated schema modules in the provider-only bundle; present in both SSR bundles (checked using Webpack module statistics). This report shows current PR artifact sizes only; it does not compare against the base branch. |
…ency 🐛 fix(browser): preserve exposure cache updates across instances
Motivation
Browser exposure deduplication still uses localStorage or Chrome storage. localStorage serializes and writes the cache during evaluation. Use IndexedDB, which already stores flag configurations, for asynchronous persistence.
Changes and Decisions
createdAtinvalidation behavior.Validation
Ran the packed release-mode SDK in Chromium. Verified exposure deduplication across reloads and obfuscation salt changes, separate client-token scopes, and original flag keys in exposure payloads. All 10 browser smoke scenarios passed. Responses came from local fixtures; this was not a staging test.