analytics-client
Advanced tools
Comparing version 0.1.0-roman-url-params-431f6998b0134ff6209577529d1d3737fc8b1bbe to 0.1.0-roman-url-params-4733d273bb81097a71d9254baa29a9d383e8397c
import { Mixpanel } from 'mixpanel-browser'; | ||
export declare class AnalyticsUrlParams { | ||
private mixpanel?; | ||
private readonly cookiesSupported; | ||
private deviceIds; | ||
constructor(mixpanel?: Mixpanel | undefined); | ||
private storeInboundDeviceIds; | ||
private retrieveAndMerge; | ||
private takeFirstId; | ||
static clearCookies(): void; | ||
private setDeviceIds; | ||
clearCookies(): void; | ||
consumeUrlParameters(queryString: string): string | null; | ||
allDeviceIds(): string; | ||
deviceIdQuery(): string; | ||
allDeviceIds(): string[]; | ||
getDeviceIdsQueryString(): string; | ||
} |
{ | ||
"name": "analytics-client", | ||
"version": "0.1.0-roman-url-params-431f6998b0134ff6209577529d1d3737fc8b1bbe", | ||
"version": "0.1.0-roman-url-params-4733d273bb81097a71d9254baa29a9d383e8397c", | ||
"description": "Convenient builders to compose analytics tools", | ||
@@ -28,3 +28,5 @@ "repository": { | ||
"@types/mixpanel-browser": "^2.23.1", | ||
"husky": "^3.0.9", | ||
"jest": "^24.9.0", | ||
"lint-staged": "^9.4.2", | ||
"mixpanel-browser": "^2.29.1", | ||
@@ -36,3 +38,19 @@ "resin-lint": "^3.1.0", | ||
"webpack-cli": "^3.3.9" | ||
}, | ||
"lint-staged": { | ||
"*.ts": [ | ||
"prettier --config ./node_modules/resin-lint/config/.prettierrc --write", | ||
"resin-lint --typescript --no-prettier", | ||
"git add" | ||
], | ||
"test/**/*.ts": [ | ||
"resin-lint --typescript --no-prettier --tests" | ||
] | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged", | ||
"pre-push": "npm run lint" | ||
} | ||
} | ||
} |
Analytics client | ||
================ | ||
Client side analytics tools. | ||
Client part of analytics services used at balena. | ||
@@ -6,0 +6,0 @@ ## Installation |
@@ -1,7 +0,7 @@ | ||
import * as _ from 'lodash'; | ||
import { | ||
getCookie, | ||
hasCookieSupport, | ||
setCookie, | ||
hasCookieSupport, | ||
} from '@analytics/cookie-utils'; | ||
import union from 'lodash/union'; | ||
import { Mixpanel } from 'mixpanel-browser'; | ||
@@ -14,4 +14,2 @@ | ||
const cookiesSupported = hasCookieSupport(); | ||
/** | ||
@@ -22,31 +20,32 @@ * AnalyticsUrlParams helps with handling analytics-related URL parameters | ||
export class AnalyticsUrlParams { | ||
private deviceIds: string | null; | ||
private readonly cookiesSupported = hasCookieSupport(); | ||
private deviceIds: string[]; | ||
constructor(private mixpanel?: Mixpanel) {} | ||
constructor(private mixpanel?: Mixpanel) { | ||
const storedValue = this.cookiesSupported | ||
? getCookie(COOKIES_DEVICE_IDS) | ||
: null; | ||
this.setDeviceIds( | ||
storedValue, | ||
this.mixpanel ? this.mixpanel.get_distinct_id() : null, | ||
); | ||
} | ||
private storeInboundDeviceIds(ids: string, currentDeviceId: string | null) { | ||
const list = ids ? ids.split(deviceIdSeparator) : []; | ||
private setDeviceIds( | ||
inputIdString: string | null, | ||
currentDeviceId: string | null, | ||
) { | ||
const list = inputIdString ? inputIdString.split(deviceIdSeparator) : []; | ||
if (currentDeviceId) { | ||
list.push(currentDeviceId); | ||
} | ||
const res = this.retrieveAndMerge(list); | ||
this.deviceIds = res; | ||
if (cookiesSupported) { | ||
setCookie(COOKIES_DEVICE_IDS, res); | ||
this.deviceIds = union(this.deviceIds, list); | ||
if (this.cookiesSupported) { | ||
setCookie(COOKIES_DEVICE_IDS, this.deviceIds.join(',')); | ||
} | ||
return res; | ||
return list.length > 0 ? list[0] : null; | ||
} | ||
private retrieveAndMerge(input: string[]) { | ||
const storedValue = cookiesSupported ? getCookie(COOKIES_DEVICE_IDS) : null; | ||
const storedList = storedValue ? storedValue.split(deviceIdSeparator) : []; | ||
return _.union(storedList, input).join(','); | ||
} | ||
private takeFirstId(passedId: string) { | ||
return passedId.split(deviceIdSeparator, 1)[0]; | ||
} | ||
static clearCookies() { | ||
if (cookiesSupported) { | ||
clearCookies() { | ||
if (this.cookiesSupported) { | ||
setCookie(COOKIES_DEVICE_IDS, ''); | ||
@@ -68,19 +67,20 @@ } | ||
if (passedDeviceId) { | ||
let originalMpId: string | null = null; | ||
const originalMixpanelId = | ||
this.mixpanel != null ? this.mixpanel.get_distinct_id() : null; | ||
if (this.mixpanel != null) { | ||
originalMpId = this.mixpanel.get_distinct_id(); | ||
const newCurrentDeviceId = this.setDeviceIds( | ||
passedDeviceId, | ||
originalMixpanelId, | ||
); | ||
if (this.mixpanel != null && newCurrentDeviceId) { | ||
// Switch mixpanel ID to using the passed device ID, so we can track events in one timeline branch. | ||
// Previous user activity recorded with another device ID will be merged upon signup, | ||
// since we store the previous ID to pass it to other sites. | ||
const mpId = this.takeFirstId(passedDeviceId); | ||
this.mixpanel.register({ | ||
distinct_id: mpId, | ||
$device_id: mpId, | ||
distinct_id: newCurrentDeviceId, | ||
$device_id: newCurrentDeviceId, | ||
}); | ||
} | ||
this.storeInboundDeviceIds(passedDeviceId, originalMpId); | ||
params.delete(URL_PARAM_DEVICE_ID); | ||
@@ -94,10 +94,6 @@ return params.toString(); | ||
/** | ||
* @return all anonymous device IDs that can be passed to other sites, separated with comma | ||
* @return all anonymous device IDs that can be passed to other sites | ||
*/ | ||
allDeviceIds(): string { | ||
if (this.deviceIds == null) { | ||
const knownIds = this.mixpanel == null ? [] : [ this.mixpanel.get_distinct_id() ]; | ||
this.deviceIds = this.retrieveAndMerge(knownIds); | ||
} | ||
return this.deviceIds!; | ||
allDeviceIds() { | ||
return this.deviceIds; | ||
} | ||
@@ -108,9 +104,9 @@ | ||
*/ | ||
deviceIdQuery(): string { | ||
getDeviceIdsQueryString(): string { | ||
const ids = this.allDeviceIds(); | ||
if (ids === '') { | ||
if (ids.length === 0) { | ||
return ''; | ||
} | ||
return `${URL_PARAM_DEVICE_ID}=${encodeURIComponent(ids)}`; | ||
return `${URL_PARAM_DEVICE_ID}=${encodeURIComponent(ids.join(','))}`; | ||
} | ||
} |
import { Mixpanel } from 'mixpanel-browser'; | ||
import { AnalyticsUrlParams } from '../src/url-params'; | ||
beforeEach(AnalyticsUrlParams.clearCookies); | ||
beforeEach(() => new AnalyticsUrlParams().clearCookies()); | ||
@@ -29,4 +29,6 @@ test('remove device ID from query string', () => { | ||
const urlParams = new AnalyticsUrlParams(); | ||
urlParams.consumeUrlParameters('d_id=' + encodeURIComponent('d1,d2,d3') + '&other=value'); | ||
expect(urlParams.allDeviceIds()).toBe('d1,d2,d3'); | ||
urlParams.consumeUrlParameters( | ||
'd_id=' + encodeURIComponent('d1,d2,d3') + '&other=value', | ||
); | ||
expect(urlParams.allDeviceIds()).toStrictEqual(['d1', 'd2', 'd3']); | ||
}); | ||
@@ -36,6 +38,8 @@ | ||
const urlParams = new AnalyticsUrlParams(); | ||
expect(urlParams.deviceIdQuery()).toBe(''); | ||
expect(urlParams.getDeviceIdsQueryString()).toBe(''); | ||
urlParams.consumeUrlParameters('d_id=d1,d2,d3&other=value'); | ||
expect(urlParams.deviceIdQuery()).toBe('d_id=' + encodeURIComponent('d1,d2,d3')); | ||
expect(urlParams.getDeviceIdsQueryString()).toBe( | ||
'd_id=' + encodeURIComponent('d1,d2,d3'), | ||
); | ||
}); | ||
@@ -107,5 +111,10 @@ | ||
const [urlParams] = mpUrlParameters(); | ||
expect(urlParams.allDeviceIds()).toBe('test_mp_distinct_id'); | ||
expect(urlParams.allDeviceIds()).toStrictEqual(['test_mp_distinct_id']); | ||
urlParams.consumeUrlParameters('d_id=d1,d2,d3&other=value'); | ||
expect(urlParams.allDeviceIds()).toBe('d1,d2,d3,test_mp_distinct_id'); | ||
expect(urlParams.allDeviceIds()).toStrictEqual([ | ||
'test_mp_distinct_id', | ||
'd1', | ||
'd2', | ||
'd3', | ||
]); | ||
}); | ||
@@ -116,9 +125,13 @@ | ||
new AnalyticsUrlParams().consumeUrlParameters('d_id=2'); | ||
expect(new AnalyticsUrlParams().allDeviceIds()).toBe('1,2'); | ||
expect(new AnalyticsUrlParams().allDeviceIds()).toStrictEqual(['1', '2']); | ||
}); | ||
test('encodes URI component', () => { | ||
new AnalyticsUrlParams().consumeUrlParameters('d_id=' + encodeURIComponent('%%$!!')); | ||
expect(new AnalyticsUrlParams().allDeviceIds()).toBe('%%$!!'); | ||
expect(new AnalyticsUrlParams().deviceIdQuery()).toBe('d_id=%25%25%24!!'); | ||
new AnalyticsUrlParams().consumeUrlParameters( | ||
'd_id=' + encodeURIComponent('%%$!!'), | ||
); | ||
expect(new AnalyticsUrlParams().allDeviceIds()).toStrictEqual(['%%$!!']); | ||
expect(new AnalyticsUrlParams().getDeviceIdsQueryString()).toBe( | ||
'd_id=%25%25%24!!', | ||
); | ||
}); |
Sorry, the diff of this file is too big to display
24388
12
312