@openreplay/tracker 16.0.0 → 16.0.1

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
@@ -727,8 +727,8 @@ class StringDictionary {
727
727
  let isNew = false;
728
728
  if (!this.backDict[str]) {
729
729
  isNew = true;
730
- const digits = Math.floor(Math.log10(Date.now())) + 1;
731
- const shavedTs = Date.now() % (10 ** (digits - 2));
730
+ // shaving the first 2 digits of the timestamp (since they are irrelevant for next millennia)
731
+ const shavedTs = Date.now() % 10 ** (13 - 2);
732
732
  let id = shavedTs;
733
733
  if (id === this.lastTs) {
734
734
  id = id * 10000 + this.lastSuffix;
@@ -1254,7 +1254,7 @@ function hasOpenreplayAttribute(e, attr) {
1254
1254
  if (DEPRECATED_ATTRS[attr]) {
1255
1255
  deprecationWarn(`"${newName}" attribute`,
1256
1256
  // @ts-ignore
1257
- `"${DEPRECATED_ATTRS[attr]}" attribute`, '/installation/sanitize-data');
1257
+ `"${DEPRECATED_ATTRS[attr]}" attribute`, '/en/sdk/sanitize-data');
1258
1258
  }
1259
1259
  return true;
1260
1260
  }
@@ -3756,8 +3756,8 @@ class Nodes {
3756
3756
  }
3757
3757
 
3758
3758
  const iconCache = {};
3759
- const domParser = new DOMParser();
3760
- async function parseUseEl(useElement, mode) {
3759
+ const svgUrlCache = {};
3760
+ async function parseUseEl(useElement, mode, domParser) {
3761
3761
  try {
3762
3762
  const href = useElement.getAttribute('xlink:href') || useElement.getAttribute('href');
3763
3763
  if (!href) {
@@ -3772,13 +3772,43 @@ async function parseUseEl(useElement, mode) {
3772
3772
  if (iconCache[symbolId]) {
3773
3773
  return iconCache[symbolId];
3774
3774
  }
3775
- const response = await fetch(url);
3776
- const svgText = await response.text();
3777
- const svgDoc = domParser.parseFromString(svgText, 'image/svg+xml');
3775
+ let svgDoc;
3776
+ if (svgUrlCache[url]) {
3777
+ if (svgUrlCache[url] === 1) {
3778
+ await new Promise((resolve) => {
3779
+ let tries = 0;
3780
+ const interval = setInterval(() => {
3781
+ if (tries > 100) {
3782
+ clearInterval(interval);
3783
+ resolve(false);
3784
+ }
3785
+ if (svgUrlCache[url] !== 1) {
3786
+ svgDoc = svgUrlCache[url];
3787
+ clearInterval(interval);
3788
+ resolve(true);
3789
+ }
3790
+ else {
3791
+ tries++;
3792
+ }
3793
+ }, 100);
3794
+ });
3795
+ }
3796
+ else {
3797
+ svgDoc = svgUrlCache[url] ?? `<svg xmlns="http://www.w3.org/2000/svg"></svg>`;
3798
+ }
3799
+ }
3800
+ else {
3801
+ svgUrlCache[url] = 1;
3802
+ const response = await fetch(url);
3803
+ const svgText = await response.text();
3804
+ svgDoc = domParser.parseFromString(svgText, 'image/svg+xml');
3805
+ svgUrlCache[url] = svgDoc;
3806
+ }
3807
+ // @ts-ignore
3778
3808
  const symbol = svgDoc.getElementById(symbolId);
3779
3809
  if (!symbol) {
3780
3810
  console.debug('Openreplay: Symbol not found in SVG.');
3781
- return;
3811
+ return '';
3782
3812
  }
3783
3813
  if (mode === 'inline') ;
3784
3814
  if (mode === 'svgtext') {
@@ -3833,7 +3863,7 @@ var RecentsType;
3833
3863
  RecentsType[RecentsType["Changed"] = 2] = "Changed";
3834
3864
  })(RecentsType || (RecentsType = {}));
3835
3865
  class Observer {
3836
- constructor(app, isTopContext = false) {
3866
+ constructor(app, isTopContext = false, options = { disableSprites: false }) {
3837
3867
  this.app = app;
3838
3868
  this.isTopContext = isTopContext;
3839
3869
  this.commited = [];
@@ -3841,6 +3871,9 @@ class Observer {
3841
3871
  this.indexes = [];
3842
3872
  this.attributesMap = new Map();
3843
3873
  this.textSet = new Set();
3874
+ this.disableSprites = false;
3875
+ this.domParser = new DOMParser();
3876
+ this.disableSprites = options.disableSprites;
3844
3877
  this.observer = createMutationObserver(this.app.safe((mutations) => {
3845
3878
  for (const mutation of mutations) {
3846
3879
  // mutations order is sequential
@@ -3935,8 +3968,8 @@ class Observer {
3935
3968
  if (value === null) {
3936
3969
  this.app.send(RemoveNodeAttribute(id, name));
3937
3970
  }
3938
- if (isUseElement(node) && name === 'href') {
3939
- parseUseEl(node, 'svgtext')
3971
+ if (isUseElement(node) && name === 'href' && !this.disableSprites) {
3972
+ parseUseEl(node, 'svgtext', this.domParser)
3940
3973
  .then((svgData) => {
3941
3974
  if (svgData) {
3942
3975
  this.app.send(SetNodeAttribute(id, name, `_$OPENREPLAY_SPRITE$_${svgData}`));
@@ -4011,7 +4044,7 @@ class Observer {
4011
4044
  const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, {
4012
4045
  acceptNode: (node) => {
4013
4046
  if (this.app.nodes.getID(node) !== undefined) {
4014
- this.app.debug.error('! Node is already bound', node);
4047
+ this.app.debug.warn('! Node is already bound', node);
4015
4048
  }
4016
4049
  return isIgnored(node) || this.app.nodes.getID(node) !== undefined
4017
4050
  ? NodeFilter.FILTER_REJECT
@@ -4289,7 +4322,11 @@ class IFrameOffsets {
4289
4322
  const attachShadowNativeFn = IN_BROWSER ? Element.prototype.attachShadow : () => new ShadowRoot();
4290
4323
  class TopObserver extends Observer {
4291
4324
  constructor(params) {
4292
- super(params.app, true);
4325
+ const opts = Object.assign({
4326
+ captureIFrames: true,
4327
+ disableSprites: false,
4328
+ }, params.options);
4329
+ super(params.app, true, opts);
4293
4330
  this.iframeOffsets = new IFrameOffsets();
4294
4331
  this.contextCallbacks = [];
4295
4332
  // Attached once per Tracker instance
@@ -4299,9 +4336,7 @@ class TopObserver extends Observer {
4299
4336
  this.docObservers = new WeakMap();
4300
4337
  this.shadowRootObservers = new WeakMap();
4301
4338
  this.app = params.app;
4302
- this.options = Object.assign({
4303
- captureIFrames: true,
4304
- }, params.options);
4339
+ this.options = opts;
4305
4340
  // IFrames
4306
4341
  this.app.nodes.attachNodeCallback((node) => {
4307
4342
  if (hasTag(node, 'iframe') &&
@@ -4730,7 +4765,7 @@ class App {
4730
4765
  this.stopCallbacks = [];
4731
4766
  this.commitCallbacks = [];
4732
4767
  this.activityState = ActivityState.NotActive;
4733
- this.version = '16.0.0'; // TODO: version compatability check inside each plugin.
4768
+ this.version = '16.0.1'; // TODO: version compatability check inside each plugin.
4734
4769
  this.socketMode = false;
4735
4770
  this.compressionThreshold = 24 * 1000;
4736
4771
  this.bc = null;
@@ -5001,7 +5036,7 @@ class App {
5001
5036
  this.canvasRecorder?.restartTracking();
5002
5037
  };
5003
5038
  this.flushBuffer = async (buffer) => {
5004
- return new Promise((res) => {
5039
+ return new Promise((res, reject) => {
5005
5040
  if (buffer.length === 0) {
5006
5041
  res(null);
5007
5042
  return;
@@ -5011,9 +5046,18 @@ class App {
5011
5046
  while (endIndex < buffer.length && buffer[endIndex][0] !== 0 /* MType.Timestamp */) {
5012
5047
  endIndex++;
5013
5048
  }
5014
- const messagesBatch = buffer.splice(0, endIndex);
5015
- this.postToWorker(messagesBatch);
5016
- res(null);
5049
+ requestIdleCb(() => {
5050
+ try {
5051
+ const messagesBatch = buffer.splice(0, endIndex);
5052
+ // Cast out potential proxy objects (produced from vue.js deep reactivity, for example) to a regular array.
5053
+ this.postToWorker(messagesBatch.map((x) => [...x]));
5054
+ res(null);
5055
+ }
5056
+ catch (e) {
5057
+ this._debug('flushBuffer', e);
5058
+ reject(new Error('flushBuffer failed'));
5059
+ }
5060
+ });
5017
5061
  });
5018
5062
  };
5019
5063
  this.onUxtCb = [];
@@ -5054,6 +5098,7 @@ class App {
5054
5098
  fixedCanvasScaling: false,
5055
5099
  disableCanvas: false,
5056
5100
  captureIFrames: true,
5101
+ disableSprites: false,
5057
5102
  obscureTextEmails: true,
5058
5103
  obscureTextNumbers: false,
5059
5104
  crossdomain: {
@@ -9133,7 +9178,7 @@ function Tabs (app) {
9133
9178
  }
9134
9179
 
9135
9180
  const Messages = _Messages;
9136
- const DOCS_SETUP = '/installation/javascript-sdk';
9181
+ const DOCS_SETUP = '/en/sdk';
9137
9182
  function processOptions(obj) {
9138
9183
  if (obj == null) {
9139
9184
  console.error(`OpenReplay: invalid options argument type. Please, check documentation on ${DOCS_HOST}${DOCS_SETUP}`);
@@ -9183,7 +9228,7 @@ class API {
9183
9228
  this.signalStartIssue = (reason, missingApi) => {
9184
9229
  const doNotTrack = this.checkDoNotTrack();
9185
9230
  console.log("Tracker couldn't start due to:", JSON.stringify({
9186
- trackerVersion: '16.0.0',
9231
+ trackerVersion: '16.0.1',
9187
9232
  projectKey: this.options.projectKey,
9188
9233
  doNotTrack,
9189
9234
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,