Skip to content

Commit e16017d

Browse files
authored
RFC - Storage Layer for Plugins V2 💿 (#638)
1 parent 0d70637 commit e16017d

File tree

13 files changed

+477
-145
lines changed

13 files changed

+477
-145
lines changed

.changeset/tall-ligers-admire.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@segment/analytics-next': minor
3+
---
4+
5+
Creating universal storage layer and passing it to plugins

packages/browser/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"size-limit": [
4444
{
4545
"path": "dist/umd/index.js",
46-
"limit": "27.3 KB"
46+
"limit": "28.0 KB"
4747
}
4848
],
4949
"dependencies": {

packages/browser/src/browser/__tests__/integration.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ import * as SegmentPlugin from '../../plugins/segmentio'
1515
import jar from 'js-cookie'
1616
import { PriorityQueue } from '../../lib/priority-queue'
1717
import { getCDN, setGlobalCDNUrl } from '../../lib/parse-cdn'
18+
import { UniversalStorage } from '../../core/user'
1819
import { clearAjsBrowserStorage } from '../../test-helpers/browser-storage'
1920
import { ActionDestination } from '@/plugins/remote-loader'
2021

22+
const storage = {} as UniversalStorage
23+
2124
let fetchCalls: Array<any>[] = []
2225

2326
jest.mock('unfetch', () => {
@@ -879,7 +882,8 @@ describe('retries', () => {
879882
throw new Error('aaay')
880883
},
881884
},
882-
ajs
885+
ajs,
886+
storage
883887
)
884888

885889
// Dispatching an event will push it into the priority queue.
@@ -907,7 +911,8 @@ describe('retries', () => {
907911
ready: () => Promise.resolve(true),
908912
track: (ctx) => ctx,
909913
},
910-
ajs
914+
ajs,
915+
storage
911916
)
912917

913918
// @ts-ignore ignore reassining function

packages/browser/src/core/analytics/index.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,15 @@ import {
2424
} from '../events'
2525
import { Plugin } from '../plugin'
2626
import { EventQueue } from '../queue/event-queue'
27-
import { CookieOptions, Group, ID, User, UserOptions } from '../user'
27+
import {
28+
CookieOptions,
29+
getAvailableStorageOptions,
30+
Group,
31+
ID,
32+
UniversalStorage,
33+
User,
34+
UserOptions,
35+
} from '../user'
2836
import autoBind from '../../lib/bind-all'
2937
import { PersistedPriorityQueue } from '../../lib/priority-queue/persisted'
3038
import type { LegacyDestination } from '../../plugins/ajs-destination'
@@ -102,6 +110,9 @@ export class Analytics
102110
private _group: Group
103111
private eventFactory: EventFactory
104112
private _debug = false
113+
private _universalStorage: UniversalStorage<{
114+
[k: string]: unknown
115+
}>
105116

106117
initialized = false
107118
integrations: Integrations
@@ -122,6 +133,14 @@ export class Analytics
122133
this.settings.timeout = this.settings.timeout ?? 300
123134
this.queue =
124135
queue ?? createDefaultQueue(options?.retryQueue, disablePersistance)
136+
137+
this._universalStorage = new UniversalStorage(
138+
disablePersistance !== false
139+
? ['localStorage', 'cookie', 'memory']
140+
: ['memory'],
141+
getAvailableStorageOptions(cookieOptions)
142+
)
143+
125144
this._user =
126145
user ??
127146
new User(
@@ -304,7 +323,7 @@ export class Analytics
304323
const ctx = Context.system()
305324

306325
const registrations = plugins.map((xt) =>
307-
this.queue.register(ctx, xt, this)
326+
this.queue.register(ctx, xt, this, this._universalStorage)
308327
)
309328
await Promise.all(registrations)
310329

packages/browser/src/core/plugin/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { Analytics } from '../analytics'
22
import { Context } from '../context'
3+
import { UniversalStorage } from '../user'
34

45
interface PluginConfig {
56
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6-
options: any
7-
priority: 'critical' | 'non-critical' // whether AJS should expect this plugin to be loaded before starting event delivery
7+
options?: any
8+
priority?: 'critical' | 'non-critical' // whether AJS should expect this plugin to be loaded before starting event delivery
9+
storage?: UniversalStorage
810
}
911

1012
// enrichment - modifies the event. Enrichment can happen in parallel, by reducing all changes in the final event. Failures in this stage could halt event delivery.

packages/browser/src/core/queue/__tests__/event-queue.test.ts

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import { Plugin } from '../../plugin'
1212
import { EventQueue } from '../event-queue'
1313
import { pTimeout } from '../../callback'
1414
import { ActionDestination } from '../../../plugins/remote-loader'
15+
import { UniversalStorage } from '../../user'
16+
17+
const storage = {} as UniversalStorage
1518

1619
async function flushAll(eq: EventQueue): Promise<Context[]> {
1720
const flushSpy = jest.spyOn(eq, 'flush')
@@ -149,7 +152,8 @@ describe('Flushing', () => {
149152
return Promise.resolve(ctx)
150153
},
151154
},
152-
ajs
155+
ajs,
156+
storage
153157
)
154158

155159
eq.dispatch(fruitBasket)
@@ -219,7 +223,8 @@ describe('Flushing', () => {
219223
return Promise.resolve(ctx)
220224
},
221225
},
222-
ajs
226+
ajs,
227+
storage
223228
)
224229

225230
eq.dispatch(fruitBasket)
@@ -257,7 +262,8 @@ describe('Flushing', () => {
257262
return ctx
258263
},
259264
},
260-
ajs
265+
ajs,
266+
storage
261267
)
262268

263269
const dispatches = [
@@ -294,7 +300,8 @@ describe('Flushing', () => {
294300
return ctx
295301
},
296302
},
297-
ajs
303+
ajs,
304+
storage
298305
)
299306

300307
const context = await eq.dispatchSingle(fruitBasket)
@@ -321,7 +328,8 @@ describe('Flushing', () => {
321328
return Promise.resolve(ctx)
322329
},
323330
},
324-
ajs
331+
ajs,
332+
storage
325333
)
326334

327335
eq.dispatch(fruitBasket)
@@ -362,7 +370,8 @@ describe('Flushing', () => {
362370
return Promise.resolve(ctx)
363371
},
364372
},
365-
ajs
373+
ajs,
374+
storage
366375
)
367376

