Skip to content

Commit 7bc0a35

Browse files
Support cooldown in chrome-backed configuration store (FF-2048) (#66)
* bump to commons 3.0.6; add LocalStorageBackedAsyncStore (FF-1980) * Add support for chrome.storage backed configuration store. * Support cooldown in chrome-backed configuration store (FF-2048) * Date.now() * option chain * docs * sync * restore test * restore specs * v3.0.2-rc.6 * export types
1 parent ec73898 commit 7bc0a35

12 files changed

+203
-10
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
2+
3+
[Home](./index.md) &gt; [@eppo/js-client-sdk](./js-client-sdk.md) &gt; [ChromeStorageAsyncStore](./js-client-sdk.chromestorageasyncstore.md) &gt; [(constructor)](./js-client-sdk.chromestorageasyncstore._constructor_.md)
4+
5+
## ChromeStorageAsyncStore.(constructor)
6+
7+
Constructs a new instance of the `ChromeStorageAsyncStore` class
8+
9+
**Signature:**
10+
11+
```typescript
12+
constructor(storageArea: chrome.storage.StorageArea, cooldownSeconds?: number | undefined);
13+
```
14+
15+
## Parameters
16+
17+
| Parameter | Type | Description |
18+
| --- | --- | --- |
19+
| storageArea | chrome.storage.StorageArea | |
20+
| cooldownSeconds | number \| undefined | _(Optional)_ |
21+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
2+
3+
[Home](./index.md) &gt; [@eppo/js-client-sdk](./js-client-sdk.md) &gt; [ChromeStorageAsyncStore](./js-client-sdk.chromestorageasyncstore.md) &gt; [getEntries](./js-client-sdk.chromestorageasyncstore.getentries.md)
4+
5+
## ChromeStorageAsyncStore.getEntries() method
6+
7+
**Signature:**
8+
9+
```typescript
10+
getEntries(): Promise<Record<string, T>>;
11+
```
12+
**Returns:**
13+
14+
Promise&lt;Record&lt;string, T&gt;&gt;
15+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
2+
3+
[Home](./index.md) &gt; [@eppo/js-client-sdk](./js-client-sdk.md) &gt; [ChromeStorageAsyncStore](./js-client-sdk.chromestorageasyncstore.md) &gt; [isExpired](./js-client-sdk.chromestorageasyncstore.isexpired.md)
4+
5+
## ChromeStorageAsyncStore.isExpired() method
6+
7+
**Signature:**
8+
9+
```typescript
10+
isExpired(): Promise<boolean>;
11+
```
12+
**Returns:**
13+
14+
Promise&lt;boolean&gt;
15+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
2+
3+
[Home](./index.md) &gt; [@eppo/js-client-sdk](./js-client-sdk.md) &gt; [ChromeStorageAsyncStore](./js-client-sdk.chromestorageasyncstore.md) &gt; [isInitialized](./js-client-sdk.chromestorageasyncstore.isinitialized.md)
4+
5+
## ChromeStorageAsyncStore.isInitialized() method
6+
7+
**Signature:**
8+
9+
```typescript
10+
isInitialized(): boolean;
11+
```
12+
**Returns:**
13+
14+
boolean
15+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
2+
3+
[Home](./index.md) &gt; [@eppo/js-client-sdk](./js-client-sdk.md) &gt; [ChromeStorageAsyncStore](./js-client-sdk.chromestorageasyncstore.md)
4+
5+
## ChromeStorageAsyncStore class
6+
7+
**Signature:**
8+
9+
```typescript
10+
export declare class ChromeStorageAsyncStore<T> implements IAsyncStore<T>
11+
```
12+
**Implements:** IAsyncStore&lt;T&gt;
13+
14+
## Constructors
15+
16+
| Constructor | Modifiers | Description |
17+
| --- | --- | --- |
18+
| [(constructor)(storageArea, cooldownSeconds)](./js-client-sdk.chromestorageasyncstore._constructor_.md) | | Constructs a new instance of the <code>ChromeStorageAsyncStore</code> class |
19+
20+
## Methods
21+
22+
| Method | Modifiers | Description |
23+
| --- | --- | --- |
24+
| [getEntries()](./js-client-sdk.chromestorageasyncstore.getentries.md) | | |
25+
| [isExpired()](./js-client-sdk.chromestorageasyncstore.isexpired.md) | | |
26+
| [isInitialized()](./js-client-sdk.chromestorageasyncstore.isinitialized.md) | | |
27+
| [setEntries(entries)](./js-client-sdk.chromestorageasyncstore.setentries.md) | | |
28+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
2+
3+
[Home](./index.md) &gt; [@eppo/js-client-sdk](./js-client-sdk.md) &gt; [ChromeStorageAsyncStore](./js-client-sdk.chromestorageasyncstore.md) &gt; [setEntries](./js-client-sdk.chromestorageasyncstore.setentries.md)
4+
5+
## ChromeStorageAsyncStore.setEntries() method
6+
7+
**Signature:**
8+
9+
```typescript
10+
setEntries(entries: Record<string, T>): Promise<void>;
11+
```
12+
13+
## Parameters
14+
15+
| Parameter | Type | Description |
16+
| --- | --- | --- |
17+
| entries | Record&lt;string, T&gt; | |
18+
19+
**Returns:**
20+
21+
Promise&lt;void&gt;
22+

docs/js-client-sdk.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
| Class | Description |
1010
| --- | --- |
11+
| [ChromeStorageAsyncStore](./js-client-sdk.chromestorageasyncstore.md) | |
1112
| [EppoJSClient](./js-client-sdk.eppojsclient.md) | Client for assigning experiment variations. |
1213

1314
## Functions

js-client-sdk.api.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,28 @@
44
55
```ts
66

7+
/// <reference types="chrome" />
8+
79
import { EppoClient } from '@eppo/js-client-sdk-common';
810
import { Flag } from '@eppo/js-client-sdk-common';
911
import { IAssignmentEvent } from '@eppo/js-client-sdk-common';
1012
import { IAssignmentLogger } from '@eppo/js-client-sdk-common';
1113
import { IAsyncStore } from '@eppo/js-client-sdk-common';
1214
import { IEppoClient } from '@eppo/js-client-sdk-common';
1315

16+
// @public (undocumented)
17+
export class ChromeStorageAsyncStore<T> implements IAsyncStore<T> {
18+
constructor(storageArea: chrome.storage.StorageArea, cooldownSeconds?: number | undefined);
19+
// (undocumented)
20+
getEntries(): Promise<Record<string, T>>;
21+
// (undocumented)
22+
isExpired(): Promise<boolean>;
23+
// (undocumented)
24+
isInitialized(): boolean;
25+
// (undocumented)
26+
setEntries(entries: Record<string, T>): Promise<void>;
27+
}
28+
1429
// @public
1530
export class EppoJSClient extends EppoClient {
1631
// (undocumented)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eppo/js-client-sdk",
3-
"version": "3.0.2-rc.5",
3+
"version": "3.0.2-rc.6",
44
"description": "Eppo SDK for client-side JavaScript applications",
55
"main": "dist/index.js",
66
"files": [

src/chrome.configuration-store.spec.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@ describe('ChromeStore', () => {
44
const mockEntries: Record<string, string> = { key1: 'value1', key2: 'value2' };
55
let chromeStore: ChromeStorageAsyncStore<string>;
66
let extendedStorageLocal: chrome.storage.StorageArea;
7+
let now: number;
78

89
beforeEach(() => {
10+
now = Date.now();
11+
12+
jest.useFakeTimers();
13+
914
const get = jest.fn();
1015
const set = jest.fn();
1116
extendedStorageLocal = {
@@ -30,20 +35,49 @@ describe('ChromeStore', () => {
3035
});
3136

3237
afterEach(() => {
38+
jest.useRealTimers();
3339
jest.clearAllMocks();
3440
});
3541

36-
it('is always expired', async () => {
42+
it('is always expired without cooldown', async () => {
43+
chromeStore = new ChromeStorageAsyncStore(extendedStorageLocal, undefined);
3744
expect(await chromeStore.isExpired()).toBe(true);
3845
});
3946

40-
it('should return empty object when no entries are found', async () => {
47+
it('is not expired with cooldown', async () => {
48+
chromeStore = new ChromeStorageAsyncStore(extendedStorageLocal, 10);
49+
4150
(extendedStorageLocal.get as jest.Mock).mockImplementation(() => {
42-
return Promise.resolve({});
51+
return Promise.resolve({
52+
['eppo-configuration']: JSON.stringify(mockEntries),
53+
['eppo-configuration-meta']: JSON.stringify({
54+
lastUpdatedAtMs: new Date().getTime(),
55+
}),
56+
});
4357
});
4458

45-
const entries = await chromeStore.getEntries();
46-
expect(entries).toEqual({});
59+
expect(await chromeStore.isExpired()).toBe(false);
60+
});
61+
62+
it('is expired after cooldown', async () => {
63+
chromeStore = new ChromeStorageAsyncStore(extendedStorageLocal, 10);
64+
65+
(extendedStorageLocal.get as jest.Mock).mockImplementation(() => {
66+
return Promise.resolve({
67+
['eppo-configuration']: JSON.stringify(mockEntries),
68+
['eppo-configuration-meta']: JSON.stringify({
69+
lastUpdatedAtMs: now,
70+
}),
71+
});
72+
});
73+
74+
// advance time by 5 seconds
75+
await jest.advanceTimersByTimeAsync(5 * 1000);
76+
expect(await chromeStore.isExpired()).toBe(false);
77+
78+
// advance time by 6 seconds
79+
await jest.advanceTimersByTimeAsync(6 * 1000);
80+
expect(await chromeStore.isExpired()).toBe(true);
4781
});
4882

4983
it('should be initialized after setting entries', async () => {

0 commit comments

Comments
 (0)