@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/lib/index.js CHANGED
@@ -723,8 +723,8 @@ class StringDictionary {
723
723
  let isNew = false;
724
724
  if (!this.backDict[str]) {
725
725
  isNew = true;
726
- const digits = Math.floor(Math.log10(Date.now())) + 1;
727
- const shavedTs = Date.now() % (10 ** (digits - 2));
726
+ // shaving the first 2 digits of the timestamp (since they are irrelevant for next millennia)
727
+ const shavedTs = Date.now() % 10 ** (13 - 2);
728
728
  let id = shavedTs;
729
729
  if (id === this.lastTs) {
730
730
  id = id * 10000 + this.lastSuffix;
@@ -1250,7 +1250,7 @@ function hasOpenreplayAttribute(e, attr) {
1250
1250
  if (DEPRECATED_ATTRS[attr]) {
1251
1251
  deprecationWarn(`"${newName}" attribute`,
1252
1252
  // @ts-ignore
1253
- `"${DEPRECATED_ATTRS[attr]}" attribute`, '/installation/sanitize-data');
1253
+ `"${DEPRECATED_ATTRS[attr]}" attribute`, '/en/sdk/sanitize-data');
1254
1254
  }
1255
1255
  return true;
1256
1256
  }
@@ -3752,8 +3752,8 @@ class Nodes {
3752
3752
  }
3753
3753
 
3754
3754
  const iconCache = {};
3755
- const domParser = new DOMParser();
3756
- async function parseUseEl(useElement, mode) {
3755
+ const svgUrlCache = {};
3756
+ async function parseUseEl(useElement, mode, domParser) {
3757
3757
  try {
3758
3758
  const href = useElement.getAttribute('xlink:href') || useElement.getAttribute('href');
3759
3759
  if (!href) {
@@ -3768,13 +3768,43 @@ async function parseUseEl(useElement, mode) {
3768
3768
  if (iconCache[symbolId]) {
3769
3769
  return iconCache[symbolId];
3770
3770
  }
3771
- const response = await fetch(url);
3772
- const svgText = await response.text();
3773
- const svgDoc = domParser.parseFromString(svgText, 'image/svg+xml');
3771
+ let svgDoc;
3772
+ if (svgUrlCache[url]) {
3773
+ if (svgUrlCache[url] === 1) {
3774
+ await new Promise((resolve) => {
3775
+ let tries = 0;
3776
+ const interval = setInterval(() => {
3777
+ if (tries > 100) {
3778
+ clearInterval(interval);
3779
+ resolve(false);
3780
+ }
3781
+ if (svgUrlCache[url] !== 1) {
3782
+ svgDoc = svgUrlCache[url];
3783
+ clearInterval(interval);
3784
+ resolve(true);
3785
+ }
3786
+ else {
3787
+ tries++;
3788
+ }
3789
+ }, 100);
3790
+ });
3791
+ }
3792
+ else {
3793
+ svgDoc = svgUrlCache[url] ?? `<svg xmlns="http://www.w3.org/2000/svg"></svg>`;
3794
+ }
3795
+ }
3796
+ else {
3797
+ svgUrlCache[url] = 1;
3798
+ const response = await fetch(url);
3799
+ const svgText = await response.text();
3800
+ svgDoc = domParser.parseFromString(svgText, 'image/svg+xml');
3801
+ svgUrlCache[url] = svgDoc;
3802
+ }
3803
+ // @ts-ignore
3774
3804
  const symbol = svgDoc.getElementById(symbolId);
3775
3805
  if (!symbol) {
3776
3806
  console.debug('Openreplay: Symbol not found in SVG.');
3777
- return;
3807
+ return '';
3778
3808
  }
3779
3809
  if (mode === 'inline') ;
3780
3810
  if (mode === 'svgtext') {
@@ -3829,7 +3859,7 @@ var RecentsType;
3829
3859
  RecentsType[RecentsType["Changed"] = 2] = "Changed";
3830
3860
  })(RecentsType || (RecentsType = {}));
3831
3861
  class Observer {
3832
- constructor(app, isTopContext = false) {
3862
+ constructor(app, isTopContext = false, options = { disableSprites: false }) {
3833
3863
  this.app = app;
3834
3864
  this.isTopContext = isTopContext;
3835
3865
  this.commited = [];
@@ -3837,6 +3867,9 @@ class Observer {
3837
3867
  this.indexes = [];
3838
3868
  this.attributesMap = new Map();
3839
3869
  this.textSet = new Set();
3870
+ this.disableSprites = false;
3871
+ this.domParser = new DOMParser();
3872
+ this.disableSprites = options.disableSprites;
3840
3873
  this.observer = createMutationObserver(this.app.safe((mutations) => {
3841
3874
  for (const mutation of mutations) {
3842
3875
  // mutations order is sequential
@@ -3931,8 +3964,8 @@ class Observer {
3931
3964
  if (value === null) {
3932
3965
  this.app.send(RemoveNodeAttribute(id, name));
3933
3966
  }
3934
- if (isUseElement(node) && name === 'href') {
3935
- parseUseEl(node, 'svgtext')
3967
+ if (isUseElement(node) && name === 'href' && !this.disableSprites) {
3968
+ parseUseEl(node, 'svgtext', this.domParser)
3936
3969
  .then((svgData) => {
3937
3970
  if (svgData) {
3938
3971
  this.app.send(SetNodeAttribute(id, name, `_$OPENREPLAY_SPRITE$_${svgData}`));
@@ -4007,7 +4040,7 @@ class Observer {
4007
4040
  const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, {
4008
4041
  acceptNode: (node) => {
4009
4042
  if (this.app.nodes.getID(node) !== undefined) {
4010
- this.app.debug.error('! Node is already bound', node);
4043
+ this.app.debug.warn('! Node is already bound', node);
4011
4044
  }
4012
4045
  return isIgnored(node) || this.app.nodes.getID(node) !== undefined
4013
4046
  ? NodeFilter.FILTER_REJECT
@@ -4285,7 +4318,11 @@ class IFrameOffsets {
4285
4318
  const attachShadowNativeFn = IN_BROWSER ? Element.prototype.attachShadow : () => new ShadowRoot();
4286
4319
  class TopObserver extends Observer {
4287
4320
  constructor(params) {
4288
- super(params.app, true);
4321
+ const opts = Object.assign({
4322
+ captureIFrames: true,
4323
+ disableSprites: false,
4324
+ }, params.options);
4325
+ super(params.app, true, opts);
4289
4326
  this.iframeOffsets = new IFrameOffsets();
4290
4327
  this.contextCallbacks = [];
4291
4328
  // Attached once per Tracker instance
@@ -4295,9 +4332,7 @@ class TopObserver extends Observer {
4295
4332
  this.docObservers = new WeakMap();
4296
4333
  this.shadowRootObservers = new WeakMap();
4297
4334
  this.app = params.app;
4298
- this.options = Object.assign({
4299
- captureIFrames: true,
4300
- }, params.options);
4335
+ this.options = opts;
4301
4336
  // IFrames
4302
4337
  this.app.nodes.attachNodeCallback((node) => {
4303
4338
  if (hasTag(node, 'iframe') &&
@@ -4726,7 +4761,7 @@ class App {
4726
4761
  this.stopCallbacks = [];
4727
4762
  this.commitCallbacks = [];
4728
4763
  this.activityState = ActivityState.NotActive;
4729
- this.version = '16.0.0'; // TODO: version compatability check inside each plugin.
4764
+ this.version = '16.0.1'; // TODO: version compatability check inside each plugin.
4730
4765
  this.socketMode = false;
4731
4766
  this.compressionThreshold = 24 * 1000;
4732
4767
  this.bc = null;
@@ -4997,7 +5032,7 @@ class App {
4997
5032
  this.canvasRecorder?.restartTracking();
4998
5033
  };
4999
5034
  this.flushBuffer = async (buffer) => {
5000
- return new Promise((res) => {
5035
+ return new Promise((res, reject) => {
5001
5036
  if (buffer.length === 0) {
5002
5037
  res(null);
5003
5038
  return;
@@ -5007,9 +5042,18 @@ class App {
5007
5042
  while (endIndex < buffer.length && buffer[endIndex][0] !== 0 /* MType.Timestamp */) {
5008
5043
  endIndex++;
5009
5044
  }
5010
- const messagesBatch = buffer.splice(0, endIndex);
5011
- this.postToWorker(messagesBatch);
5012
- res(null);
5045
+ requestIdleCb(() => {
5046
+ try {
5047
+ const messagesBatch = buffer.splice(0, endIndex);
5048
+ // Cast out potential proxy objects (produced from vue.js deep reactivity, for example) to a regular array.
5049
+ this.postToWorker(messagesBatch.map((x) => [...x]));
5050
+ res(null);
5051
+ }
5052
+ catch (e) {
5053
+ this._debug('flushBuffer', e);
5054
+ reject(new Error('flushBuffer failed'));
5055
+ }
5056
+ });
5013
5057
  });
5014
5058
  };
5015
5059
  this.onUxtCb = [];
@@ -5050,6 +5094,7 @@ class App {
5050
5094
  fixedCanvasScaling: false,
5051
5095
  disableCanvas: false,
5052
5096
  captureIFrames: true,
5097
+ disableSprites: false,
5053
5098
  obscureTextEmails: true,
5054
5099
  obscureTextNumbers: false,
5055
5100
  crossdomain: {
@@ -9129,7 +9174,7 @@ function Tabs (app) {
9129
9174
  }
9130
9175
 
9131
9176
  const Messages = _Messages;
9132
- const DOCS_SETUP = '/installation/javascript-sdk';
9177
+ const DOCS_SETUP = '/en/sdk';
9133
9178
  function processOptions(obj) {
9134
9179
  if (obj == null) {
9135
9180
  console.error(`OpenReplay: invalid options argument type. Please, check documentation on ${DOCS_HOST}${DOCS_SETUP}`);
@@ -9179,7 +9224,7 @@ class API {
9179
9224
  this.signalStartIssue = (reason, missingApi) => {
9180
9225
  const doNotTrack = this.checkDoNotTrack();
9181
9226
  console.log("Tracker couldn't start due to:", JSON.stringify({
9182
- trackerVersion: '16.0.0',
9227
+ trackerVersion: '16.0.1',
9183
9228
  projectKey: this.options.projectKey,
9184
9229
  doNotTrack,
9185
9230
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,