368377
const fruitBasketDelivery = eq.dispatch(fruitBasket)
@@ -429,9 +438,9 @@ describe('Flushing', () => {
429438

430439
const ctx = new Context(evt)
431440

432-
await eq.register(Context.system(), amplitude, ajs)
433-
await eq.register(Context.system(), mixPanel, ajs)
434-
await eq.register(Context.system(), segmentio, ajs)
441+
await eq.register(Context.system(), amplitude, ajs, storage)
442+
await eq.register(Context.system(), mixPanel, ajs, storage)
443+
await eq.register(Context.system(), segmentio, ajs, storage)
435444

436445
eq.dispatch(ctx)
437446

@@ -462,9 +471,9 @@ describe('Flushing', () => {
462471

463472
const ctx = new Context(evt)
464473

465-
await eq.register(Context.system(), amplitude, ajs)
466-
await eq.register(Context.system(), mixPanel, ajs)
467-
await eq.register(Context.system(), segmentio, ajs)
474+
await eq.register(Context.system(), amplitude, ajs, storage)
475+
await eq.register(Context.system(), mixPanel, ajs, storage)
476+
await eq.register(Context.system(), segmentio, ajs, storage)
468477

469478
eq.dispatch(ctx)
470479

@@ -496,9 +505,9 @@ describe('Flushing', () => {
496505

497506
const ctx = new Context(evt)
498507

499-
await eq.register(Context.system(), amplitude, ajs)
500-
await eq.register(Context.system(), mixPanel, ajs)
501-
await eq.register(Context.system(), segmentio, ajs)
508+
await eq.register(Context.system(), amplitude, ajs, storage)
509+
await eq.register(Context.system(), mixPanel, ajs, storage)
510+
await eq.register(Context.system(), segmentio, ajs, storage)
502511

503512
eq.dispatch(ctx)
504513

@@ -530,9 +539,9 @@ describe('Flushing', () => {
530539

531540
const ctx = new Context(evt)
532541

533-
await eq.register(Context.system(), amplitude, ajs)
534-
await eq.register(Context.system(), mixPanel, ajs)
535-
await eq.register(Context.system(), segmentio, ajs)
542+
await eq.register(Context.system(), amplitude, ajs, storage)
543+
await eq.register(Context.system(), mixPanel, ajs, storage)
544+
await eq.register(Context.system(), segmentio, ajs, storage)
536545

537546
eq.dispatch(ctx)
538547

@@ -563,9 +572,9 @@ describe('Flushing', () => {
563572

564573
const ctx = new Context(evt)
565574

566-
await eq.register(Context.system(), amplitude, ajs)
567-
await eq.register(Context.system(), mixPanel, ajs)
568-
await eq.register(Context.system(), segmentio, ajs)
575+
await eq.register(Context.system(), amplitude, ajs, storage)
576+
await eq.register(Context.system(), mixPanel, ajs, storage)
577+
await eq.register(Context.system(), segmentio, ajs, storage)
569578

570579
eq.dispatch(ctx)
571580

@@ -598,8 +607,8 @@ describe('Flushing', () => {
598607

599608
const ctx = new Context(evt)
600609

601-
await eq.register(Context.system(), amplitude, ajs)
602-
await eq.register(Context.system(), segmentio, ajs)
610+
await eq.register(Context.system(), amplitude, ajs, storage)
611+
await eq.register(Context.system(), segmentio, ajs, storage)
603612

604613
eq.dispatch(ctx)
605614

@@ -632,8 +641,8 @@ describe('Flushing', () => {
632641

633642
const ctx = new Context(evt)
634643

635-
await eq.register(Context.system(), fullstory, ajs)
636-
await eq.register(Context.system(), segmentio, ajs)
644+
await eq.register(Context.system(), fullstory, ajs, storage)
645+
await eq.register(Context.system(), segmentio, ajs, storage)
637646

638647
eq.dispatch(ctx)
639648

@@ -663,9 +672,9 @@ describe('Flushing', () => {
663672
}
664673

665674
const ctx = new Context(evt)
666-
await eq.register(Context.system(), amplitude, ajs)
667-
await eq.register(Context.system(), mixPanel, ajs)
668-
await eq.register(Context.system(), segmentio, ajs)
675+
await eq.register(Context.system(), amplitude, ajs, storage)
676+
await eq.register(Context.system(), mixPanel, ajs, storage)
677+
await eq.register(Context.system(), segmentio, ajs, storage)
669678
await eq.dispatch(ctx)
670679

671680
const skipAmplitudeAndSegment: MiddlewareFunction = ({
@@ -684,7 +693,8 @@ describe('Flushing', () => {
684693
await eq.register(
685694
Context.system(),
686695
sourceMiddlewarePlugin(skipAmplitudeAndSegment, {}),
687-
ajs
696+
ajs,
697+
storage
688698
)
689699

690700
await eq.dispatch(ctx)
@@ -702,7 +712,9 @@ describe('deregister', () => {
702712
const toBeRemoved = { ...testPlugin, name: 'remove-me' }
703713
const plugins = [testPlugin, toBeRemoved]
704714

705-
const promises = plugins.map((p) => eq.register(Context.system(), p, ajs))
715+
const promises = plugins.map((p) =>
716+
eq.register(Context.system(), p, ajs, storage)
717+
)
706718
await Promise.all(promises)
707719

708720
await eq.deregister(Context.system(), toBeRemoved, ajs)
@@ -715,7 +727,9 @@ describe('deregister', () => {
715727
const toBeRemoved = { ...testPlugin, name: 'remove-me', unload: jest.fn() }
716728
const plugins = [testPlugin, toBeRemoved]
717729

718-
const promises = plugins.map((p) => eq.register(Context.system(), p, ajs))
730+
const promises = plugins.map((p) =>
731+
eq.register(Context.system(), p, ajs, storage)
732+
)
719733
await Promise.all(promises)
720734

721735
await eq.deregister(Context.system(), toBeRemoved, ajs)
@@ -778,7 +792,8 @@ describe('dispatchSingle', () => {
778792
return Promise.resolve(ctx)
779793
},
780794
},
781-
ajs
795+
ajs,
796+
storage
782797
)
783798

784799
expect(eq.queue.length).toBe(0)

0 commit comments

Comments
 (0)