@openreplay/tracker 16.4.2 → 16.4.3

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/index.js CHANGED
@@ -5098,15 +5098,16 @@ class Session {
5098
5098
  this.userInfo = userInfo;
5099
5099
  }
5100
5100
  getSessionToken(projectKey) {
5101
- const token = this.token || this.app.sessionStorage.getItem(this.options.session_token_key);
5102
- if (projectKey && token) {
5103
- const savedProject = token.split('_&_')[1];
5101
+ const tokenWithProject = this.token || this.app.sessionStorage.getItem(this.options.session_token_key);
5102
+ if (projectKey && tokenWithProject) {
5103
+ const savedProject = tokenWithProject.split('_&_')[1];
5104
5104
  if (!savedProject || savedProject !== projectKey) {
5105
5105
  this.app.sessionStorage.removeItem(this.options.session_token_key);
5106
5106
  this.token = undefined;
5107
5107
  return undefined;
5108
5108
  }
5109
5109
  }
5110
+ const token = tokenWithProject ? tokenWithProject.split('_&_')[0] : null;
5110
5111
  return token || undefined;
5111
5112
  }
5112
5113
  setSessionToken(token, projectKey) {
@@ -5275,7 +5276,7 @@ class App {
5275
5276
  this.stopCallbacks = [];
5276
5277
  this.commitCallbacks = [];
5277
5278
  this.activityState = ActivityState.NotActive;
5278
- this.version = '16.4.2'; // TODO: version compatability check inside each plugin.
5279
+ this.version = '16.4.3'; // TODO: version compatability check inside each plugin.
5279
5280
  this.socketMode = false;
5280
5281
  this.compressionThreshold = 24 * 1000;
5281
5282
  this.bc = null;
@@ -5563,9 +5564,170 @@ class App {
5563
5564
  this.orderNumber = 0;
5564
5565
  this.coldStartTs = 0;
5565
5566
  this.singleBuffer = false;
5567
+ /**
5568
+ * start buffering messages without starting the actual session, which gives
5569
+ * user 30 seconds to "activate" and record session by calling `start()` on conditional trigger,
5570
+ * and we will then send buffered batch, so it won't get lost
5571
+ * */
5572
+ this.coldStart = async (startOpts = {}, conditional) => {
5573
+ this.singleBuffer = false;
5574
+ const second = 1000;
5575
+ const isNewSession = this.checkSessionToken(startOpts.forceNew);
5576
+ if (conditional) {
5577
+ await this.setupConditionalStart(startOpts);
5578
+ }
5579
+ const cycle = () => {
5580
+ this.orderNumber += 1;
5581
+ adjustTimeOrigin();
5582
+ this.coldStartTs = now();
5583
+ if (this.orderNumber % 2 === 0) {
5584
+ this.bufferedMessages1.length = 0;
5585
+ this.bufferedMessages1.push(Timestamp(this.timestamp()));
5586
+ this.bufferedMessages1.push(TabData(this.session.getTabId()));
5587
+ }
5588
+ else {
5589
+ this.bufferedMessages2.length = 0;
5590
+ this.bufferedMessages2.push(Timestamp(this.timestamp()));
5591
+ this.bufferedMessages2.push(TabData(this.session.getTabId()));
5592
+ }
5593
+ this.stop(false);
5594
+ this.activityState = ActivityState.ColdStart;
5595
+ if (startOpts.sessionHash) {
5596
+ this.session.applySessionHash(startOpts.sessionHash);
5597
+ }
5598
+ if (startOpts.forceNew) {
5599
+ this.session.reset();
5600
+ }
5601
+ this.session.assign({
5602
+ userID: startOpts.userID,
5603
+ metadata: startOpts.metadata,
5604
+ });
5605
+ if (!isNewSession) {
5606
+ this.debug.log('continuing session on new tab', this.session.getTabId());
5607
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
5608
+ this.send(TabChange(this.session.getTabId()));
5609
+ }
5610
+ this.observer.observe();
5611
+ this.ticker.start();
5612
+ };
5613
+ this.coldInterval = setInterval(() => {
5614
+ cycle();
5615
+ }, 30 * second);
5616
+ cycle();
5617
+ };
5618
+ this.setupConditionalStart = async (startOpts) => {
5619
+ this.conditionsManager = new ConditionsManager(this, startOpts);
5620
+ const r = await fetch(this.options.ingestPoint + '/v1/web/start', {
5621
+ method: 'POST',
5622
+ headers: {
5623
+ 'Content-Type': 'application/json',
5624
+ },
5625
+ body: JSON.stringify({
5626
+ ...this.getTrackerInfo(),
5627
+ timestamp: now(),
5628
+ doNotRecord: true,
5629
+ bufferDiff: 0,
5630
+ userID: this.session.getInfo().userID,
5631
+ token: undefined,
5632
+ deviceMemory,
5633
+ jsHeapSizeLimit,
5634
+ timezone: getTimezone(),
5635
+ width: window.screen.width,
5636
+ height: window.screen.height,
5637
+ }),
5638
+ });
5639
+ const {
5640
+ // this token is needed to fetch conditions and flags,
5641
+ // but it can't be used to record a session
5642
+ token, userBrowser, userCity, userCountry, userDevice, userOS, userState, projectID, features, } = await r.json();
5643
+ this.features = features ? features : this.features;
5644
+ this.session.assign({ projectID });
5645
+ this.session.setUserInfo({
5646
+ userBrowser,
5647
+ userCity,
5648
+ userCountry,
5649
+ userDevice,
5650
+ userOS,
5651
+ userState,
5652
+ });
5653
+ const onStartInfo = { sessionToken: token, userUUID: '', sessionID: '' };
5654
+ this.startCallbacks.forEach((cb) => cb(onStartInfo));
5655
+ await this.conditionsManager?.fetchConditions(projectID, token);
5656
+ if (this.features['feature-flags']) {
5657
+ await this.featureFlags.reloadFlags(token);
5658
+ this.conditionsManager?.processFlags(this.featureFlags.flags);
5659
+ }
5660
+ await this.tagWatcher.fetchTags(this.options.ingestPoint, token);
5661
+ };
5566
5662
  this.onSessionSent = () => {
5567
5663
  return;
5568
5664
  };
5665
+ /**
5666
+ * Starts offline session recording
5667
+ * @param {Object} startOpts - options for session start, same as .start()
5668
+ * @param {Function} onSessionSent - callback that will be called once session is fully sent
5669
+ * */
5670
+ this.offlineRecording = (startOpts = {}, onSessionSent) => {
5671
+ this.onSessionSent = onSessionSent;
5672
+ this.singleBuffer = true;
5673
+ const isNewSession = this.checkSessionToken(startOpts.forceNew);
5674
+ adjustTimeOrigin();
5675
+ this.coldStartTs = now();
5676
+ const saverBuffer = this.localStorage.getItem(bufferStorageKey);
5677
+ if (saverBuffer) {
5678
+ const data = JSON.parse(saverBuffer);
5679
+ this.bufferedMessages1 = Array.isArray(data) ? data : this.bufferedMessages1;
5680
+ this.localStorage.removeItem(bufferStorageKey);
5681
+ }
5682
+ this.bufferedMessages1.push(Timestamp(this.timestamp()));
5683
+ this.bufferedMessages1.push(TabData(this.session.getTabId()));
5684
+ this.activityState = ActivityState.ColdStart;
5685
+ if (startOpts.sessionHash) {
5686
+ this.session.applySessionHash(startOpts.sessionHash);
5687
+ }
5688
+ if (startOpts.forceNew) {
5689
+ this.session.reset();
5690
+ }
5691
+ this.session.assign({
5692
+ userID: startOpts.userID,
5693
+ metadata: startOpts.metadata,
5694
+ });
5695
+ const onStartInfo = { sessionToken: '', userUUID: '', sessionID: '' };
5696
+ this.startCallbacks.forEach((cb) => cb(onStartInfo));
5697
+ if (!isNewSession) {
5698
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
5699
+ this.send(TabChange(this.session.getTabId()));
5700
+ }
5701
+ this.observer.observe();
5702
+ this.ticker.start();
5703
+ return {
5704
+ saveBuffer: this.saveBuffer,
5705
+ getBuffer: this.getBuffer,
5706
+ setBuffer: this.setBuffer,
5707
+ };
5708
+ };
5709
+ /**
5710
+ * Saves the captured messages in localStorage (or whatever is used in its place)
5711
+ *
5712
+ * Then, when this.offlineRecording is called, it will preload this messages and clear the storage item
5713
+ *
5714
+ * Keeping the size of local storage reasonable is up to the end users of this library
5715
+ * */
5716
+ this.saveBuffer = () => {
5717
+ this.localStorage.setItem(bufferStorageKey, JSON.stringify(this.bufferedMessages1));
5718
+ };
5719
+ /**
5720
+ * @returns buffer with stored messages for offline recording
5721
+ * */
5722
+ this.getBuffer = () => {
5723
+ return this.bufferedMessages1;
5724
+ };
5725
+ /**
5726
+ * Used to set a buffer with messages array
5727
+ * */
5728
+ this.setBuffer = (buffer) => {
5729
+ this.bufferedMessages1 = buffer;
5730
+ };
5569
5731
  this.prevOpts = {};
5570
5732
  this.restartCanvasTracking = () => {
5571
5733
  this.canvasRecorder?.restartTracking();
@@ -6072,167 +6234,6 @@ class App {
6072
6234
  const sessionToken = this.session.getSessionToken(this.projectKey);
6073
6235
  return needNewSessionID || !sessionToken;
6074
6236
  }
6075
- /**
6076
- * start buffering messages without starting the actual session, which gives
6077
- * user 30 seconds to "activate" and record session by calling `start()` on conditional trigger,
6078
- * and we will then send buffered batch, so it won't get lost
6079
- * */
6080
- async coldStart(startOpts = {}, conditional) {
6081
- this.singleBuffer = false;
6082
- const second = 1000;
6083
- const isNewSession = this.checkSessionToken(startOpts.forceNew);
6084
- if (conditional) {
6085
- await this.setupConditionalStart(startOpts);
6086
- }
6087
- const cycle = () => {
6088
- this.orderNumber += 1;
6089
- adjustTimeOrigin();
6090
- this.coldStartTs = now();
6091
- if (this.orderNumber % 2 === 0) {
6092
- this.bufferedMessages1.length = 0;
6093
- this.bufferedMessages1.push(Timestamp(this.timestamp()));
6094
- this.bufferedMessages1.push(TabData(this.session.getTabId()));
6095
- }
6096
- else {
6097
- this.bufferedMessages2.length = 0;
6098
- this.bufferedMessages2.push(Timestamp(this.timestamp()));
6099
- this.bufferedMessages2.push(TabData(this.session.getTabId()));
6100
- }
6101
- this.stop(false);
6102
- this.activityState = ActivityState.ColdStart;
6103
- if (startOpts.sessionHash) {
6104
- this.session.applySessionHash(startOpts.sessionHash);
6105
- }
6106
- if (startOpts.forceNew) {
6107
- this.session.reset();
6108
- }
6109
- this.session.assign({
6110
- userID: startOpts.userID,
6111
- metadata: startOpts.metadata,
6112
- });
6113
- if (!isNewSession) {
6114
- this.debug.log('continuing session on new tab', this.session.getTabId());
6115
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
6116
- this.send(TabChange(this.session.getTabId()));
6117
- }
6118
- this.observer.observe();
6119
- this.ticker.start();
6120
- };
6121
- this.coldInterval = setInterval(() => {
6122
- cycle();
6123
- }, 30 * second);
6124
- cycle();
6125
- }
6126
- async setupConditionalStart(startOpts) {
6127
- this.conditionsManager = new ConditionsManager(this, startOpts);
6128
- const r = await fetch(this.options.ingestPoint + '/v1/web/start', {
6129
- method: 'POST',
6130
- headers: {
6131
- 'Content-Type': 'application/json',
6132
- },
6133
- body: JSON.stringify({
6134
- ...this.getTrackerInfo(),
6135
- timestamp: now(),
6136
- doNotRecord: true,
6137
- bufferDiff: 0,
6138
- userID: this.session.getInfo().userID,
6139
- token: undefined,
6140
- deviceMemory,
6141
- jsHeapSizeLimit,
6142
- timezone: getTimezone(),
6143
- width: window.screen.width,
6144
- height: window.screen.height,
6145
- }),
6146
- });
6147
- const {
6148
- // this token is needed to fetch conditions and flags,
6149
- // but it can't be used to record a session
6150
- token, userBrowser, userCity, userCountry, userDevice, userOS, userState, projectID, features, } = await r.json();
6151
- this.features = features ? features : this.features;
6152
- this.session.assign({ projectID });
6153
- this.session.setUserInfo({
6154
- userBrowser,
6155
- userCity,
6156
- userCountry,
6157
- userDevice,
6158
- userOS,
6159
- userState,
6160
- });
6161
- const onStartInfo = { sessionToken: token, userUUID: '', sessionID: '' };
6162
- this.startCallbacks.forEach((cb) => cb(onStartInfo));
6163
- await this.conditionsManager?.fetchConditions(projectID, token);
6164
- if (this.features['feature-flags']) {
6165
- await this.featureFlags.reloadFlags(token);
6166
- this.conditionsManager?.processFlags(this.featureFlags.flags);
6167
- }
6168
- await this.tagWatcher.fetchTags(this.options.ingestPoint, token);
6169
- }
6170
- /**
6171
- * Starts offline session recording
6172
- * @param {Object} startOpts - options for session start, same as .start()
6173
- * @param {Function} onSessionSent - callback that will be called once session is fully sent
6174
- * */
6175
- offlineRecording(startOpts = {}, onSessionSent) {
6176
- this.onSessionSent = onSessionSent;
6177
- this.singleBuffer = true;
6178
- const isNewSession = this.checkSessionToken(startOpts.forceNew);
6179
- adjustTimeOrigin();
6180
- this.coldStartTs = now();
6181
- const saverBuffer = this.localStorage.getItem(bufferStorageKey);
6182
- if (saverBuffer) {
6183
- const data = JSON.parse(saverBuffer);
6184
- this.bufferedMessages1 = Array.isArray(data) ? data : this.bufferedMessages1;
6185
- this.localStorage.removeItem(bufferStorageKey);
6186
- }
6187
- this.bufferedMessages1.push(Timestamp(this.timestamp()));
6188
- this.bufferedMessages1.push(TabData(this.session.getTabId()));
6189
- this.activityState = ActivityState.ColdStart;
6190
- if (startOpts.sessionHash) {
6191
- this.session.applySessionHash(startOpts.sessionHash);
6192
- }
6193
- if (startOpts.forceNew) {
6194
- this.session.reset();
6195
- }
6196
- this.session.assign({
6197
- userID: startOpts.userID,
6198
- metadata: startOpts.metadata,
6199
- });
6200
- const onStartInfo = { sessionToken: '', userUUID: '', sessionID: '' };
6201
- this.startCallbacks.forEach((cb) => cb(onStartInfo));
6202
- if (!isNewSession) {
6203
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
6204
- this.send(TabChange(this.session.getTabId()));
6205
- }
6206
- this.observer.observe();
6207
- this.ticker.start();
6208
- return {
6209
- saveBuffer: this.saveBuffer,
6210
- getBuffer: this.getBuffer,
6211
- setBuffer: this.setBuffer,
6212
- };
6213
- }
6214
- /**
6215
- * Saves the captured messages in localStorage (or whatever is used in its place)
6216
- *
6217
- * Then, when this.offlineRecording is called, it will preload this messages and clear the storage item
6218
- *
6219
- * Keeping the size of local storage reasonable is up to the end users of this library
6220
- * */
6221
- saveBuffer() {
6222
- this.localStorage.setItem(bufferStorageKey, JSON.stringify(this.bufferedMessages1));
6223
- }
6224
- /**
6225
- * @returns buffer with stored messages for offline recording
6226
- * */
6227
- getBuffer() {
6228
- return this.bufferedMessages1;
6229
- }
6230
- /**
6231
- * Used to set a buffer with messages array
6232
- * */
6233
- setBuffer(buffer) {
6234
- this.bufferedMessages1 = buffer;
6235
- }
6236
6237
  /**
6237
6238
  * Uploads the stored session buffer to backend
6238
6239
  * @returns promise that resolves once messages are loaded, it has to be awaited
@@ -9655,7 +9656,7 @@ class API {
9655
9656
  this.signalStartIssue = (reason, missingApi) => {
9656
9657
  const doNotTrack = this.checkDoNotTrack();
9657
9658
  console.log("Tracker couldn't start due to:", JSON.stringify({
9658
- trackerVersion: '16.4.2',
9659
+ trackerVersion: '16.4.3',
9659
9660
  projectKey: this.options.projectKey,
9660
9661
  doNotTrack,
9661
9662
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,