Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/js-client-sdk.iclientconfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,25 @@ boolean
_(Optional)_ Whether initialization will be considered successfully complete if expired cache values are loaded. If false, initialization will always wait for a fetch if cached values are expired. (default: false)


</td></tr>
<tr><td>

[useIndexedDB?](./js-client-sdk.iclientconfig.useindexeddb.md)


</td><td>


</td><td>

boolean


</td><td>

_(Optional)_ Use IndexedDB for storing flag configurations and assignment cache instead of localStorage. IndexedDB provides significantly larger storage capacity (gigabytes, browser-dependent) compared to localStorage (\~5-10MB). Data is stored as native JavaScript objects using IndexedDB's structured clone algorithm for efficient storage and retrieval. (default: false)


</td></tr>
</tbody></table>

13 changes: 13 additions & 0 deletions docs/js-client-sdk.iclientconfig.useindexeddb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@eppo/js-client-sdk](./js-client-sdk.md) &gt; [IClientConfig](./js-client-sdk.iclientconfig.md) &gt; [useIndexedDB](./js-client-sdk.iclientconfig.useindexeddb.md)

## IClientConfig.useIndexedDB property

Use IndexedDB for storing flag configurations and assignment cache instead of localStorage. IndexedDB provides significantly larger storage capacity (gigabytes, browser-dependent) compared to localStorage (\~5-10MB). Data is stored as native JavaScript objects using IndexedDB's structured clone algorithm for efficient storage and retrieval. (default: false)

**Signature:**

```typescript
useIndexedDB?: boolean;
```
19 changes: 19 additions & 0 deletions docs/js-client-sdk.iprecomputedclientconfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,25 @@ IPrecompute
</td><td>


</td></tr>
<tr><td>

[useIndexedDB?](./js-client-sdk.iprecomputedclientconfig.useindexeddb.md)


</td><td>


</td><td>

boolean


</td><td>

_(Optional)_ Use IndexedDB for storing flag configurations and assignment cache instead of localStorage. IndexedDB provides significantly larger storage capacity (gigabytes, browser-dependent) compared to localStorage (\~5-10MB). Data is stored as native JavaScript objects using IndexedDB's structured clone algorithm for efficient storage and retrieval. (default: false)


</td></tr>
</tbody></table>

13 changes: 13 additions & 0 deletions docs/js-client-sdk.iprecomputedclientconfig.useindexeddb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@eppo/js-client-sdk](./js-client-sdk.md) &gt; [IPrecomputedClientConfig](./js-client-sdk.iprecomputedclientconfig.md) &gt; [useIndexedDB](./js-client-sdk.iprecomputedclientconfig.useindexeddb.md)

## IPrecomputedClientConfig.useIndexedDB property

Use IndexedDB for storing flag configurations and assignment cache instead of localStorage. IndexedDB provides significantly larger storage capacity (gigabytes, browser-dependent) compared to localStorage (\~5-10MB). Data is stored as native JavaScript objects using IndexedDB's structured clone algorithm for efficient storage and retrieval. (default: false)

**Signature:**

```typescript
useIndexedDB?: boolean;
```
2 changes: 2 additions & 0 deletions js-client-sdk.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export interface IClientConfig extends IBaseRequestConfig {
// Warning: (ae-forgotten-export) The symbol "ServingStoreUpdateStrategy" needs to be exported by the entry point index.d.ts
updateOnFetch?: ServingStoreUpdateStrategy;
useExpiredCache?: boolean;
useIndexedDB?: boolean;
}

// @public
Expand Down Expand Up @@ -198,6 +199,7 @@ export interface IPrecomputedClientConfig extends IBaseRequestConfig {
//
// (undocumented)
precompute: IPrecompute;
useIndexedDB?: boolean;
}

// @public
Expand Down
20 changes: 13 additions & 7 deletions src/cache/assignment-cache-factory.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { AssignmentCache } from '@eppo/js-client-sdk-common';

import { hasWindowLocalStorage } from '../configuration-factory';
import { hasIndexedDB, hasWindowLocalStorage } from '../configuration-factory';

import ChromeStorageAssignmentCache from './chrome-storage-assignment-cache';
import HybridAssignmentCache from './hybrid-assignment-cache';
import { IndexedDBAssignmentCache } from './indexed-db-assignment-cache';
import { LocalStorageAssignmentCache } from './local-storage-assignment-cache';
import SimpleAssignmentCache from './simple-assignment-cache';

export function assignmentCacheFactory({
forceMemoryOnly = false,
useIndexedDB = false,
chromeStorage,
storageKeySuffix,
}: {
forceMemoryOnly?: boolean;
useIndexedDB?: boolean;
storageKeySuffix: string;
chromeStorage?: chrome.storage.StorageArea;
}): AssignmentCache {
Expand All @@ -22,15 +25,18 @@ export function assignmentCacheFactory({
return simpleCache;
}

// Priority order: Chrome storage > IndexedDB (if opted in) > localStorage > memory-only
if (chromeStorage) {
const chromeStorageCache = new ChromeStorageAssignmentCache(chromeStorage);
return new HybridAssignmentCache(simpleCache, chromeStorageCache);
} else if (useIndexedDB && hasIndexedDB()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥

// IndexedDB is available and user has opted in
const indexedDBCache = new IndexedDBAssignmentCache(storageKeySuffix);
return new HybridAssignmentCache(simpleCache, indexedDBCache);
} else if (hasWindowLocalStorage()) {
const localStorageCache = new LocalStorageAssignmentCache(storageKeySuffix);
return new HybridAssignmentCache(simpleCache, localStorageCache);
} else {
if (hasWindowLocalStorage()) {
const localStorageCache = new LocalStorageAssignmentCache(storageKeySuffix);
return new HybridAssignmentCache(simpleCache, localStorageCache);
} else {
return simpleCache;
}
return simpleCache;
}
}
39 changes: 39 additions & 0 deletions src/cache/indexed-db-assignment-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { AbstractAssignmentCache } from '@eppo/js-client-sdk-common';

import { BulkReadAssignmentCache, BulkWriteAssignmentCache } from './hybrid-assignment-cache';
import { IndexedDBAssignmentShim } from './indexed-db-assignment-shim';

/**
* IndexedDB-backed assignment cache.
*
* Provides persistent storage for assignment results with larger capacity than localStorage.
* Stores assignments as a blob in IndexedDB for efficient storage and retrieval.
*/
export class IndexedDBAssignmentCache
extends AbstractAssignmentCache<IndexedDBAssignmentShim>
implements BulkReadAssignmentCache, BulkWriteAssignmentCache
{
constructor(storageKeySuffix: string) {
super(new IndexedDBAssignmentShim(storageKeySuffix));
}

setEntries(entries: [string, string][]): void {
entries.forEach(([key, value]) => {
if (key && value) {
this.delegate.set(key, value);
}
});
}

async getEntries(): Promise<[string, string][]> {
return Array.from(this.entries());
}

/**
* Initialize the cache by loading from IndexedDB.
* This should be called during SDK initialization.
*/
async init(): Promise<void> {
await this.delegate.init();
}
}
Loading