Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.

Commit 4b70e99

Browse files
authored
feat: createClient "storePersistor" option (segmentio#549)
1 parent 4bd3821 commit 4b70e99

File tree

6 files changed

+81
-22
lines changed

6 files changed

+81
-22
lines changed

README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,18 @@ You must pass at least the `writeKey`. Additional configuration options are list
9898

9999
### Client Options
100100

101-
| Name | Default | Description |
102-
| -------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
103-
| `writeKey` **(REQUIRED)** | '' | Your Segment API key. |
104-
| `debug` | true\* | When set to false, it will not generate any logs. |
105-
| `flushAt` | 20 | How many events to accumulate before sending events to the backend. |
106-
| `flushInterval` | 30 | In seconds, how often to send events to the backend. |
107-
| `maxBatchSize` | 1000 | How many events to send to the API at once |
101+
| Name | Default | Description |
102+
| -------------------------- | --------- | -----------------------------------------------------------------------------------------------------------------------------------------------|
103+
| `writeKey` **(REQUIRED)** | '' | Your Segment API key. |
104+
| `debug` | true\* | When set to false, it will not generate any logs. |
105+
| `flushAt` | 20 | How many events to accumulate before sending events to the backend. |
106+
| `flushInterval` | 30 | In seconds, how often to send events to the backend. |
107+
| `maxBatchSize` | 1000 | How many events to send to the API at once |
108108
| `trackAppLifecycleEvents` | false | Enable automatic tracking for [app lifecycle events](https://segment.com/docs/connections/spec/mobile/#lifecycle-events): application installed, opened, updated, backgrounded) |
109109
| `trackDeepLinks` | false | Enable automatic tracking for when the user opens the app via a deep link (Note: Requires additional setup on iOS, [see instructions](#ios-deep-link-tracking-setup)) |
110-
| `defaultSettings` | undefined | Settings that will be used if the request to get the settings from Segment fails |
111-
| `autoAddSegmentDestination`| true | Set to false to skip adding the SegmentDestination plugin |
110+
| `defaultSettings` | undefined | Settings that will be used if the request to get the settings from Segment fails |
111+
| `autoAddSegmentDestination`| true | Set to false to skip adding the SegmentDestination plugin |
112+
| `storePersistor` | undefined | A custom persistor for the store that `analytics-react-native` leverages. Must match `Persistor` interface exported from [sovran-react-native](https://github.com/segmentio/sovran-react-native).|
112113

113114
\* The default value of `debug` will be false in production.
114115

packages/core/src/client.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ export const createClient = (config: Config) => {
1717
}
1818
const clientConfig = { ...defaultConfig, ...config };
1919

20-
const segmentStore = new SovranStorage(config.writeKey);
20+
const segmentStore = new SovranStorage({
21+
storeId: config.writeKey,
22+
storePersistor: config.storePersistor,
23+
});
2124

2225
const client = new SegmentClient({
2326
config: clientConfig,

packages/core/src/storage/__tests__/sovranStorage.test.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Persistor } from '@segment/sovran-react-native';
12
import deepmerge from 'deepmerge';
23
import { createCallbackManager } from '../../__tests__/__helpers__/utils';
34
import { SovranStorage } from '../sovranStorage';
@@ -33,9 +34,8 @@ jest.mock('@segment/sovran-react-native', () => ({
3334
}));
3435

3536
describe('sovranStorage', () => {
36-
it('works', async () => {
37+
async function commonAssertions(sovran: SovranStorage) {
3738
// First test that the constructor works correctly
38-
const sovran = new SovranStorage('test');
3939
expect(sovran.isReady.get()).toBe(false);
4040

4141
// Setup a listener for context changes
@@ -98,5 +98,27 @@ describe('sovranStorage', () => {
9898
const updatedSettings = await sovran.settings.set(settingsUpdate);
9999
expect(updatedSettings).toEqual(settingsUpdate);
100100
expect(sovran.settings.get()).toEqual(settingsUpdate);
101+
}
102+
103+
it('works', async () => {
104+
const sovran = new SovranStorage({ storeId: 'test' });
105+
await commonAssertions(sovran);
106+
});
107+
108+
it('works with custom Persistor', async () => {
109+
const customStorage: any = {};
110+
const CustomPersistor: Persistor = {
111+
get: async <T>(key: string): Promise<T | undefined> => {
112+
return Promise.resolve(customStorage[key] as T);
113+
},
114+
set: async <T>(key: string, state: T): Promise<void> => {
115+
customStorage[key] = state;
116+
},
117+
};
118+
const sovran = new SovranStorage({
119+
storeId: 'custom-persistor',
120+
storePersistor: CustomPersistor,
121+
});
122+
await commonAssertions(sovran);
101123
});
102124
});

packages/core/src/storage/sovranStorage.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
createStore,
33
registerBridgeStore,
44
Store,
5+
Persistor,
56
} from '@segment/sovran-react-native';
67
import deepmerge from 'deepmerge';
78
import type {
@@ -13,7 +14,11 @@ import type {
1314
UserInfoState,
1415
} from '..';
1516
import { getUUID } from '../uuid';
16-
import type { Storage, DeepLinkData } from './types';
17+
import type { Storage, StorageConfig, DeepLinkData } from './types';
18+
19+
// NOTE: Not exported from @segment/sovran-react-native. Must explicitly declare here.
20+
// Also this fallback is used in store.ts in @segment/sovran-react-native yet "storeId" is required.
21+
const DEFAULT_STORE_NAME = 'default';
1722

1823
type Data = {
1924
isReady: boolean;
@@ -73,41 +78,61 @@ registerBridgeStore({
7378

7479
export class SovranStorage implements Storage {
7580
private storeId: string;
81+
private storePersistor?: Persistor;
7682
private readinessStore: Store<ReadinessStore>;
7783
private contextStore: Store<{ context: DeepPartial<Context> }>;
7884
private settingsStore: Store<{ settings: SegmentAPIIntegrations }>;
7985
private eventsStore: Store<{ events: SegmentEvent[] }>;
8086
private userInfoStore: Store<{ userInfo: UserInfoState }>;
8187
private deepLinkStore: Store<DeepLinkData> = deepLinkStore;
8288

83-
constructor(storeId: string) {
84-
this.storeId = storeId;
85-
this.readinessStore = createStore<ReadinessStore>({
86-
hasLoadedContext: false,
87-
});
89+
constructor(config: StorageConfig) {
90+
this.storeId = config.storeId;
91+
this.storePersistor = config.storePersistor;
92+
this.readinessStore = createStore<ReadinessStore>(
93+
{
94+
hasLoadedContext: false,
95+
},
96+
{
97+
persist: {
98+
storeId: DEFAULT_STORE_NAME,
99+
persistor: this.storePersistor,
100+
},
101+
}
102+
);
88103
this.contextStore = createStore(
89104
{ context: INITIAL_VALUES.context },
90105
{
91-
persist: { storeId: `${this.storeId}-context` },
106+
persist: {
107+
storeId: `${this.storeId}-context`,
108+
persistor: this.storePersistor,
109+
},
92110
}
93111
);
94112
this.settingsStore = createStore(
95113
{ settings: INITIAL_VALUES.settings },
96114
{
97-
persist: { storeId: `${this.storeId}-settings` },
115+
persist: {
116+
storeId: `${this.storeId}-settings`,
117+
persistor: this.storePersistor,
118+
},
98119
}
99120
);
100121
this.eventsStore = createStore(
101122
{ events: INITIAL_VALUES.events },
102123
{
103-
persist: { storeId: `${this.storeId}-events` },
124+
persist: {
125+
storeId: `${this.storeId}-events`,
126+
persistor: this.storePersistor,
127+
},
104128
}
105129
);
106130
this.userInfoStore = createStore(
107131
{ userInfo: INITIAL_VALUES.userInfo },
108132
{
109133
persist: {
110134
storeId: `${this.storeId}-userInfo`,
135+
persistor: this.storePersistor,
111136
},
112137
}
113138
);

packages/core/src/storage/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Unsubscribe } from '@segment/sovran-react-native';
1+
import type { Unsubscribe, Persistor } from '@segment/sovran-react-native';
22
import type { SegmentEvent } from '..';
33
import type {
44
Context,
@@ -69,3 +69,8 @@ export interface DeepLinkData {
6969
referring_application: string;
7070
url: string;
7171
}
72+
73+
export type StorageConfig = {
74+
storeId: string;
75+
storePersistor?: Persistor;
76+
};

packages/core/src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { Persistor } from '@segment/sovran-react-native';
2+
13
export type JsonValue =
24
| boolean
35
| number
@@ -123,6 +125,7 @@ export type Config = {
123125
defaultSettings?: SegmentAPISettings;
124126
autoAddSegmentDestination?: boolean;
125127
collectDeviceId?: boolean;
128+
storePersistor?: Persistor;
126129
};
127130

128131
export type ClientMethods = {

0 commit comments

Comments
 (0)