Skip to content

Commit 99402e9

Browse files
authored
Increases specificity of localStorage keys to differentiate events by writeKey (#861)
1 parent 40745ff commit 99402e9

File tree

19 files changed

+355
-123
lines changed

19 files changed

+355
-123
lines changed

.changeset/violet-rockets-tie.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@segment/analytics-next': patch
3+
---
4+
5+
Fixes issue related to how retried events are stored in localStorage to prevent analytics.js from reading events for a different writeKey when that writeKey is used on the same domain as the current analytics.js.

packages/browser-integration-tests/src/fixtures/settings.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ type RemotePlugin = NonNullable<LegacySettings['remotePlugins']>[number]
44

55
export class SettingsBuilder {
66
private settings: Record<string, any>
7-
constructor(baseSettings?: Record<string, any>) {
7+
constructor(writeKey: string, baseSettings?: Record<string, any>) {
88
this.settings = baseSettings || {
99
integrations: {
1010
'Segment.io': {
11-
apiKey: 'writeKey',
11+
apiKey: writeKey,
1212
unbundledIntegrations: [],
1313
addBundledMetadata: true,
1414
maybeBundledConfigIds: {},
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export function extractWriteKeyFromUrl(url: string): string | undefined {
2+
const matches = url.match(
3+
/https:\/\/cdn.segment.com\/v1\/projects\/(.+)\/settings/
4+
)
5+
6+
if (matches) {
7+
return matches[1]
8+
}
9+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
export interface PersistedQueueResult {
2+
key: string
3+
name: string
4+
messageIds: string[]
5+
writeKey?: string
6+
}
7+
8+
export function getPersistedItems(): PersistedQueueResult[] {
9+
const results: PersistedQueueResult[] = []
10+
11+
for (let i = 0; i < window.localStorage.length; i++) {
12+
const key = window.localStorage.key(i)
13+
if (
14+
key &&
15+
key.startsWith('persisted-queue:v1:') &&
16+
key.endsWith(':items')
17+
) {
18+
const value = window.localStorage.getItem(key)
19+
const messageIds = value
20+
? JSON.parse(value).map((i: any) => i.event.messageId)
21+
: []
22+
23+
// Key looks like either:
24+
// new keys - persisted-queue:v1:writeKey:dest-Segment.io:items
25+
// old keys - persisted-queue:v1:dest-Segment.io:items
26+
const components = key.split(':')
27+
let writeKey: string | undefined
28+
let name: string
29+
30+
if (components.length === 5) {
31+
;[, , writeKey, name] = components
32+
} else if (components.length === 4) {
33+
;[, , name] = components
34+
} else {
35+
throw new Error('Unrecognized persisted queue key.')
36+
}
37+
results.push({ key, messageIds, name, writeKey })
38+
}
39+
}
40+
41+
return results
42+
}

packages/browser-integration-tests/src/index.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { test, expect } from '@playwright/test'
22
import { SettingsBuilder } from './fixtures/settings'
33
import { standaloneMock } from './helpers/standalone-mock'
4+
import { extractWriteKeyFromUrl } from './helpers/extract-writekey'
45

56
test.describe('Standalone tests', () => {
67
test.beforeEach(standaloneMock)
@@ -14,13 +15,14 @@ test.describe('Standalone tests', () => {
1415
return route.continue()
1516
}
1617

18+
const writeKey = extractWriteKeyFromUrl(request.url()) || 'writeKey'
1719
return route.fulfill({
1820
status: 200,
1921
headers: {
2022
'Content-Type': 'application/json',
2123
},
2224
body: JSON.stringify(
23-
new SettingsBuilder()
25+
new SettingsBuilder(writeKey)
2426
.addActionDestinationSettings({
2527
name: 'Amplitude (Actions)',
2628
creationName: 'Actions Amplitude',
@@ -74,13 +76,14 @@ test.describe('Standalone tests', () => {
7476
return route.continue()
7577
}
7678

79+
const writeKey = extractWriteKeyFromUrl(request.url()) || 'writeKey'
7780
return route.fulfill({
7881
status: 200,
7982
headers: {
8083
'Content-Type': 'application/json',
8184
},
8285
body: JSON.stringify(
83-
new SettingsBuilder()
86+
new SettingsBuilder(writeKey)
8487
.addActionDestinationSettings({
8588
name: 'Braze Cloud Mode (Actions)',
8689
creationName: 'Braze Cloud Mode (Actions)',

0 commit comments

Comments
 (0)