Skip to content

Commit 836de23

Browse files
[FME] JS SDKs: update 'Configuration' and 'Subscribe to events' sections related to custom storage (#11628)
* Update 'Configuration' and 'Subscribe to events' sections * Remove item in troubleshooting section for React Native (doesn't apply anymore) * Added IndexedDB example * Update Anchor Links * Clarification * Update docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-suites/browser-suite.md Co-authored-by: Austin Lai <[email protected]> * Update docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-sdks/redux-sdk.md Co-authored-by: Austin Lai <[email protected]> * Update docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-sdks/react-sdk.md Co-authored-by: Austin Lai <[email protected]> * Update docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-sdks/react-native-sdk.md Co-authored-by: Austin Lai <[email protected]> * Update docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-sdks/javascript-sdk.md Co-authored-by: Austin Lai <[email protected]> * Update docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-sdks/browser-sdk.md Co-authored-by: Austin Lai <[email protected]> * Update docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-sdks/react-native-sdk.md Co-authored-by: Austin Lai <[email protected]> --------- Co-authored-by: Austin Lai <[email protected]> Co-authored-by: Austin Lai <[email protected]>
1 parent 842209f commit 836de23

File tree

7 files changed

+231
-73
lines changed

7 files changed

+231
-73
lines changed

docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-sdks/browser-sdk.md

Lines changed: 123 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ npm install --save @splitsoftware/splitio-browserjs
6060
<!-- Choose the preferred script tag, you don't need both -->
6161

6262
<!-- Slim build, smaller footprint -->
63-
<script src="//cdn.split.io/sdk/split-browser-1.2.0.min.js"></script>
63+
<script src="//cdn.split.io/sdk/split-browser-1.4.0.min.js"></script>
6464

6565
<!-- Full build, bigger footprint but all modules are exposed and usable,
6666
including fetch polyfill -->
67-
<script src="//cdn.split.io/sdk/split-browser-1.2.0.full.min.js"></script>
67+
<script src="//cdn.split.io/sdk/split-browser-1.4.0.full.min.js"></script>
6868
```
6969

7070
</TabItem>
@@ -490,10 +490,10 @@ Three types of properties are supported: strings, numbers, and booleans.
490490

491491
```javascript
492492
const evaluationOptions = {
493-
properties: {
494-
package: "premium",
495-
admin: true,
496-
discount: 50
493+
properties: {
494+
package: "premium",
495+
admin: true,
496+
discount: 50
497497
}
498498
};
499499

@@ -505,10 +505,10 @@ const treatment = client.getTreatment('FEATURE_FLAG_NAME', undefined, evaluation
505505

506506
```typescript
507507
const evaluationOptions: SplitIO.EvaluationOptions = {
508-
properties: {
509-
package: "premium",
510-
admin: true,
511-
discount: 50
508+
properties: {
509+
package: "premium",
510+
admin: true,
511+
discount: 50
512512
}
513513
};
514514

@@ -625,7 +625,7 @@ The SDK has a number of knobs for configuring performance. Each knob is tuned to
625625
| sync.impressionsMode | This configuration defines how impressions (decisioning events) are queued on the SDK. Supported modes are OPTIMIZED, NONE, and DEBUG. In OPTIMIZED mode, only unique impressions are queued and posted to Harness; this is the recommended mode for experimentation use cases. In NONE mode, no impression is tracked in Harness FME and only minimum viable data to support usage stats is, so never use this mode if you are experimenting with that instance impressions. Use NONE when you want to optimize for feature flagging only use cases and reduce impressions network and storage load. In DEBUG mode, ALL impressions are queued and sent to Harness; this is useful for validations. This mode doesn't impact the impression listener which receives all generated impressions locally. | `OPTIMIZED` |
626626
| sync.enabled | Controls the SDK continuous synchronization flags. When `true`, a running SDK processes rollout plan updates performed in Harness FME (default). When `false`, it fetches all data upon init, which ensures a consistent experience during a user session and optimizes resources when these updates are not consumed by the app. | true |
627627
| sync.requestOptions.getHeaderOverrides | A callback function that can be used to override the Authentication header or append new headers to the SDK's HTTP(S) requests. | undefined |
628-
| storage | Pluggable storage instance to be used by the SDK as a complement to in memory storage. Only supported option today is `InLocalStorage`. Read more [here](#configuring-localstorage-cache-for-the-sdk). | In memory storage |
628+
| storage | Pluggable storage instance to be used by the SDK as a complement to in memory storage. Only supported option today is `InLocalStorage`. Read more [here](#configuring-cache). | In memory storage |
629629
| debug | Either a boolean flag, string log level or logger instance for activating SDK logs. See [logging](#logging) for details. | false |
630630
| streamingEnabled | Boolean flag to enable the streaming service as default synchronization mechanism. In the event of an issue with streaming, the SDK will fallback to the polling mechanism. If false, the SDK will poll for changes as usual without attempting to use streaming. | true |
631631
| userConsent | User consent status used to control the tracking of events and impressions. Possible values are `GRANTED`, `DECLINED`, and `UNKNOWN`. See [User consent](#user-consent) for details. | `GRANTED` |
@@ -701,7 +701,7 @@ const sdk: SplitIO.IBrowserSDK = SplitFactory({
701701
</TabItem>
702702
</Tabs>
703703

704-
### Configuring LocalStorage cache for the SDK
704+
### Configuring cache
705705

706706
To use the pluggable `InLocalStorage` option of the SDK and be able to cache flags for subsequent loads in the same browser, you need to pass it to the SDK config on its `storage` option.
707707

@@ -712,48 +712,142 @@ This `InLocalStorage` function accepts an optional object with options described
712712
| prefix | An optional prefix for your data, to avoid collisions. This prefix is prepended to the existing "SPLITIO" localStorage prefix. | `SPLITIO` |
713713
| expirationDays | Number of days before cached data expires if it was not updated. If cache expires, it is cleared when the SDK is initialized. | 10 |
714714
| clearOnInit | When set to `true`, the SDK clears the cached data on initialization unless it was cleared within the last 24 hours. This 24-hour window is not configurable. If the cache is cleared (whether due to expiration or `clearOnInit`), both the 24-hour period and the `expirationDays` period are reset. | false |
715+
| wrapper | Storage wrapper used to persist the SDK cached data. | `localStorage` |
715716

716717
These pluggable caches are always available on NPM, but if using the CDN you need the full bundle. Refer to the [Import the SDK into your project](#1-import-the-sdk-into-your-project) section for more information.
717718

718719
<Tabs>
719-
<TabItem value="With full bundle from CDN">
720+
<TabItem value="With NPM package">
720721

721722
```javascript
722-
var factory = window.splitio.SplitFactory({
723+
import { SplitFactory, InLocalStorage } from '@splitsoftware/splitio-browserjs';
724+
725+
const factory: SplitIO.IBrowserSDK = SplitFactory({
723726
core: {
724727
authorizationKey: 'YOUR_SDK_KEY',
725728
key: 'key'
726729
},
727-
// Same as SplitFactory, InLocalStorage is exposed on the global splitio object
728-
storage: window.splitio.InLocalStorage({
730+
storage: InLocalStorage({
729731
prefix: 'MY_PREFIX',
730732
expirationDays: 10,
731-
clearOnInit: false
733+
clearOnInit: false,
734+
wrapper: window.localStorage
732735
})
733736
});
734737

735738
// Now use the SDK as usual
736-
var client = factory.client();
739+
const client = factory.client();
737740
```
738741

739742
</TabItem>
740-
<TabItem value="With NPM package">
743+
<TabItem value="With full bundle from CDN">
741744

742745
```javascript
743-
import { SplitFactory, InLocalStorage } from '@splitsoftware/splitio-browserjs';
744-
745-
const factory: SplitIO.IBrowserSDK = SplitFactory({
746+
var factory = window.splitio.SplitFactory({
746747
core: {
747748
authorizationKey: 'YOUR_SDK_KEY',
748749
key: 'key'
749750
},
750-
storage: InLocalStorage({
751-
prefix: 'MY_PREFIX'
751+
// Same as SplitFactory, InLocalStorage is exposed on the global splitio object
752+
storage: window.splitio.InLocalStorage({
753+
prefix: 'MY_PREFIX',
754+
expirationDays: 10,
755+
clearOnInit: false,
756+
wrapper: window.localStorage
752757
})
753758
});
754759

755760
// Now use the SDK as usual
756-
const client = factory.client();
761+
var client = factory.client();
762+
```
763+
764+
</TabItem>
765+
</Tabs>
766+
767+
By default, the SDK uses the `localStorage` global object if available. If `localStorage` is not available, the SDK will use the default in memory storage. You can pass your own storage wrapper like, for example, one based on `IndexedDB` or another storage solution, by implementing the `SplitIO.StorageWrapper` interface.
768+
769+
<Tabs>
770+
<TabItem value="StorageWrapper interface">
771+
772+
```typescript
773+
declare namespace SplitIO {
774+
interface StorageWrapper {
775+
/**
776+
* Returns the value associated with the given key, or null if the key does not exist.
777+
* If the operation is asynchronous, returns a Promise.
778+
*/
779+
getItem(key: string): string | null | Promise<string | null>;
780+
/**
781+
* Sets the value for the given key, creating a new key/value pair if key does not exist.
782+
* If the operation is asynchronous, returns a Promise.
783+
*/
784+
setItem(key: string, value: string): void | Promise<void>;
785+
/**
786+
* Removes the key/value pair for the given key, if the key exists.
787+
* If the operation is asynchronous, returns a Promise.
788+
*/
789+
removeItem(key: string): void | Promise<void>;
790+
}
791+
...
792+
}
793+
```
794+
795+
</TabItem>
796+
<TabItem value="StorageWrapper implementation based on IndexedDB">
797+
798+
```typescript
799+
class IndexedDBWrapper implements SplitIO.StorageWrapper {
800+
private dbName: string;
801+
private storeName: string;
802+
private dbPromise: Promise<IDBDatabase>;
803+
804+
constructor(dbName: string, storeName: string) {
805+
this.dbName = dbName;
806+
this.storeName = storeName;
807+
this.dbPromise = this.openDB();
808+
}
809+
810+
private openDB(): Promise<IDBDatabase> {
811+
return new Promise((resolve, reject) => {
812+
const request = indexedDB.open(this.dbName);
813+
814+
request.onupgradeneeded = () => {
815+
const db = request.result;
816+
if (!db.objectStoreNames.contains(this.storeName)) {
817+
db.createObjectStore(this.storeName);
818+
}
819+
};
820+
821+
request.onsuccess = () => resolve(request.result);
822+
request.onerror = () => reject(request.error);
823+
});
824+
}
825+
826+
private async withStore(type: IDBTransactionMode, callback: (store: IDBObjectStore) => IDBRequest) {
827+
const db = await this.dbPromise;
828+
return new Promise((resolve, reject) => {
829+
const tx = db.transaction(this.storeName, type);
830+
const store = tx.objectStore(this.storeName);
831+
const request = callback(store);
832+
request.onsuccess = () => resolve(request.result);
833+
request.onerror = () => reject(request.error);
834+
});
835+
}
836+
837+
// Wrapper methods:
838+
839+
async getItem(key: string): Promise<string | null> {
840+
return this.withStore('readonly', store => store.get(key)) as Promise<string | null>;
841+
}
842+
843+
async setItem(key: string, value: string): Promise<void> {
844+
await this.withStore('readwrite', store => store.put(value, key));
845+
}
846+
847+
async removeItem(key: string): Promise<void> {
848+
await this.withStore('readwrite', store => store.delete(key));
849+
}
850+
}
757851
```
758852

759853
</TabItem>
@@ -781,7 +875,7 @@ If you define just a string as the value for a feature flag name, any config ret
781875
<TabItem value="JavaScript" label="JavaScript (using CDN bundle)">
782876

783877
```javascript
784-
<script src="//cdn.split.io/sdk/split-browser-1.2.0.full.min.js"></script>
878+
<script src="//cdn.split.io/sdk/split-browser-1.4.0.full.min.js"></script>
785879

786880
var sdk = splitio.SplitFactory({
787881
core: {
@@ -1247,9 +1341,9 @@ While the SDK does not put any limitations on the number of instances that can b
12471341

12481342
You can listen for four different events from the SDK.
12491343

1250-
* `SDK_READY_FROM_CACHE`. This event fires once the SDK is ready to evaluate treatments using a version of your rollout plan cached in localStorage from a previous session (which might be stale). If there is data in localStorage, this event fires almost immediately, since access to localStorage is fast; otherwise, it doesn't fire.
1344+
* `SDK_READY_FROM_CACHE`. This event fires if you are using the `InLocalStorage` module and the SDK is ready to evaluate treatments using a version of your rollout plan cached from a previous session, which may be stale. By default, the `localStorage` API is used to cache the rollout plan (see [Configuring cache](#configuring-cache) for configuration options). If data is cached, this event fires almost immediately since access to `localStorage` is fast; otherwise, it doesn't fire.
12511345
* `SDK_READY`. This event fires once the SDK is ready to evaluate treatments using the most up-to-date version of your rollout plan, downloaded from Harness servers.
1252-
* `SDK_READY_TIMED_OUT`. This event fires if there is no cached version of your rollout plan cached in localStorage, and the SDK could not download the data from Harness servers within the time specified by the `readyTimeout` configuration parameter. This event does not indicate that the SDK initialization was interrupted. The SDK continues downloading the rollout plan and fires the `SDK_READY` event when finished. This delayed `SDK_READY` event may happen with slow connections or large rollout plans with many feature flags, segments, or dynamic configurations.
1346+
* `SDK_READY_TIMED_OUT`. This event fires if the SDK could not download the data from Harness servers within the time specified by the `readyTimeout` configuration parameter. This event does not indicate that the SDK initialization was interrupted. The SDK continues downloading the rollout plan and fires the `SDK_READY` event when finished. This delayed `SDK_READY` event may happen with slow connections or large rollout plans with many feature flags, segments, or dynamic configurations.
12531347
* `SDK_UPDATE`. This event fires whenever your rollout plan is changed. Listen for this event to refresh your app whenever a feature flag or segment is changed in Harness FME.
12541348

12551349
The syntax to listen for each event is shown below:
@@ -1313,7 +1407,7 @@ client.once(client.Event.SDK_READY, whenReady);
13131407

13141408
client.once(client.Event.SDK_READY_TIMED_OUT, () => {
13151409
// This callback will be called after `readyTimeout` seconds (10 seconds by default)
1316-
// if and only if the client is not ready for that time.
1410+
// if and only if the client is not ready for that time.
13171411
// You can still call `getTreatment()` but it could return `CONTROL`.
13181412
});
13191413

docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-sdks/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ The Split mobile (iOS and Android) and JavaScript Browser SDKs download a local
2121
The default and configuration options differ slightly by SDK:
2222

2323
* JavaScript SDK (v11.2.0 and later): Default expiration of 10 days, configurable via the `LOCALSTORAGE` setting.
24-
* Browser SDK (v1.2.0 and later): Default expiration of 10 days, configurable via the `InLocalStorage` setting. See [Configuring LocalStorage cache for the SDK](/docs/feature-management-experimentation/sdks-and-infrastructure/client-side-sdks/browser-sdk#configuring-localstorage-cache-for-the-sdk).
24+
* Browser SDK (v1.2.0 and later): Default expiration of 10 days, configurable via the `InLocalStorage` setting. See [Configuring persistent cache for the SDK](/docs/feature-management-experimentation/sdks-and-infrastructure/client-side-sdks/browser-sdk#configuring-cache).
2525
* Android SDK (v5.3.0 and later): Default expiration of 10 days, configurable via the `rolloutCacheConfiguration` setting.
2626
* iOS SDK (v3.3.0 and later): Default expiration of 10 days, configurable via the `rolloutCacheConfiguration` setting.
2727

docs/feature-management-experimentation/20-sdks-and-infrastructure/client-side-sdks/javascript-sdk.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ npm install --save @splitsoftware/splitio
5555
<TabItem value="CDN bundle">
5656

5757
```html
58-
<script src="//cdn.split.io/sdk/split-11.4.1.min.js"></script>
58+
<script src="//cdn.split.io/sdk/split-11.6.0.min.js"></script>
5959

6060
```
6161

@@ -629,6 +629,7 @@ The SDK has a number of knobs for configuring performance. Each knob is tuned to
629629
| storage.prefix | Only applies to the `LOCALSTORAGE` storage type. An optional prefix for your data to avoid collisions. This prefix is prepended to the existing "SPLITIO" localStorage prefix. | `SPLITIO` |
630630
| storage.expirationDays | Only applies to the `LOCALSTORAGE` storage type. Number of days before cached data expires if it was not updated. If cache expires, it is cleared when the SDK is initialized. | 10 |
631631
| storage.clearOnInit | Only applies to the `LOCALSTORAGE` storage type. When set to `true`, the SDK clears the cached data on initialization unless it was cleared within the last 24 hours. This 24-hour window is not configurable. If the cache is cleared (whether due to expiration or `clearOnInit`), both the 24-hour period and the `expirationDays` period are reset. | false |
632+
| storage.wrapper | Only applies to the `LOCALSTORAGE` storage type. Storage wrapper used to persist the SDK cached data. | `localStorage` |
632633
| debug | Either a boolean flag or log level string ('ERROR', 'WARN', 'INFO', or 'DEBUG'). See [logging](#logging) for details. | false |
633634
| streamingEnabled | Boolean flag to enable the streaming service as default synchronization mechanism. In the event of an issue with streaming, the SDK falls back to the polling mechanism. If false, the SDK polls for changes as usual without attempting to use streaming. | true |
634635
| userConsent | User consent status used to control the tracking of events and impressions. Possible values are `GRANTED`, `DECLINED`, and `UNKNOWN`. See [User consent](#user-consent) for details. | `GRANTED` |
@@ -670,7 +671,8 @@ var sdk = SplitFactory({
670671
type: 'LOCALSTORAGE',
671672
prefix: 'MYPREFIX',
672673
expirationDays: 10,
673-
clearOnInit: false
674+
clearOnInit: false,
675+
wrapper: window.localStorage
674676
},
675677
streamingEnabled: true,
676678
debug: false
@@ -712,7 +714,8 @@ const sdk: SplitIO.IBrowserSDK = SplitFactory({
712714
type: 'LOCALSTORAGE',
713715
prefix: 'MYPREFIX',
714716
expirationDays: 10,
715-
clearOnInit: false
717+
clearOnInit: false,
718+
wrapper: window.localStorage
716719
},
717720
streamingEnabled: true,
718721
debug: false
@@ -1258,9 +1261,9 @@ While the SDK does not put any limitations on the number of instances that can b
12581261
12591262
You can listen for four different events from the SDK.
12601263
1261-
* `SDK_READY_FROM_CACHE`. This event fires once the SDK is ready to evaluate treatments using a version of your rollout plan cached in localStorage from a previous session (which might be stale). If there is data in localStorage, this event fires almost immediately, since access to localStorage is fast; otherwise, it doesn't fire.
1264+
* `SDK_READY_FROM_CACHE`. This event fires if you are using the `LOCALSTORAGE` storage type and the SDK is ready to evaluate treatments using a version of your rollout plan cached from a previous session, which may be stale. By default, the `localStorage` API is used to cache the rollout plan (see [Configuration](#configuration) for more information). If data is cached, this event fires almost immediately since access to `localStorage` is fast; otherwise, it doesn't fire.
12621265
* `SDK_READY`. This event fires once the SDK is ready to evaluate treatments using the most up-to-date version of your rollout plan, downloaded from Harness servers.
1263-
* `SDK_READY_TIMED_OUT`. This event fires if there is no cached version of your rollout plan cached in localStorage, and the SDK could not download the data from Harness servers within the time specified by the `readyTimeout` configuration parameter. This event does not indicate that the SDK initialization was interrupted. The SDK continues downloading the rollout plan and fires the `SDK_READY` event when finished. This delayed `SDK_READY` event may happen with slow connections or large rollout plans with many feature flags, segments, or dynamic configurations.
1266+
* `SDK_READY_TIMED_OUT`. This event fires if the SDK could not download the data from Harness servers within the time specified by the `readyTimeout` configuration parameter. This event does not indicate that the SDK initialization was interrupted. The SDK continues downloading the rollout plan and fires the `SDK_READY` event when finished. This delayed `SDK_READY` event may happen with slow connections or large rollout plans with many feature flags, segments, or dynamic configurations.
12641267
* `SDK_UPDATE`. This event fires whenever your rollout plan is changed. Listen for this event to refresh your app whenever a feature flag or segment is changed in Harness FME.
12651268
12661269
The syntax to listen for each event is shown below:

0 commit comments

Comments
 (0)