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