@openreplay/tracker 17.0.0 → 17.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/entry.js +1072 -47
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +1070 -47
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/main/app/index.d.ts +1 -0
- package/dist/cjs/main/app/session.d.ts +1 -0
- package/dist/cjs/main/entry.d.ts +5 -4
- package/dist/cjs/main/index.d.ts +17 -5
- package/dist/cjs/main/modules/analytics/batcher.d.ts +46 -0
- package/dist/cjs/main/modules/analytics/constantProperties.d.ts +53 -0
- package/dist/cjs/main/modules/analytics/demo.d.ts +0 -0
- package/dist/cjs/main/modules/analytics/events.d.ts +37 -0
- package/dist/cjs/main/modules/analytics/index.d.ts +73 -0
- package/dist/cjs/main/modules/analytics/people.d.ts +51 -0
- package/dist/cjs/main/modules/analytics/types.d.ts +32 -0
- package/dist/cjs/main/modules/analytics/utils.d.ts +19 -0
- package/dist/lib/entry.js +1071 -48
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +1070 -47
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/main/app/index.d.ts +1 -0
- package/dist/lib/main/app/session.d.ts +1 -0
- package/dist/lib/main/entry.d.ts +5 -4
- package/dist/lib/main/index.d.ts +17 -5
- package/dist/lib/main/modules/analytics/batcher.d.ts +46 -0
- package/dist/lib/main/modules/analytics/constantProperties.d.ts +53 -0
- package/dist/lib/main/modules/analytics/demo.d.ts +0 -0
- package/dist/lib/main/modules/analytics/events.d.ts +37 -0
- package/dist/lib/main/modules/analytics/index.d.ts +73 -0
- package/dist/lib/main/modules/analytics/people.d.ts +51 -0
- package/dist/lib/main/modules/analytics/types.d.ts +32 -0
- package/dist/lib/main/modules/analytics/utils.d.ts +19 -0
- package/dist/types/main/app/index.d.ts +1 -0
- package/dist/types/main/app/session.d.ts +1 -0
- package/dist/types/main/entry.d.ts +5 -4
- package/dist/types/main/index.d.ts +17 -5
- package/dist/types/main/modules/analytics/batcher.d.ts +46 -0
- package/dist/types/main/modules/analytics/constantProperties.d.ts +53 -0
- package/dist/types/main/modules/analytics/demo.d.ts +0 -0
- package/dist/types/main/modules/analytics/events.d.ts +37 -0
- package/dist/types/main/modules/analytics/index.d.ts +73 -0
- package/dist/types/main/modules/analytics/people.d.ts +51 -0
- package/dist/types/main/modules/analytics/types.d.ts +32 -0
- package/dist/types/main/modules/analytics/utils.d.ts +19 -0
- package/package.json +3 -3
package/dist/lib/index.js
CHANGED
|
@@ -3515,8 +3515,7 @@ class Observer {
|
|
|
3515
3515
|
sl.assignedNodes({ flatten: true }).forEach((n) => {
|
|
3516
3516
|
const nid = this.app.nodes.getID(n);
|
|
3517
3517
|
if (nid !== undefined) {
|
|
3518
|
-
this.recents.set(nid, RecentsType.
|
|
3519
|
-
this.commitNode(nid);
|
|
3518
|
+
this.recents.set(nid, RecentsType.Changed);
|
|
3520
3519
|
}
|
|
3521
3520
|
});
|
|
3522
3521
|
});
|
|
@@ -3583,13 +3582,6 @@ class Observer {
|
|
|
3583
3582
|
return true;
|
|
3584
3583
|
}
|
|
3585
3584
|
let slot = node.assignedSlot;
|
|
3586
|
-
let isLightDom = false;
|
|
3587
|
-
if (slot) {
|
|
3588
|
-
// Check if the node is in light DOM (not in shadow DOM)
|
|
3589
|
-
// This is a workaround for the issue with shadow DOM and slots
|
|
3590
|
-
// where the slot is not assigned to the node in shadow DOM.
|
|
3591
|
-
isLightDom = node.getRootNode() instanceof ShadowRoot;
|
|
3592
|
-
}
|
|
3593
3585
|
const parent = node.parentNode;
|
|
3594
3586
|
let parentID;
|
|
3595
3587
|
// Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
|
|
@@ -3602,15 +3594,7 @@ class Observer {
|
|
|
3602
3594
|
this.unbindTree(node);
|
|
3603
3595
|
return false;
|
|
3604
3596
|
}
|
|
3605
|
-
|
|
3606
|
-
parentID = this.app.nodes.getID(slot);
|
|
3607
|
-
// in light dom, we don't "slot" the node,
|
|
3608
|
-
// but rather use the slot as a parent
|
|
3609
|
-
slot = null;
|
|
3610
|
-
}
|
|
3611
|
-
else {
|
|
3612
|
-
parentID = this.app.nodes.getID(parent);
|
|
3613
|
-
}
|
|
3597
|
+
parentID = this.app.nodes.getID(parent);
|
|
3614
3598
|
if (parentID === undefined) {
|
|
3615
3599
|
this.unbindTree(node);
|
|
3616
3600
|
return false;
|
|
@@ -3906,12 +3890,12 @@ function getInlineOptions(mode, logger) {
|
|
|
3906
3890
|
case InlineCssMode.Unset:
|
|
3907
3891
|
const isLocalhost = /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?\/?/.test(window.location.href);
|
|
3908
3892
|
if (isLocalhost) {
|
|
3909
|
-
logger(`Enabling InlineCssMode by default on localhost to preserve css styles, refer to ${localhostStylesDoc} for details, set InlineCssMode to 0 to skip this behavior`);
|
|
3893
|
+
logger(`Enabling InlineCssMode.PlainFetched by default on localhost to preserve css styles, refer to ${localhostStylesDoc} for details, set InlineCssMode to 0 to skip this behavior`);
|
|
3910
3894
|
return {
|
|
3911
3895
|
inlineRemoteCss: true,
|
|
3912
3896
|
inlinerOptions: {
|
|
3913
|
-
forceFetch:
|
|
3914
|
-
forcePlain:
|
|
3897
|
+
forceFetch: true,
|
|
3898
|
+
forcePlain: true,
|
|
3915
3899
|
},
|
|
3916
3900
|
};
|
|
3917
3901
|
}
|
|
@@ -4159,6 +4143,7 @@ class Sanitizer {
|
|
|
4159
4143
|
}
|
|
4160
4144
|
}
|
|
4161
4145
|
|
|
4146
|
+
const tokenSeparator = '_$_';
|
|
4162
4147
|
class Session {
|
|
4163
4148
|
constructor(params) {
|
|
4164
4149
|
this.metadata = {};
|
|
@@ -4186,19 +4171,22 @@ class Session {
|
|
|
4186
4171
|
this.getSessionToken = (projectKey) => {
|
|
4187
4172
|
const tokenWithProject = this.token || this.app.sessionStorage.getItem(this.options.session_token_key);
|
|
4188
4173
|
if (projectKey && tokenWithProject) {
|
|
4189
|
-
const savedProject = tokenWithProject.split(
|
|
4174
|
+
const savedProject = tokenWithProject.split(tokenSeparator)[1];
|
|
4190
4175
|
if (!savedProject || savedProject !== projectKey) {
|
|
4191
4176
|
this.app.sessionStorage.removeItem(this.options.session_token_key);
|
|
4192
4177
|
this.token = undefined;
|
|
4193
4178
|
return undefined;
|
|
4194
4179
|
}
|
|
4195
4180
|
}
|
|
4196
|
-
const token = tokenWithProject ? tokenWithProject.split(
|
|
4181
|
+
const token = tokenWithProject ? tokenWithProject.split(tokenSeparator)[0] : null;
|
|
4197
4182
|
return token || undefined;
|
|
4198
4183
|
};
|
|
4184
|
+
this.getRawTokenWithProject = () => {
|
|
4185
|
+
return this.token || this.app.sessionStorage.getItem(this.options.session_token_key);
|
|
4186
|
+
};
|
|
4199
4187
|
this.setSessionToken = (token, projectKey) => {
|
|
4200
|
-
this.token = `${token}
|
|
4201
|
-
this.app.sessionStorage.setItem(this.options.session_token_key, `${token}
|
|
4188
|
+
this.token = `${token}${tokenSeparator}${projectKey}`;
|
|
4189
|
+
this.app.sessionStorage.setItem(this.options.session_token_key, `${token}${tokenSeparator}${projectKey}`);
|
|
4202
4190
|
};
|
|
4203
4191
|
this.app = params.app;
|
|
4204
4192
|
this.options = params.options;
|
|
@@ -4261,7 +4249,7 @@ class Session {
|
|
|
4261
4249
|
}
|
|
4262
4250
|
getSessionHash() {
|
|
4263
4251
|
const pageNo = this.getPageNumber();
|
|
4264
|
-
const token = this.
|
|
4252
|
+
const token = this.getRawTokenWithProject();
|
|
4265
4253
|
if (pageNo === undefined || token === undefined) {
|
|
4266
4254
|
return;
|
|
4267
4255
|
}
|
|
@@ -4391,6 +4379,9 @@ const proto = {
|
|
|
4391
4379
|
startIframe: 'start tracker inside frame',
|
|
4392
4380
|
// checking updates
|
|
4393
4381
|
polling: 'hello-how-are-you-im-under-the-water-please-help-me',
|
|
4382
|
+
// happens if tab is old and has outdated token but
|
|
4383
|
+
// not communicating with backend to update it (for whatever reason)
|
|
4384
|
+
reset: 'reset-your-session-please',
|
|
4394
4385
|
};
|
|
4395
4386
|
class App {
|
|
4396
4387
|
constructor(projectKey, sessionToken, options, signalError, insideIframe) {
|
|
@@ -4407,7 +4398,7 @@ class App {
|
|
|
4407
4398
|
this.stopCallbacks = [];
|
|
4408
4399
|
this.commitCallbacks = [];
|
|
4409
4400
|
this.activityState = ActivityState.NotActive;
|
|
4410
|
-
this.version = '17.
|
|
4401
|
+
this.version = '17.1.0'; // TODO: version compatability check inside each plugin.
|
|
4411
4402
|
this.socketMode = false;
|
|
4412
4403
|
this.compressionThreshold = 24 * 1000;
|
|
4413
4404
|
this.bc = null;
|
|
@@ -4641,6 +4632,19 @@ class App {
|
|
|
4641
4632
|
}
|
|
4642
4633
|
};
|
|
4643
4634
|
this.startTimeout = null;
|
|
4635
|
+
this.restart = () => {
|
|
4636
|
+
this.stop(false);
|
|
4637
|
+
this.waitStatus(ActivityState.NotActive).then(() => {
|
|
4638
|
+
this.allowAppStart();
|
|
4639
|
+
this.start(this.prevOpts, true)
|
|
4640
|
+
.then((r) => {
|
|
4641
|
+
this.debug.info('Session restart', r);
|
|
4642
|
+
})
|
|
4643
|
+
.catch((e) => {
|
|
4644
|
+
this.debug.error('Session restart failed', e);
|
|
4645
|
+
});
|
|
4646
|
+
});
|
|
4647
|
+
};
|
|
4644
4648
|
this.send = (message, urgent = false) => {
|
|
4645
4649
|
if (this.activityState === ActivityState.NotActive) {
|
|
4646
4650
|
return;
|
|
@@ -4802,7 +4806,12 @@ class App {
|
|
|
4802
4806
|
});
|
|
4803
4807
|
this.session.attachUpdateCallback(({ userID, metadata }) => {
|
|
4804
4808
|
if (userID != null) {
|
|
4805
|
-
|
|
4809
|
+
if (!userID ||
|
|
4810
|
+
typeof userID !== 'string' ||
|
|
4811
|
+
userID.trim().length === 0) {
|
|
4812
|
+
this.debug.warn('Invalid userID (must be type string), ignoring.');
|
|
4813
|
+
return;
|
|
4814
|
+
}
|
|
4806
4815
|
this.send(UserID(userID));
|
|
4807
4816
|
}
|
|
4808
4817
|
if (metadata != null) {
|
|
@@ -4877,6 +4886,12 @@ class App {
|
|
|
4877
4886
|
});
|
|
4878
4887
|
}
|
|
4879
4888
|
}
|
|
4889
|
+
if (ev.data.line === proto.reset) {
|
|
4890
|
+
const newToken = ev.data.token;
|
|
4891
|
+
this.debug.log('Received reset signal from another tab');
|
|
4892
|
+
this.session.setSessionToken(newToken, this.projectKey);
|
|
4893
|
+
this.restart();
|
|
4894
|
+
}
|
|
4880
4895
|
};
|
|
4881
4896
|
}
|
|
4882
4897
|
}
|
|
@@ -5449,9 +5464,10 @@ class App {
|
|
|
5449
5464
|
// Reset session metadata only if requested directly
|
|
5450
5465
|
this.session.reset();
|
|
5451
5466
|
}
|
|
5467
|
+
const userId = startOpts.userID ? startOpts.userID.trim() : undefined;
|
|
5452
5468
|
this.session.assign({
|
|
5453
5469
|
// MBTODO: maybe it would make sense to `forceNew` if the `userID` was changed
|
|
5454
|
-
userID:
|
|
5470
|
+
userID: userId || undefined,
|
|
5455
5471
|
metadata: startOpts.metadata,
|
|
5456
5472
|
});
|
|
5457
5473
|
const timestamp = now();
|
|
@@ -5518,6 +5534,12 @@ class App {
|
|
|
5518
5534
|
}
|
|
5519
5535
|
this.delay = delay;
|
|
5520
5536
|
this.session.setSessionToken(token, this.projectKey);
|
|
5537
|
+
if (sessionToken && sessionToken !== token) {
|
|
5538
|
+
this.bc?.postMessage({
|
|
5539
|
+
type: proto.reset,
|
|
5540
|
+
token: token,
|
|
5541
|
+
});
|
|
5542
|
+
}
|
|
5521
5543
|
this.session.setUserInfo({
|
|
5522
5544
|
userBrowser,
|
|
5523
5545
|
userCity,
|
|
@@ -7408,9 +7430,9 @@ function axiosSpy (app, instance, opts, sanitize, stringify) {
|
|
|
7408
7430
|
});
|
|
7409
7431
|
}
|
|
7410
7432
|
function isAxiosError(payload) {
|
|
7411
|
-
return isObject(payload) && payload.isAxiosError === true;
|
|
7433
|
+
return isObject$1(payload) && payload.isAxiosError === true;
|
|
7412
7434
|
}
|
|
7413
|
-
function isObject(thing) {
|
|
7435
|
+
function isObject$1(thing) {
|
|
7414
7436
|
return thing !== null && typeof thing === 'object';
|
|
7415
7437
|
}
|
|
7416
7438
|
|
|
@@ -8824,6 +8846,969 @@ function webAnimations(app, options = {}) {
|
|
|
8824
8846
|
});
|
|
8825
8847
|
}
|
|
8826
8848
|
|
|
8849
|
+
/**
|
|
8850
|
+
* Detects client browser, OS, and device information
|
|
8851
|
+
*/
|
|
8852
|
+
function uaParse(sWindow) {
|
|
8853
|
+
const unknown = '-';
|
|
8854
|
+
// Screen detection
|
|
8855
|
+
let width = 0;
|
|
8856
|
+
let height = 0;
|
|
8857
|
+
let screenSize = '';
|
|
8858
|
+
if (sWindow.screen.width) {
|
|
8859
|
+
width = sWindow.screen.width;
|
|
8860
|
+
height = sWindow.screen.height;
|
|
8861
|
+
screenSize = `${width} x ${height}`;
|
|
8862
|
+
}
|
|
8863
|
+
// Browser detection
|
|
8864
|
+
const nVer = sWindow.navigator.appVersion ?? '0';
|
|
8865
|
+
const nAgt = sWindow.navigator.userAgent ?? 'unknown';
|
|
8866
|
+
let browser = sWindow.navigator.appName ?? "unknown";
|
|
8867
|
+
let version = String(parseFloat(nVer));
|
|
8868
|
+
let nameOffset;
|
|
8869
|
+
let verOffset;
|
|
8870
|
+
let ix;
|
|
8871
|
+
// Browser detection logic
|
|
8872
|
+
if ((verOffset = nAgt.indexOf('YaBrowser')) !== -1) {
|
|
8873
|
+
browser = 'Yandex';
|
|
8874
|
+
version = nAgt.substring(verOffset + 10);
|
|
8875
|
+
}
|
|
8876
|
+
else if ((verOffset = nAgt.indexOf('SamsungBrowser')) !== -1) {
|
|
8877
|
+
browser = 'Samsung';
|
|
8878
|
+
version = nAgt.substring(verOffset + 15);
|
|
8879
|
+
}
|
|
8880
|
+
else if ((verOffset = nAgt.indexOf('UCBrowser')) !== -1) {
|
|
8881
|
+
browser = 'UC Browser';
|
|
8882
|
+
version = nAgt.substring(verOffset + 10);
|
|
8883
|
+
}
|
|
8884
|
+
else if ((verOffset = nAgt.indexOf('OPR')) !== -1) {
|
|
8885
|
+
browser = 'Opera';
|
|
8886
|
+
version = nAgt.substring(verOffset + 4);
|
|
8887
|
+
}
|
|
8888
|
+
else if ((verOffset = nAgt.indexOf('Opera')) !== -1) {
|
|
8889
|
+
browser = 'Opera';
|
|
8890
|
+
version = nAgt.substring(verOffset + 6);
|
|
8891
|
+
if ((verOffset = nAgt.indexOf('Version')) !== -1) {
|
|
8892
|
+
version = nAgt.substring(verOffset + 8);
|
|
8893
|
+
}
|
|
8894
|
+
}
|
|
8895
|
+
else if ((verOffset = nAgt.indexOf('Edge')) !== -1) {
|
|
8896
|
+
browser = 'Microsoft Legacy Edge';
|
|
8897
|
+
version = nAgt.substring(verOffset + 5);
|
|
8898
|
+
}
|
|
8899
|
+
else if ((verOffset = nAgt.indexOf('Edg')) !== -1) {
|
|
8900
|
+
browser = 'Microsoft Edge';
|
|
8901
|
+
version = nAgt.substring(verOffset + 4);
|
|
8902
|
+
}
|
|
8903
|
+
else if ((verOffset = nAgt.indexOf('MSIE')) !== -1) {
|
|
8904
|
+
browser = 'Microsoft Internet Explorer';
|
|
8905
|
+
version = nAgt.substring(verOffset + 5);
|
|
8906
|
+
}
|
|
8907
|
+
else if ((verOffset = nAgt.indexOf('Chrome')) !== -1) {
|
|
8908
|
+
browser = 'Chrome';
|
|
8909
|
+
version = nAgt.substring(verOffset + 7);
|
|
8910
|
+
}
|
|
8911
|
+
else if ((verOffset = nAgt.indexOf('Safari')) !== -1) {
|
|
8912
|
+
browser = 'Safari';
|
|
8913
|
+
version = nAgt.substring(verOffset + 7);
|
|
8914
|
+
if ((verOffset = nAgt.indexOf('Version')) !== -1) {
|
|
8915
|
+
version = nAgt.substring(verOffset + 8);
|
|
8916
|
+
}
|
|
8917
|
+
}
|
|
8918
|
+
else if ((verOffset = nAgt.indexOf('Firefox')) !== -1) {
|
|
8919
|
+
browser = 'Firefox';
|
|
8920
|
+
version = nAgt.substring(verOffset + 8);
|
|
8921
|
+
}
|
|
8922
|
+
else if (nAgt.indexOf('Trident/') !== -1) {
|
|
8923
|
+
browser = 'Microsoft Internet Explorer';
|
|
8924
|
+
version = nAgt.substring(nAgt.indexOf('rv:') + 3);
|
|
8925
|
+
}
|
|
8926
|
+
else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) {
|
|
8927
|
+
browser = nAgt.substring(nameOffset, verOffset);
|
|
8928
|
+
version = nAgt.substring(verOffset + 1);
|
|
8929
|
+
if (browser.toLowerCase() === browser.toUpperCase()) {
|
|
8930
|
+
browser = sWindow.navigator.appName;
|
|
8931
|
+
}
|
|
8932
|
+
}
|
|
8933
|
+
// Trim the version string
|
|
8934
|
+
if ((ix = version.indexOf(';')) !== -1) {
|
|
8935
|
+
version = version.substring(0, ix);
|
|
8936
|
+
}
|
|
8937
|
+
if ((ix = version.indexOf(' ')) !== -1) {
|
|
8938
|
+
version = version.substring(0, ix);
|
|
8939
|
+
}
|
|
8940
|
+
if ((ix = version.indexOf(')')) !== -1) {
|
|
8941
|
+
version = version.substring(0, ix);
|
|
8942
|
+
}
|
|
8943
|
+
let majorVersion = parseInt(version, 10);
|
|
8944
|
+
if (isNaN(majorVersion)) {
|
|
8945
|
+
version = String(parseFloat(nVer));
|
|
8946
|
+
majorVersion = parseInt(nVer, 10);
|
|
8947
|
+
}
|
|
8948
|
+
// Mobile detection
|
|
8949
|
+
const mobile = /Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(nVer);
|
|
8950
|
+
// Cookie detection
|
|
8951
|
+
let cookieEnabled = sWindow.navigator.cookieEnabled || false;
|
|
8952
|
+
if (typeof navigator.cookieEnabled === 'undefined' && !cookieEnabled) {
|
|
8953
|
+
sWindow.document.cookie = 'testcookie';
|
|
8954
|
+
cookieEnabled = sWindow.document.cookie.indexOf('testcookie') !== -1;
|
|
8955
|
+
}
|
|
8956
|
+
// OS detection
|
|
8957
|
+
let os = unknown;
|
|
8958
|
+
const clientStrings = [
|
|
8959
|
+
{ s: 'Windows 10', r: /(Windows 10.0|Windows NT 10.0)/ },
|
|
8960
|
+
{ s: 'Windows 8.1', r: /(Windows 8.1|Windows NT 6.3)/ },
|
|
8961
|
+
{ s: 'Windows 8', r: /(Windows 8|Windows NT 6.2)/ },
|
|
8962
|
+
{ s: 'Windows 7', r: /(Windows 7|Windows NT 6.1)/ },
|
|
8963
|
+
{ s: 'Windows Vista', r: /Windows NT 6.0/ },
|
|
8964
|
+
{ s: 'Windows Server 2003', r: /Windows NT 5.2/ },
|
|
8965
|
+
{ s: 'Windows XP', r: /(Windows NT 5.1|Windows XP)/ },
|
|
8966
|
+
{ s: 'Windows 2000', r: /(Windows NT 5.0|Windows 2000)/ },
|
|
8967
|
+
{ s: 'Windows ME', r: /(Win 9x 4.90|Windows ME)/ },
|
|
8968
|
+
{ s: 'Windows 98', r: /(Windows 98|Win98)/ },
|
|
8969
|
+
{ s: 'Windows 95', r: /(Windows 95|Win95|Windows_95)/ },
|
|
8970
|
+
{ s: 'Windows NT 4.0', r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/ },
|
|
8971
|
+
{ s: 'Windows CE', r: /Windows CE/ },
|
|
8972
|
+
{ s: 'Windows 3.11', r: /Win16/ },
|
|
8973
|
+
{ s: 'Android', r: /Android/ },
|
|
8974
|
+
{ s: 'Open BSD', r: /OpenBSD/ },
|
|
8975
|
+
{ s: 'Sun OS', r: /SunOS/ },
|
|
8976
|
+
{ s: 'Chrome OS', r: /CrOS/ },
|
|
8977
|
+
{ s: 'Linux', r: /(Linux|X11(?!.*CrOS))/ },
|
|
8978
|
+
{ s: 'iOS', r: /(iPhone|iPad|iPod)/ },
|
|
8979
|
+
{ s: 'Mac OS X', r: /Mac OS X/ },
|
|
8980
|
+
{ s: 'Mac OS', r: /(Mac OS|MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ },
|
|
8981
|
+
{ s: 'QNX', r: /QNX/ },
|
|
8982
|
+
{ s: 'UNIX', r: /UNIX/ },
|
|
8983
|
+
{ s: 'BeOS', r: /BeOS/ },
|
|
8984
|
+
{ s: 'OS/2', r: /OS\/2/ },
|
|
8985
|
+
{
|
|
8986
|
+
s: 'Search Bot',
|
|
8987
|
+
r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/,
|
|
8988
|
+
},
|
|
8989
|
+
];
|
|
8990
|
+
// Find matching OS
|
|
8991
|
+
for (const client of clientStrings) {
|
|
8992
|
+
if (client.r.test(nAgt)) {
|
|
8993
|
+
os = client.s;
|
|
8994
|
+
break;
|
|
8995
|
+
}
|
|
8996
|
+
}
|
|
8997
|
+
// OS Version detection
|
|
8998
|
+
let osVersion = unknown;
|
|
8999
|
+
if (/Windows/.test(os)) {
|
|
9000
|
+
const matches = /Windows (.*)/.exec(os);
|
|
9001
|
+
if (matches && matches[1]) {
|
|
9002
|
+
osVersion = matches[1];
|
|
9003
|
+
// Handle Windows 10/11 detection with newer API if available
|
|
9004
|
+
if (osVersion === '10' && 'userAgentData' in sWindow.navigator) {
|
|
9005
|
+
const nav = navigator;
|
|
9006
|
+
if (nav.userAgentData) {
|
|
9007
|
+
nav.userAgentData
|
|
9008
|
+
.getHighEntropyValues(['platformVersion'])
|
|
9009
|
+
.then((ua) => {
|
|
9010
|
+
const version = parseInt(ua.platformVersion.split('.')[0], 10);
|
|
9011
|
+
osVersion = version < 13 ? '10' : '11';
|
|
9012
|
+
})
|
|
9013
|
+
.catch(() => {
|
|
9014
|
+
// ignore errors and keep osVersion as is
|
|
9015
|
+
});
|
|
9016
|
+
}
|
|
9017
|
+
}
|
|
9018
|
+
}
|
|
9019
|
+
os = 'Windows';
|
|
9020
|
+
}
|
|
9021
|
+
// OS version detection for Mac/Android/iOS
|
|
9022
|
+
switch (os) {
|
|
9023
|
+
case 'Mac OS':
|
|
9024
|
+
case 'Mac OS X':
|
|
9025
|
+
case 'Android': {
|
|
9026
|
+
const matches = /(?:Android|Mac OS|Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh) ([\.\_\d]+)/.exec(nAgt);
|
|
9027
|
+
osVersion = matches && matches[1] ? matches[1] : unknown;
|
|
9028
|
+
break;
|
|
9029
|
+
}
|
|
9030
|
+
case 'iOS': {
|
|
9031
|
+
const matches = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer);
|
|
9032
|
+
if (matches && matches[1]) {
|
|
9033
|
+
osVersion = `${matches[1]}.${matches[2]}.${parseInt(matches[3] || '0', 10)}`;
|
|
9034
|
+
}
|
|
9035
|
+
break;
|
|
9036
|
+
}
|
|
9037
|
+
}
|
|
9038
|
+
// Return client data
|
|
9039
|
+
return {
|
|
9040
|
+
screen: screenSize,
|
|
9041
|
+
width,
|
|
9042
|
+
height,
|
|
9043
|
+
browser,
|
|
9044
|
+
browserVersion: version,
|
|
9045
|
+
browserMajorVersion: majorVersion,
|
|
9046
|
+
mobile,
|
|
9047
|
+
os,
|
|
9048
|
+
osVersion,
|
|
9049
|
+
cookies: cookieEnabled,
|
|
9050
|
+
};
|
|
9051
|
+
}
|
|
9052
|
+
function isObject(item) {
|
|
9053
|
+
const isNull = item === null;
|
|
9054
|
+
return Boolean(item && typeof item === 'object' && !Array.isArray(item) && !isNull);
|
|
9055
|
+
}
|
|
9056
|
+
function getUTCOffsetString() {
|
|
9057
|
+
const date = new Date();
|
|
9058
|
+
const offsetMinutes = date.getTimezoneOffset();
|
|
9059
|
+
const hours = Math.abs(Math.floor(offsetMinutes / 60));
|
|
9060
|
+
const minutes = Math.abs(offsetMinutes % 60);
|
|
9061
|
+
const sign = offsetMinutes <= 0 ? '+' : '-';
|
|
9062
|
+
const hoursStr = hours.toString().padStart(2, '0');
|
|
9063
|
+
const minutesStr = minutes.toString().padStart(2, '0');
|
|
9064
|
+
return `UTC${sign}${hoursStr}:${minutesStr}`;
|
|
9065
|
+
}
|
|
9066
|
+
|
|
9067
|
+
const refKey = '$__or__initial_ref__$';
|
|
9068
|
+
const distinctIdKey = '$__or__distinct_device_id__$';
|
|
9069
|
+
const utmParamsKey = '$__or__utm_params__$';
|
|
9070
|
+
const superPropKey = '$__or__super_properties__$';
|
|
9071
|
+
const userIdKey = '$__or__user_id__$';
|
|
9072
|
+
const win = 'window' in globalThis
|
|
9073
|
+
? window
|
|
9074
|
+
: {
|
|
9075
|
+
navigator: { userAgent: '' },
|
|
9076
|
+
screen: {},
|
|
9077
|
+
document: {
|
|
9078
|
+
cookie: '',
|
|
9079
|
+
},
|
|
9080
|
+
location: { search: '' },
|
|
9081
|
+
};
|
|
9082
|
+
const doc = 'document' in globalThis ? document : { referrer: '' };
|
|
9083
|
+
const searchEngineList = [
|
|
9084
|
+
'google',
|
|
9085
|
+
'bing',
|
|
9086
|
+
'yahoo',
|
|
9087
|
+
'baidu',
|
|
9088
|
+
'yandex',
|
|
9089
|
+
'duckduckgo',
|
|
9090
|
+
'ecosia',
|
|
9091
|
+
'ask',
|
|
9092
|
+
'aol',
|
|
9093
|
+
'wolframalpha',
|
|
9094
|
+
'startpage',
|
|
9095
|
+
'swisscows',
|
|
9096
|
+
'qwant',
|
|
9097
|
+
'lycos',
|
|
9098
|
+
'dogpile',
|
|
9099
|
+
'info',
|
|
9100
|
+
'teoma',
|
|
9101
|
+
'webcrawler',
|
|
9102
|
+
'naver',
|
|
9103
|
+
'seznam',
|
|
9104
|
+
'perplexity',
|
|
9105
|
+
];
|
|
9106
|
+
class ConstantProperties {
|
|
9107
|
+
constructor(localStorage, sessionStorage) {
|
|
9108
|
+
this.localStorage = localStorage;
|
|
9109
|
+
this.sessionStorage = sessionStorage;
|
|
9110
|
+
this.user_id = null;
|
|
9111
|
+
this.setUserId = (user_id) => {
|
|
9112
|
+
this.user_id = user_id;
|
|
9113
|
+
this.sessionStorage.setItem(userIdKey, user_id ?? '');
|
|
9114
|
+
};
|
|
9115
|
+
this.resetUserId = (hard) => {
|
|
9116
|
+
this.user_id = null;
|
|
9117
|
+
if (hard) {
|
|
9118
|
+
this.deviceId = this.getDistinctDeviceId(true);
|
|
9119
|
+
}
|
|
9120
|
+
};
|
|
9121
|
+
this.getDistinctDeviceId = (force) => {
|
|
9122
|
+
const potentialStored = this.localStorage.getItem(distinctIdKey);
|
|
9123
|
+
if (potentialStored && !force) {
|
|
9124
|
+
return potentialStored;
|
|
9125
|
+
}
|
|
9126
|
+
else {
|
|
9127
|
+
const distinctId = `${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`;
|
|
9128
|
+
this.localStorage.setItem(distinctIdKey, distinctId);
|
|
9129
|
+
return distinctId;
|
|
9130
|
+
}
|
|
9131
|
+
};
|
|
9132
|
+
this.getReferrer = () => {
|
|
9133
|
+
const potentialStored = this.sessionStorage.getItem(refKey);
|
|
9134
|
+
if (potentialStored) {
|
|
9135
|
+
return potentialStored;
|
|
9136
|
+
}
|
|
9137
|
+
else {
|
|
9138
|
+
const ref = doc.referrer;
|
|
9139
|
+
this.sessionStorage.setItem(refKey, ref);
|
|
9140
|
+
return ref;
|
|
9141
|
+
}
|
|
9142
|
+
};
|
|
9143
|
+
this.parseUTM = () => {
|
|
9144
|
+
const potentialStored = this.sessionStorage.getItem(utmParamsKey);
|
|
9145
|
+
if (potentialStored) {
|
|
9146
|
+
const obj = JSON.parse(potentialStored);
|
|
9147
|
+
this.utmSource = obj.utm_source;
|
|
9148
|
+
this.utmMedium = obj.utm_medium;
|
|
9149
|
+
this.utmCampaign = obj.utm_campaign;
|
|
9150
|
+
}
|
|
9151
|
+
else {
|
|
9152
|
+
const searchParams = new URLSearchParams(win.location.search);
|
|
9153
|
+
this.utmSource = searchParams.get('utm_source') || null;
|
|
9154
|
+
this.utmMedium = searchParams.get('utm_medium') || null;
|
|
9155
|
+
this.utmCampaign = searchParams.get('utm_campaign') || null;
|
|
9156
|
+
const obj = {
|
|
9157
|
+
utm_source: this.utmSource,
|
|
9158
|
+
utm_medium: this.utmMedium,
|
|
9159
|
+
utm_campaign: this.utmCampaign,
|
|
9160
|
+
};
|
|
9161
|
+
this.sessionStorage.setItem(utmParamsKey, JSON.stringify(obj));
|
|
9162
|
+
}
|
|
9163
|
+
};
|
|
9164
|
+
this.getSearchEngine = (ref) => {
|
|
9165
|
+
for (const searchEngine of searchEngineList) {
|
|
9166
|
+
if (ref.includes(searchEngine)) {
|
|
9167
|
+
return searchEngine;
|
|
9168
|
+
}
|
|
9169
|
+
}
|
|
9170
|
+
return null;
|
|
9171
|
+
};
|
|
9172
|
+
this.getSuperProperties = () => {
|
|
9173
|
+
const potentialStored = this.localStorage.getItem(superPropKey);
|
|
9174
|
+
if (potentialStored) {
|
|
9175
|
+
return JSON.parse(potentialStored);
|
|
9176
|
+
}
|
|
9177
|
+
else {
|
|
9178
|
+
return {};
|
|
9179
|
+
}
|
|
9180
|
+
};
|
|
9181
|
+
this.saveSuperProperties = (props) => {
|
|
9182
|
+
this.localStorage.setItem(superPropKey, JSON.stringify(props));
|
|
9183
|
+
};
|
|
9184
|
+
this.clearSuperProperties = () => {
|
|
9185
|
+
this.localStorage.setItem(superPropKey, JSON.stringify({}));
|
|
9186
|
+
};
|
|
9187
|
+
const { width, height, browser, browserVersion, browserMajorVersion, os, osVersion, mobile } = uaParse(win);
|
|
9188
|
+
const storedUserId = this.sessionStorage.getItem(userIdKey);
|
|
9189
|
+
if (storedUserId) {
|
|
9190
|
+
this.user_id = storedUserId;
|
|
9191
|
+
}
|
|
9192
|
+
this.os = os;
|
|
9193
|
+
this.osVersion = osVersion;
|
|
9194
|
+
this.browser = `${browser}`;
|
|
9195
|
+
this.browserVersion = `${browserVersion} (${browserMajorVersion})`;
|
|
9196
|
+
this.platform = mobile ? 'mobile' : 'desktop';
|
|
9197
|
+
this.screenHeight = height;
|
|
9198
|
+
this.screenWidth = width;
|
|
9199
|
+
this.initialReferrer = this.getReferrer();
|
|
9200
|
+
this.deviceId = this.getDistinctDeviceId();
|
|
9201
|
+
this.searchEngine = this.getSearchEngine(this.initialReferrer);
|
|
9202
|
+
this.parseUTM();
|
|
9203
|
+
}
|
|
9204
|
+
get all() {
|
|
9205
|
+
return {
|
|
9206
|
+
os: this.os,
|
|
9207
|
+
os_version: this.osVersion,
|
|
9208
|
+
browser: this.browser,
|
|
9209
|
+
browser_version: this.browserVersion,
|
|
9210
|
+
platform: this.platform,
|
|
9211
|
+
screen_height: this.screenHeight,
|
|
9212
|
+
screen_width: this.screenWidth,
|
|
9213
|
+
initial_referrer: this.initialReferrer,
|
|
9214
|
+
utm_source: this.utmSource,
|
|
9215
|
+
utm_medium: this.utmMedium,
|
|
9216
|
+
utm_campaign: this.utmCampaign,
|
|
9217
|
+
user_id: this.user_id,
|
|
9218
|
+
distinct_id: this.deviceId,
|
|
9219
|
+
sdk_edition: 'web',
|
|
9220
|
+
sdk_version: '17.1.0',
|
|
9221
|
+
timezone: getUTCOffsetString(),
|
|
9222
|
+
search_engine: this.searchEngine,
|
|
9223
|
+
};
|
|
9224
|
+
}
|
|
9225
|
+
get defaultPropertyKeys() {
|
|
9226
|
+
return Object.keys(this.all);
|
|
9227
|
+
}
|
|
9228
|
+
get distinctId() {
|
|
9229
|
+
return this.deviceId;
|
|
9230
|
+
}
|
|
9231
|
+
}
|
|
9232
|
+
|
|
9233
|
+
const mutationTypes = {
|
|
9234
|
+
identity: 'identity',
|
|
9235
|
+
deleteUser: 'delete_user',
|
|
9236
|
+
setProperty: 'set_property',
|
|
9237
|
+
setPropertyOnce: 'set_property_once',
|
|
9238
|
+
appendProperty: 'append_property',
|
|
9239
|
+
appendUniqueProperty: 'append_unique_property',
|
|
9240
|
+
incrementProperty: 'increment_property',
|
|
9241
|
+
};
|
|
9242
|
+
const categories = {
|
|
9243
|
+
people: 'user_actions',
|
|
9244
|
+
events: 'events',
|
|
9245
|
+
};
|
|
9246
|
+
const createEvent = (category, type, timestamp, payload) => {
|
|
9247
|
+
if (category === categories.people) {
|
|
9248
|
+
return {
|
|
9249
|
+
category,
|
|
9250
|
+
data: {
|
|
9251
|
+
type,
|
|
9252
|
+
user_id: payload.user_id,
|
|
9253
|
+
payload: payload.properties,
|
|
9254
|
+
timestamp,
|
|
9255
|
+
},
|
|
9256
|
+
};
|
|
9257
|
+
}
|
|
9258
|
+
else {
|
|
9259
|
+
if (!payload) {
|
|
9260
|
+
throw new Error('Payload is required for event creation');
|
|
9261
|
+
}
|
|
9262
|
+
return {
|
|
9263
|
+
category,
|
|
9264
|
+
data: {
|
|
9265
|
+
name: payload.name,
|
|
9266
|
+
payload: payload.properties,
|
|
9267
|
+
timestamp,
|
|
9268
|
+
},
|
|
9269
|
+
};
|
|
9270
|
+
}
|
|
9271
|
+
};
|
|
9272
|
+
|
|
9273
|
+
const reservedProps = ['properties', 'token', 'timestamp'];
|
|
9274
|
+
class Events {
|
|
9275
|
+
constructor(constantProperties, getTimestamp, batcher) {
|
|
9276
|
+
this.constantProperties = constantProperties;
|
|
9277
|
+
this.getTimestamp = getTimestamp;
|
|
9278
|
+
this.batcher = batcher;
|
|
9279
|
+
this.ownProperties = {};
|
|
9280
|
+
/**
|
|
9281
|
+
* Add event to batch with option to send it immediately,
|
|
9282
|
+
* properties are optional and will not be saved as super prop
|
|
9283
|
+
* */
|
|
9284
|
+
this.sendEvent = (eventName, properties, options) => {
|
|
9285
|
+
// add properties
|
|
9286
|
+
const eventProps = {};
|
|
9287
|
+
if (properties) {
|
|
9288
|
+
if (!isObject(properties)) {
|
|
9289
|
+
throw new Error('Properties must be an object');
|
|
9290
|
+
}
|
|
9291
|
+
Object.entries(properties).forEach(([key, value]) => {
|
|
9292
|
+
if (!this.constantProperties.defaultPropertyKeys.includes(key)) {
|
|
9293
|
+
eventProps[key] = value;
|
|
9294
|
+
}
|
|
9295
|
+
});
|
|
9296
|
+
}
|
|
9297
|
+
const eventPayload = {
|
|
9298
|
+
name: eventName,
|
|
9299
|
+
properties: { ...this.ownProperties, ...eventProps },
|
|
9300
|
+
};
|
|
9301
|
+
const event = createEvent(categories.events, undefined, this.getTimestamp(), eventPayload);
|
|
9302
|
+
if (options?.send_immediately) {
|
|
9303
|
+
void this.batcher.sendImmediately(event);
|
|
9304
|
+
}
|
|
9305
|
+
else {
|
|
9306
|
+
this.batcher.addEvent(event);
|
|
9307
|
+
}
|
|
9308
|
+
};
|
|
9309
|
+
/**
|
|
9310
|
+
* creates super property for all events
|
|
9311
|
+
* */
|
|
9312
|
+
this.setProperty = (nameOrProperties, value) => {
|
|
9313
|
+
let changed = false;
|
|
9314
|
+
if (isObject(nameOrProperties)) {
|
|
9315
|
+
Object.entries(nameOrProperties).forEach(([key, val]) => {
|
|
9316
|
+
if (!this.constantProperties.defaultPropertyKeys.includes(key)) {
|
|
9317
|
+
this.ownProperties[key] = val;
|
|
9318
|
+
changed = true;
|
|
9319
|
+
}
|
|
9320
|
+
});
|
|
9321
|
+
}
|
|
9322
|
+
if (typeof nameOrProperties === 'string' && value !== undefined) {
|
|
9323
|
+
if (!this.constantProperties.defaultPropertyKeys.includes(nameOrProperties)) {
|
|
9324
|
+
this.ownProperties[nameOrProperties] = value;
|
|
9325
|
+
changed = true;
|
|
9326
|
+
}
|
|
9327
|
+
}
|
|
9328
|
+
if (changed) {
|
|
9329
|
+
this.constantProperties.saveSuperProperties(this.ownProperties);
|
|
9330
|
+
}
|
|
9331
|
+
};
|
|
9332
|
+
/**
|
|
9333
|
+
* set super property only if it doesn't exist yet
|
|
9334
|
+
* */
|
|
9335
|
+
this.setPropertiesOnce = (nameOrProperties, value) => {
|
|
9336
|
+
let changed = false;
|
|
9337
|
+
if (isObject(nameOrProperties)) {
|
|
9338
|
+
Object.entries(nameOrProperties).forEach(([key, val]) => {
|
|
9339
|
+
if (!this.ownProperties[key] && !reservedProps.includes(key)) {
|
|
9340
|
+
this.ownProperties[key] = val;
|
|
9341
|
+
changed = true;
|
|
9342
|
+
}
|
|
9343
|
+
});
|
|
9344
|
+
}
|
|
9345
|
+
if (typeof nameOrProperties === 'string' && value !== undefined) {
|
|
9346
|
+
if (!this.ownProperties[nameOrProperties] && !reservedProps.includes(nameOrProperties)) {
|
|
9347
|
+
this.ownProperties[nameOrProperties] = value;
|
|
9348
|
+
changed = true;
|
|
9349
|
+
}
|
|
9350
|
+
}
|
|
9351
|
+
if (changed) {
|
|
9352
|
+
this.constantProperties.saveSuperProperties(this.ownProperties);
|
|
9353
|
+
}
|
|
9354
|
+
};
|
|
9355
|
+
/**
|
|
9356
|
+
* removes properties from list of super properties
|
|
9357
|
+
* */
|
|
9358
|
+
this.unsetProperties = (properties) => {
|
|
9359
|
+
let changed = false;
|
|
9360
|
+
if (Array.isArray(properties)) {
|
|
9361
|
+
properties.forEach((key) => {
|
|
9362
|
+
if (this.ownProperties[key] && !reservedProps.includes(key)) {
|
|
9363
|
+
delete this.ownProperties[key];
|
|
9364
|
+
changed = true;
|
|
9365
|
+
}
|
|
9366
|
+
});
|
|
9367
|
+
}
|
|
9368
|
+
else if (this.ownProperties[properties] && !reservedProps.includes(properties)) {
|
|
9369
|
+
delete this.ownProperties[properties];
|
|
9370
|
+
changed = true;
|
|
9371
|
+
}
|
|
9372
|
+
if (changed) {
|
|
9373
|
+
this.constantProperties.saveSuperProperties(this.ownProperties);
|
|
9374
|
+
}
|
|
9375
|
+
};
|
|
9376
|
+
/** clears all super properties */
|
|
9377
|
+
this.reset = () => {
|
|
9378
|
+
this.ownProperties = {};
|
|
9379
|
+
this.constantProperties.clearSuperProperties();
|
|
9380
|
+
};
|
|
9381
|
+
/** mixpanel compatibility */
|
|
9382
|
+
this.register = this.setProperty;
|
|
9383
|
+
this.register_once = this.setPropertiesOnce;
|
|
9384
|
+
this.unregister = this.unsetProperties;
|
|
9385
|
+
this.track = this.sendEvent;
|
|
9386
|
+
this.ownProperties = this.constantProperties.getSuperProperties();
|
|
9387
|
+
}
|
|
9388
|
+
}
|
|
9389
|
+
|
|
9390
|
+
class People {
|
|
9391
|
+
constructor(constantProperties, getTimestamp, onId, batcher) {
|
|
9392
|
+
this.constantProperties = constantProperties;
|
|
9393
|
+
this.getTimestamp = getTimestamp;
|
|
9394
|
+
this.onId = onId;
|
|
9395
|
+
this.batcher = batcher;
|
|
9396
|
+
this.ownProperties = {};
|
|
9397
|
+
this.identify = (user_id, options) => {
|
|
9398
|
+
if (!user_id || typeof user_id !== 'string') {
|
|
9399
|
+
throw new Error('OR SDK: user_id (string) is required for .identify()');
|
|
9400
|
+
}
|
|
9401
|
+
// if user exists already, reset properties
|
|
9402
|
+
if (this.constantProperties.user_id && this.constantProperties.user_id !== user_id) {
|
|
9403
|
+
this.reset();
|
|
9404
|
+
}
|
|
9405
|
+
this.constantProperties.setUserId(user_id);
|
|
9406
|
+
if (!options?.fromTracker) {
|
|
9407
|
+
this.onId(user_id);
|
|
9408
|
+
}
|
|
9409
|
+
const identityEvent = createEvent(categories.people, mutationTypes.identity, this.getTimestamp(), { user_id });
|
|
9410
|
+
this.batcher.addEvent(identityEvent);
|
|
9411
|
+
};
|
|
9412
|
+
/** Resets user id and own properties
|
|
9413
|
+
*
|
|
9414
|
+
* !hard reset will destroy persistent device id!
|
|
9415
|
+
* */
|
|
9416
|
+
this.reset = (hard) => {
|
|
9417
|
+
this.constantProperties.resetUserId(hard);
|
|
9418
|
+
this.ownProperties = {};
|
|
9419
|
+
};
|
|
9420
|
+
/**
|
|
9421
|
+
* Will delete user and its data from backend, then reset all local properties
|
|
9422
|
+
*/
|
|
9423
|
+
this.deleteUser = () => {
|
|
9424
|
+
const removedUser = this.constantProperties.user_id;
|
|
9425
|
+
if (!removedUser)
|
|
9426
|
+
return;
|
|
9427
|
+
this.constantProperties.setUserId(null);
|
|
9428
|
+
this.ownProperties = {};
|
|
9429
|
+
const deleteEvent = createEvent(categories.people, mutationTypes.deleteUser, undefined, {
|
|
9430
|
+
user_id: removedUser,
|
|
9431
|
+
});
|
|
9432
|
+
this.batcher.addEvent(deleteEvent);
|
|
9433
|
+
this.reset();
|
|
9434
|
+
};
|
|
9435
|
+
/**
|
|
9436
|
+
* set user properties, overwriting existing ones
|
|
9437
|
+
* */
|
|
9438
|
+
this.setProperties = (propertyOrObj, value) => {
|
|
9439
|
+
if (!propertyOrObj) {
|
|
9440
|
+
throw new Error('OR SDK: no user properties provided to set');
|
|
9441
|
+
}
|
|
9442
|
+
const properties = {};
|
|
9443
|
+
if (typeof propertyOrObj === 'string' && propertyOrObj && value) {
|
|
9444
|
+
properties[propertyOrObj] = value;
|
|
9445
|
+
}
|
|
9446
|
+
else if (isObject(propertyOrObj)) {
|
|
9447
|
+
Object.assign(properties, propertyOrObj);
|
|
9448
|
+
}
|
|
9449
|
+
else {
|
|
9450
|
+
throw new Error('OR SDK: invalid user properties provided to set');
|
|
9451
|
+
}
|
|
9452
|
+
Object.entries(properties).forEach(([key, value]) => {
|
|
9453
|
+
if (!this.constantProperties.defaultPropertyKeys.includes(key)) {
|
|
9454
|
+
this.ownProperties[key] = value;
|
|
9455
|
+
}
|
|
9456
|
+
});
|
|
9457
|
+
const setEvent = createEvent(categories.people, mutationTypes.setProperty, undefined, {
|
|
9458
|
+
user_id: this.user_id,
|
|
9459
|
+
properties,
|
|
9460
|
+
});
|
|
9461
|
+
this.batcher.addEvent(setEvent);
|
|
9462
|
+
};
|
|
9463
|
+
/**
|
|
9464
|
+
* Set property if it doesn't exist yet
|
|
9465
|
+
* */
|
|
9466
|
+
this.setPropertiesOnce = (properties) => {
|
|
9467
|
+
if (!isObject(properties)) {
|
|
9468
|
+
throw new Error('Properties must be an object');
|
|
9469
|
+
}
|
|
9470
|
+
Object.entries(properties).forEach(([key, value]) => {
|
|
9471
|
+
if (!this.constantProperties.defaultPropertyKeys.includes(key) && !this.ownProperties[key]) {
|
|
9472
|
+
this.ownProperties[key] = value;
|
|
9473
|
+
}
|
|
9474
|
+
});
|
|
9475
|
+
const setEvent = createEvent(categories.people, mutationTypes.setPropertyOnce, undefined, {
|
|
9476
|
+
user_id: this.user_id,
|
|
9477
|
+
properties,
|
|
9478
|
+
});
|
|
9479
|
+
this.batcher.addEvent(setEvent);
|
|
9480
|
+
};
|
|
9481
|
+
/**
|
|
9482
|
+
* Add value to property (will turn string prop into array)
|
|
9483
|
+
* */
|
|
9484
|
+
this.appendValues = (key, value) => {
|
|
9485
|
+
if (!this.constantProperties.defaultPropertyKeys.includes(key) && this.ownProperties[key]) {
|
|
9486
|
+
if (Array.isArray(this.ownProperties[key])) {
|
|
9487
|
+
this.ownProperties[key].push(value);
|
|
9488
|
+
}
|
|
9489
|
+
else {
|
|
9490
|
+
this.ownProperties[key] = [this.ownProperties[key], value];
|
|
9491
|
+
}
|
|
9492
|
+
}
|
|
9493
|
+
const appendEvent = createEvent(categories.people, mutationTypes.appendProperty, undefined, {
|
|
9494
|
+
properties: { [key]: value },
|
|
9495
|
+
user_id: this.user_id,
|
|
9496
|
+
});
|
|
9497
|
+
this.batcher.addEvent(appendEvent);
|
|
9498
|
+
};
|
|
9499
|
+
/**
|
|
9500
|
+
* Add unique values to property (will turn string prop into array)
|
|
9501
|
+
* */
|
|
9502
|
+
this.appendUniqueValues = (key, value) => {
|
|
9503
|
+
if (!this.ownProperties[key])
|
|
9504
|
+
return;
|
|
9505
|
+
if (Array.isArray(this.ownProperties[key])) {
|
|
9506
|
+
if (!this.ownProperties[key].includes(value)) {
|
|
9507
|
+
this.appendValues(key, value);
|
|
9508
|
+
}
|
|
9509
|
+
}
|
|
9510
|
+
else if (this.ownProperties[key] !== value) {
|
|
9511
|
+
this.appendValues(key, value);
|
|
9512
|
+
}
|
|
9513
|
+
const unionEvent = createEvent(categories.people, mutationTypes.appendUniqueProperty, undefined, {
|
|
9514
|
+
properties: { [key]: value },
|
|
9515
|
+
user_id: this.user_id,
|
|
9516
|
+
});
|
|
9517
|
+
this.batcher.addEvent(unionEvent);
|
|
9518
|
+
};
|
|
9519
|
+
/**
|
|
9520
|
+
* Adds value (incl. negative) to existing numerical property
|
|
9521
|
+
* */
|
|
9522
|
+
this.increment = (key, value) => {
|
|
9523
|
+
if (!this.ownProperties[key]) {
|
|
9524
|
+
this.ownProperties[key] = 0;
|
|
9525
|
+
}
|
|
9526
|
+
if (this.ownProperties[key] && typeof this.ownProperties[key] !== 'number') {
|
|
9527
|
+
throw new Error('OR SDK: Property must be a number to increment');
|
|
9528
|
+
}
|
|
9529
|
+
// @ts-ignore
|
|
9530
|
+
this.ownProperties[key] += value;
|
|
9531
|
+
const incrementEvent = createEvent(categories.people, mutationTypes.incrementProperty, undefined, {
|
|
9532
|
+
user_id: this.user_id,
|
|
9533
|
+
properties: { [key]: value },
|
|
9534
|
+
});
|
|
9535
|
+
this.batcher.addEvent(incrementEvent);
|
|
9536
|
+
};
|
|
9537
|
+
/** mixpanel compatibility */
|
|
9538
|
+
this.union = this.appendUniqueValues;
|
|
9539
|
+
this.set = this.setProperties;
|
|
9540
|
+
this.set_once = this.setPropertiesOnce;
|
|
9541
|
+
this.append = this.appendValues;
|
|
9542
|
+
this.incrementBy = this.increment;
|
|
9543
|
+
}
|
|
9544
|
+
get user_id() {
|
|
9545
|
+
return this.constantProperties.user_id;
|
|
9546
|
+
}
|
|
9547
|
+
}
|
|
9548
|
+
|
|
9549
|
+
/**
|
|
9550
|
+
* Creates batches of events, then sends them at intervals.
|
|
9551
|
+
*/
|
|
9552
|
+
class Batcher {
|
|
9553
|
+
constructor(backendUrl, getToken, init) {
|
|
9554
|
+
this.backendUrl = backendUrl;
|
|
9555
|
+
this.getToken = getToken;
|
|
9556
|
+
this.init = init;
|
|
9557
|
+
this.autosendInterval = 5 * 1000;
|
|
9558
|
+
this.retryTimeout = 3 * 1000;
|
|
9559
|
+
this.retryLimit = 3;
|
|
9560
|
+
this.apiEdp = '/v1/sdk/i';
|
|
9561
|
+
this.batch = {
|
|
9562
|
+
[categories.people]: [],
|
|
9563
|
+
[categories.events]: [],
|
|
9564
|
+
};
|
|
9565
|
+
this.intervalId = null;
|
|
9566
|
+
}
|
|
9567
|
+
getBatches() {
|
|
9568
|
+
this.batch[categories.people] = this.dedupePeopleEvents();
|
|
9569
|
+
const finalData = { data: this.batch };
|
|
9570
|
+
return finalData;
|
|
9571
|
+
}
|
|
9572
|
+
addEvent(event) {
|
|
9573
|
+
this.batch[event.category].push(event.data);
|
|
9574
|
+
}
|
|
9575
|
+
sendImmediately(event) {
|
|
9576
|
+
this.sendBatch({ [event.category]: [event.data] });
|
|
9577
|
+
}
|
|
9578
|
+
/**
|
|
9579
|
+
*
|
|
9580
|
+
* Essentially we're dividing the batch by identify events and squash all same category events into one in each part,
|
|
9581
|
+
* taking priority to the last one
|
|
9582
|
+
*/
|
|
9583
|
+
dedupePeopleEvents() {
|
|
9584
|
+
const peopleEvents = this.batch[categories.people];
|
|
9585
|
+
const finalEvents = [];
|
|
9586
|
+
const currentPart = [];
|
|
9587
|
+
for (let event of peopleEvents) {
|
|
9588
|
+
if (event.type === 'identity') {
|
|
9589
|
+
if (currentPart.length > 0) {
|
|
9590
|
+
finalEvents.push(...this.squashPeopleEvents(currentPart), event);
|
|
9591
|
+
currentPart.length = 0;
|
|
9592
|
+
}
|
|
9593
|
+
else {
|
|
9594
|
+
finalEvents.push(event);
|
|
9595
|
+
}
|
|
9596
|
+
}
|
|
9597
|
+
else {
|
|
9598
|
+
currentPart.push(event);
|
|
9599
|
+
}
|
|
9600
|
+
}
|
|
9601
|
+
if (currentPart.length > 0) {
|
|
9602
|
+
finalEvents.push(...this.squashPeopleEvents(currentPart));
|
|
9603
|
+
}
|
|
9604
|
+
return finalEvents;
|
|
9605
|
+
}
|
|
9606
|
+
squashPeopleEvents(events) {
|
|
9607
|
+
if (!events || events.length === 0) {
|
|
9608
|
+
return [];
|
|
9609
|
+
}
|
|
9610
|
+
const uniqueEventsByType = new Map();
|
|
9611
|
+
for (let event of events) {
|
|
9612
|
+
const prev = uniqueEventsByType.get(event.type);
|
|
9613
|
+
if (prev) {
|
|
9614
|
+
if (event.type === 'increment_property') {
|
|
9615
|
+
const previousValues = Object.entries(prev.payload);
|
|
9616
|
+
const currentValues = Object.entries(event.payload);
|
|
9617
|
+
const uniqueKeys = new Set([...previousValues.map(([key]) => key), ...currentValues.map(([key]) => key)]);
|
|
9618
|
+
const mergedPayload = {};
|
|
9619
|
+
uniqueKeys.forEach((key) => {
|
|
9620
|
+
const prevValue = typeof prev.payload[key] === 'number' ? prev.payload[key] : 0;
|
|
9621
|
+
const currValue = typeof event.payload[key] === 'number' ? event.payload[key] : 0;
|
|
9622
|
+
mergedPayload[key] = prevValue + currValue;
|
|
9623
|
+
});
|
|
9624
|
+
uniqueEventsByType.set(event.type, {
|
|
9625
|
+
type: event.type,
|
|
9626
|
+
timestamp: event.timestamp,
|
|
9627
|
+
payload: mergedPayload,
|
|
9628
|
+
});
|
|
9629
|
+
continue;
|
|
9630
|
+
}
|
|
9631
|
+
// merge payloads, taking priority to the latest one
|
|
9632
|
+
uniqueEventsByType.set(event.type, {
|
|
9633
|
+
type: event.type,
|
|
9634
|
+
timestamp: event.timestamp,
|
|
9635
|
+
payload: { ...(prev.payload ?? {}), ...(event.payload ?? {}) },
|
|
9636
|
+
});
|
|
9637
|
+
}
|
|
9638
|
+
else {
|
|
9639
|
+
uniqueEventsByType.set(event.type, event);
|
|
9640
|
+
}
|
|
9641
|
+
}
|
|
9642
|
+
return Array.from(uniqueEventsByType.values());
|
|
9643
|
+
}
|
|
9644
|
+
sendBatch(batch) {
|
|
9645
|
+
const sentBatch = batch;
|
|
9646
|
+
let attempts = 0;
|
|
9647
|
+
const send = () => {
|
|
9648
|
+
const token = this.getToken();
|
|
9649
|
+
if (!token) {
|
|
9650
|
+
return;
|
|
9651
|
+
}
|
|
9652
|
+
attempts++;
|
|
9653
|
+
return fetch(`${this.backendUrl}${this.apiEdp}`, {
|
|
9654
|
+
method: 'POST',
|
|
9655
|
+
headers: {
|
|
9656
|
+
'Content-Type': 'application/json',
|
|
9657
|
+
Authorization: `Bearer ${token}`,
|
|
9658
|
+
},
|
|
9659
|
+
body: JSON.stringify(sentBatch),
|
|
9660
|
+
})
|
|
9661
|
+
.then((response) => {
|
|
9662
|
+
if (response.status === 403) {
|
|
9663
|
+
this.init().then(() => {
|
|
9664
|
+
send();
|
|
9665
|
+
});
|
|
9666
|
+
}
|
|
9667
|
+
if (!response.ok) {
|
|
9668
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
9669
|
+
}
|
|
9670
|
+
})
|
|
9671
|
+
.catch(() => {
|
|
9672
|
+
if (attempts < this.retryLimit) {
|
|
9673
|
+
setTimeout(() => void send(), this.retryTimeout);
|
|
9674
|
+
}
|
|
9675
|
+
});
|
|
9676
|
+
};
|
|
9677
|
+
void send();
|
|
9678
|
+
}
|
|
9679
|
+
startAutosend() {
|
|
9680
|
+
this.intervalId = setInterval(() => {
|
|
9681
|
+
this.flush();
|
|
9682
|
+
}, this.autosendInterval);
|
|
9683
|
+
}
|
|
9684
|
+
flush() {
|
|
9685
|
+
const categories = Object.keys(this.batch);
|
|
9686
|
+
const isEmpty = categories.every((category) => this.batch[category].length === 0);
|
|
9687
|
+
if (isEmpty) {
|
|
9688
|
+
return;
|
|
9689
|
+
}
|
|
9690
|
+
this.sendBatch(this.getBatches());
|
|
9691
|
+
categories.forEach((key) => {
|
|
9692
|
+
this.batch[key] = [];
|
|
9693
|
+
});
|
|
9694
|
+
}
|
|
9695
|
+
stop() {
|
|
9696
|
+
this.flush();
|
|
9697
|
+
if (this.intervalId) {
|
|
9698
|
+
clearInterval(this.intervalId);
|
|
9699
|
+
this.intervalId = null;
|
|
9700
|
+
}
|
|
9701
|
+
}
|
|
9702
|
+
}
|
|
9703
|
+
|
|
9704
|
+
const STORAGEKEY = '__or_sdk_analytics_token';
|
|
9705
|
+
class Analytics {
|
|
9706
|
+
/**
|
|
9707
|
+
* @param localStorage Class or Object that implements Storage-like interface that stores
|
|
9708
|
+
* values persistently like window.localStorage or any other file-based storage
|
|
9709
|
+
*
|
|
9710
|
+
* @param sessionStorage Class or Object that implements Storage-like interface that stores values
|
|
9711
|
+
* on per-session basis like window.sessionStorage or any other in-memory storage
|
|
9712
|
+
*
|
|
9713
|
+
* @param getToken Function that returns token to bind events to a session
|
|
9714
|
+
*
|
|
9715
|
+
* @param getTimestamp returns current timestamp
|
|
9716
|
+
*
|
|
9717
|
+
* @param setUserId callback for people.identify
|
|
9718
|
+
*
|
|
9719
|
+
* @param standalone if true, analytics will manage its own token (instead of using with openreplay tracker session)
|
|
9720
|
+
* */
|
|
9721
|
+
constructor(options) {
|
|
9722
|
+
this.token = null;
|
|
9723
|
+
this.standalone = false;
|
|
9724
|
+
this._getToken = () => {
|
|
9725
|
+
if (this.standalone) {
|
|
9726
|
+
return this.token;
|
|
9727
|
+
}
|
|
9728
|
+
return this.getToken();
|
|
9729
|
+
};
|
|
9730
|
+
this._getTimestamp = () => {
|
|
9731
|
+
if (this.standalone) {
|
|
9732
|
+
return Date.now();
|
|
9733
|
+
}
|
|
9734
|
+
return this.getTimestamp();
|
|
9735
|
+
};
|
|
9736
|
+
this.init = async () => {
|
|
9737
|
+
if (!this.standalone) {
|
|
9738
|
+
this.batcher.startAutosend();
|
|
9739
|
+
return;
|
|
9740
|
+
}
|
|
9741
|
+
else {
|
|
9742
|
+
const defaultFields = this.constantProperties.all;
|
|
9743
|
+
const apiEdp = '/v1/sdk/start';
|
|
9744
|
+
const data = {
|
|
9745
|
+
projectKey: this.projectKey,
|
|
9746
|
+
defaultFields,
|
|
9747
|
+
};
|
|
9748
|
+
const resp = await fetch(apiEdp, {
|
|
9749
|
+
method: 'POST',
|
|
9750
|
+
body: JSON.stringify(data),
|
|
9751
|
+
});
|
|
9752
|
+
if (!resp.ok) {
|
|
9753
|
+
throw new Error(`HTTP error! status: ${resp.status}`);
|
|
9754
|
+
}
|
|
9755
|
+
const result = await resp.json();
|
|
9756
|
+
if (result.token) {
|
|
9757
|
+
this.token = result.token;
|
|
9758
|
+
this.sessionStorage.setItem(STORAGEKEY, result.token);
|
|
9759
|
+
}
|
|
9760
|
+
else {
|
|
9761
|
+
throw new Error('No token received from server');
|
|
9762
|
+
}
|
|
9763
|
+
}
|
|
9764
|
+
};
|
|
9765
|
+
this.reset = () => {
|
|
9766
|
+
this.people.reset(true);
|
|
9767
|
+
this.events.reset();
|
|
9768
|
+
this.batcher.stop();
|
|
9769
|
+
if (this.standalone) {
|
|
9770
|
+
this.token = null;
|
|
9771
|
+
this.sessionStorage.setItem(STORAGEKEY, '');
|
|
9772
|
+
}
|
|
9773
|
+
};
|
|
9774
|
+
/**
|
|
9775
|
+
* COMPATIBILITY LAYER
|
|
9776
|
+
* */
|
|
9777
|
+
/**
|
|
9778
|
+
* Identify a user with an id (e.g. email, username, etc.)
|
|
9779
|
+
* will bind all events and properties (including device_id) to this user
|
|
9780
|
+
*
|
|
9781
|
+
* you will need to manually call people.reset() to clear the id on logout event
|
|
9782
|
+
* */
|
|
9783
|
+
this.identify = (user_id) => {
|
|
9784
|
+
return this.people.identify(user_id);
|
|
9785
|
+
};
|
|
9786
|
+
/**
|
|
9787
|
+
* Add event to batch with option to send it immediately,
|
|
9788
|
+
* properties are optional and will not be saved as super prop
|
|
9789
|
+
* */
|
|
9790
|
+
this.track = (eventName, properties, options) => {
|
|
9791
|
+
return this.events.track(eventName, properties, options);
|
|
9792
|
+
};
|
|
9793
|
+
this.sessionStorage = options.sessionStorage || sessionStorage;
|
|
9794
|
+
this.localStorage = options.localStorage || localStorage;
|
|
9795
|
+
this.backendUrl = options.ingestPoint;
|
|
9796
|
+
this.projectKey = options.projectKey;
|
|
9797
|
+
this.getToken = options.getToken || (() => '');
|
|
9798
|
+
this.getTimestamp = options.getTimestamp || (() => Date.now());
|
|
9799
|
+
this.setUserId = options.setUserId || (() => { });
|
|
9800
|
+
this.standalone = !options.notStandalone;
|
|
9801
|
+
this.token = this.sessionStorage.getItem(STORAGEKEY);
|
|
9802
|
+
this.constantProperties = new ConstantProperties(this.localStorage, this.sessionStorage);
|
|
9803
|
+
this.batcher = new Batcher(this.backendUrl, this._getToken, this.init);
|
|
9804
|
+
this.events = new Events(this.constantProperties, this._getTimestamp, this.batcher);
|
|
9805
|
+
this.people = new People(this.constantProperties, this._getTimestamp, this.setUserId, this.batcher);
|
|
9806
|
+
if (options.notStandalone) {
|
|
9807
|
+
this.init();
|
|
9808
|
+
}
|
|
9809
|
+
}
|
|
9810
|
+
}
|
|
9811
|
+
|
|
8827
9812
|
const Messages = _Messages;
|
|
8828
9813
|
const DOCS_SETUP = '/en/sdk';
|
|
8829
9814
|
function processOptions(obj) {
|
|
@@ -8865,6 +9850,7 @@ class API {
|
|
|
8865
9850
|
constructor(options) {
|
|
8866
9851
|
this.options = options;
|
|
8867
9852
|
this.app = null;
|
|
9853
|
+
this.analytics = null;
|
|
8868
9854
|
this.crossdomainMode = false;
|
|
8869
9855
|
this.checkDoNotTrack = () => {
|
|
8870
9856
|
return (this.options.respectDoNotTrack &&
|
|
@@ -8875,7 +9861,7 @@ class API {
|
|
|
8875
9861
|
this.signalStartIssue = (reason, missingApi) => {
|
|
8876
9862
|
const doNotTrack = this.checkDoNotTrack();
|
|
8877
9863
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
8878
|
-
trackerVersion: '17.
|
|
9864
|
+
trackerVersion: '17.1.0',
|
|
8879
9865
|
projectKey: this.options.projectKey,
|
|
8880
9866
|
doNotTrack,
|
|
8881
9867
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -8887,6 +9873,22 @@ class API {
|
|
|
8887
9873
|
}
|
|
8888
9874
|
this.app.restartCanvasTracking();
|
|
8889
9875
|
};
|
|
9876
|
+
this.getSessionURL = (options) => {
|
|
9877
|
+
if (this.app === null) {
|
|
9878
|
+
return undefined;
|
|
9879
|
+
}
|
|
9880
|
+
return this.app.getSessionURL(options);
|
|
9881
|
+
};
|
|
9882
|
+
this.setUserID = (id) => {
|
|
9883
|
+
if (typeof id === 'string' && this.app !== null) {
|
|
9884
|
+
this.app.session.setUserID(id);
|
|
9885
|
+
this.analytics?.people.identify(id, { fromTracker: true });
|
|
9886
|
+
}
|
|
9887
|
+
};
|
|
9888
|
+
this.userID = (id) => {
|
|
9889
|
+
deprecationWarn("'userID' method", "'setUserID' method", '/');
|
|
9890
|
+
this.setUserID(id);
|
|
9891
|
+
};
|
|
8890
9892
|
this.handleError = (e, metadata = {}) => {
|
|
8891
9893
|
if (this.app === null) {
|
|
8892
9894
|
return;
|
|
@@ -8909,6 +9911,21 @@ class API {
|
|
|
8909
9911
|
}
|
|
8910
9912
|
this.app.send(Incident(options.label ?? '', options.startTime, options.endTime ?? options.startTime));
|
|
8911
9913
|
};
|
|
9914
|
+
this.analyticsToken = null;
|
|
9915
|
+
/**
|
|
9916
|
+
* Use custom token for analytics events without session recording
|
|
9917
|
+
* */
|
|
9918
|
+
this.setAnalyticsToken = (token) => {
|
|
9919
|
+
this.analyticsToken = token;
|
|
9920
|
+
};
|
|
9921
|
+
this.getAnalyticsToken = () => {
|
|
9922
|
+
if (this.analyticsToken) {
|
|
9923
|
+
return this.analyticsToken;
|
|
9924
|
+
}
|
|
9925
|
+
else {
|
|
9926
|
+
return this.app?.session.getSessionToken() ?? '';
|
|
9927
|
+
}
|
|
9928
|
+
};
|
|
8912
9929
|
this.crossdomainMode = Boolean(inIframe() && options.crossdomain?.enabled);
|
|
8913
9930
|
if (!IN_BROWSER || !processOptions(options)) {
|
|
8914
9931
|
return;
|
|
@@ -8967,6 +9984,24 @@ class API {
|
|
|
8967
9984
|
}
|
|
8968
9985
|
const app = new App(options.projectKey, options.sessionToken, options, this.signalStartIssue, this.crossdomainMode);
|
|
8969
9986
|
this.app = app;
|
|
9987
|
+
if (options.projectKey && options.analytics?.active) {
|
|
9988
|
+
const isSaas = !options.ingestPoint || options.ingestPoint.includes('api.openreplay.com');
|
|
9989
|
+
const defaultEdp = 'https://api.openreplay.com/ingest';
|
|
9990
|
+
this.analytics = new Analytics({
|
|
9991
|
+
localStorage: options.localStorage ?? localStorage,
|
|
9992
|
+
sessionStorage: options.sessionStorage ?? sessionStorage,
|
|
9993
|
+
getToken: () => this.getAnalyticsToken(),
|
|
9994
|
+
getTimestamp: () => this.app?.timestamp() ?? Date.now(),
|
|
9995
|
+
setUserId: (id) => {
|
|
9996
|
+
this.app?.session.setUserID(id);
|
|
9997
|
+
},
|
|
9998
|
+
notStandalone: true,
|
|
9999
|
+
ingestPoint: isSaas
|
|
10000
|
+
? defaultEdp
|
|
10001
|
+
: (options.analytics?.ingestPoint ?? options.ingestPoint ?? defaultEdp),
|
|
10002
|
+
projectKey: options.projectKey,
|
|
10003
|
+
});
|
|
10004
|
+
}
|
|
8970
10005
|
if (!this.crossdomainMode) {
|
|
8971
10006
|
// no need to send iframe viewport data since its a node for us
|
|
8972
10007
|
Viewport(app, options.urls);
|
|
@@ -9046,6 +10081,9 @@ class API {
|
|
|
9046
10081
|
if (this.app === null) {
|
|
9047
10082
|
return Promise.reject("Browser doesn't support required api, or doNotTrack is active.");
|
|
9048
10083
|
}
|
|
10084
|
+
if (startOpts?.userID) {
|
|
10085
|
+
this.analytics?.people.identify(startOpts.userID, { fromTracker: true });
|
|
10086
|
+
}
|
|
9049
10087
|
return this.app.start(startOpts);
|
|
9050
10088
|
}
|
|
9051
10089
|
else {
|
|
@@ -9153,21 +10191,6 @@ class API {
|
|
|
9153
10191
|
deprecationWarn("'sessionID' method", "'getSessionID' method", '/');
|
|
9154
10192
|
return this.getSessionID();
|
|
9155
10193
|
}
|
|
9156
|
-
getSessionURL(options) {
|
|
9157
|
-
if (this.app === null) {
|
|
9158
|
-
return undefined;
|
|
9159
|
-
}
|
|
9160
|
-
return this.app.getSessionURL(options);
|
|
9161
|
-
}
|
|
9162
|
-
setUserID(id) {
|
|
9163
|
-
if (typeof id === 'string' && this.app !== null) {
|
|
9164
|
-
this.app.session.setUserID(id);
|
|
9165
|
-
}
|
|
9166
|
-
}
|
|
9167
|
-
userID(id) {
|
|
9168
|
-
deprecationWarn("'userID' method", "'setUserID' method", '/');
|
|
9169
|
-
this.setUserID(id);
|
|
9170
|
-
}
|
|
9171
10194
|
setUserAnonymousID(id) {
|
|
9172
10195
|
if (typeof id === 'string' && this.app !== null) {
|
|
9173
10196
|
this.app.send(UserAnonymousID(id));
|