@openreplay/tracker 16.2.2-beta.19 → 16.3.0-beta.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.
@@ -13,6 +13,7 @@ import type { Options as TimingOptions } from './modules/timing.js';
13
13
  import type { Options as NetworkOptions } from './modules/network.js';
14
14
  import type { MouseHandlerOptions } from './modules/mouse.js';
15
15
  import type { SessionInfo } from './app/session.js';
16
+ import type { CssRulesOptions } from './modules/cssrules.js';
16
17
  import type { StartOptions } from './app/index.js';
17
18
  import type { StartPromiseReturn } from './app/index.js';
18
19
  export type Options = Partial<AppOptions & ConsoleOptions & ExceptionOptions & InputOptions & PerformanceOptions & TimingOptions> & {
@@ -28,7 +29,7 @@ export type Options = Partial<AppOptions & ConsoleOptions & ExceptionOptions & I
28
29
  onFlagsLoad?: (flags: IFeatureFlag[]) => void;
29
30
  };
30
31
  __DISABLE_SECURE_MODE?: boolean;
31
- checkCssInterval?: number;
32
+ css: CssRulesOptions;
32
33
  };
33
34
  export default class API {
34
35
  readonly options: Partial<Options>;
@@ -1,4 +1,16 @@
1
1
  import type App from '../app/index.js';
2
- export default function (app: App, opts: {
2
+ export interface CssRulesOptions {
3
3
  checkCssInterval?: number;
4
- }): void;
4
+ scanInMemoryCSS?: boolean;
5
+ /**
6
+ Useful for cases where you expect limited amount of mutations
7
+
8
+ i.e when sheets are hydrated on client after initial render.
9
+
10
+ if you want to observe for x seconds, do (x*1000)/checkCssInterval = checkLimit
11
+
12
+ applied to each stylesheet individually.
13
+ */
14
+ checkLimit?: number;
15
+ }
16
+ export default function (app: App, opts: CssRulesOptions): void;
package/dist/lib/entry.js CHANGED
@@ -3560,7 +3560,7 @@ function isNodeStillActive(node) {
3560
3560
  return [false, e];
3561
3561
  }
3562
3562
  }
3563
- const defaults = {
3563
+ const defaults$1 = {
3564
3564
  interval: SECOND * 30,
3565
3565
  batchSize: 2500,
3566
3566
  enabled: true,
@@ -3588,7 +3588,7 @@ class Maintainer {
3588
3588
  clearInterval(this.interval);
3589
3589
  }
3590
3590
  };
3591
- this.options = { ...defaults, ...options };
3591
+ this.options = { ...defaults$1, ...options };
3592
3592
  }
3593
3593
  }
3594
3594
 
@@ -4042,7 +4042,6 @@ function ConstructedStyleSheets (app) {
4042
4042
  return replace.call(this, text).then((sheet) => {
4043
4043
  const sheetID = styleSheetIDMap.get(this);
4044
4044
  if (sheetID) {
4045
- console.log('replace');
4046
4045
  app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
4047
4046
  }
4048
4047
  return sheet;
@@ -4052,7 +4051,6 @@ function ConstructedStyleSheets (app) {
4052
4051
  context.CSSStyleSheet.prototype.replaceSync = function (text) {
4053
4052
  const sheetID = styleSheetIDMap.get(this);
4054
4053
  if (sheetID) {
4055
- console.log('replaceSync');
4056
4054
  app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
4057
4055
  }
4058
4056
  return replaceSync.call(this, text);
@@ -5204,7 +5202,7 @@ class App {
5204
5202
  this.stopCallbacks = [];
5205
5203
  this.commitCallbacks = [];
5206
5204
  this.activityState = ActivityState.NotActive;
5207
- this.version = '16.2.2-beta.19'; // TODO: version compatability check inside each plugin.
5205
+ this.version = '16.3.0-beta.0'; // TODO: version compatability check inside each plugin.
5208
5206
  this.socketMode = false;
5209
5207
  this.compressionThreshold = 24 * 1000;
5210
5208
  this.bc = null;
@@ -8039,6 +8037,11 @@ function Viewport (app) {
8039
8037
  app.ticker.attach(sendSetViewportSize, 5, false);
8040
8038
  }
8041
8039
 
8040
+ const defaults = {
8041
+ checkCssInterval: 200,
8042
+ scanInMemoryCSS: false,
8043
+ checkLimit: undefined,
8044
+ };
8042
8045
  function CSSRules (app, opts) {
8043
8046
  if (app === null)
8044
8047
  return;
@@ -8046,34 +8049,48 @@ function CSSRules (app, opts) {
8046
8049
  app.send(TechnicalInfo('no_stylesheet_prototype_in_window', ''));
8047
8050
  return;
8048
8051
  }
8049
- // Track CSS rule snapshots by sheetID:index
8052
+ const options = { ...defaults, ...opts };
8053
+ // sheetID:index -> ruleText
8050
8054
  const ruleSnapshots = new Map();
8051
8055
  let checkInterval = null;
8052
- const checkIntervalMs = opts.checkCssInterval || 200; // Check every 200ms
8053
- // Check all rules for changes
8056
+ const trackedSheets = new Set();
8057
+ const checkIntervalMs = options.checkCssInterval || 200;
8058
+ let checkIterations = {};
8054
8059
  function checkRuleChanges() {
8055
- for (let i = 0; i < document.styleSheets.length; i++) {
8060
+ if (!options.scanInMemoryCSS)
8061
+ return;
8062
+ const allSheets = trackedSheets.values();
8063
+ for (const sheet of allSheets) {
8056
8064
  try {
8057
- const sheet = document.styleSheets[i];
8058
8065
  const sheetID = styleSheetIDMap.get(sheet);
8059
8066
  if (!sheetID)
8060
8067
  continue;
8061
- // Check each rule in the sheet
8068
+ if (options.checkLimit) {
8069
+ if (!checkIterations[sheetID]) {
8070
+ checkIterations[sheetID] = 0;
8071
+ }
8072
+ else {
8073
+ checkIterations[sheetID]++;
8074
+ }
8075
+ if (checkIterations[sheetID] > options.checkLimit) {
8076
+ trackedSheets.delete(sheet);
8077
+ return;
8078
+ }
8079
+ }
8062
8080
  for (let j = 0; j < sheet.cssRules.length; j++) {
8063
8081
  try {
8064
8082
  const rule = sheet.cssRules[j];
8065
8083
  const key = `${sheetID}:${j}`;
8066
- const newText = rule.cssText;
8067
8084
  const oldText = ruleSnapshots.get(key);
8085
+ const newText = rule.cssText;
8068
8086
  if (oldText !== newText) {
8069
- // Rule is new or changed
8070
8087
  if (oldText !== undefined) {
8071
- // Rule changed - send update
8088
+ // Rule is changed
8072
8089
  app.send(AdoptedSSDeleteRule(sheetID, j));
8073
8090
  app.send(AdoptedSSInsertRuleURLBased(sheetID, newText, j, app.getBaseHref()));
8074
8091
  }
8075
8092
  else {
8076
- // Rule added - send insert
8093
+ // Rule added
8077
8094
  app.send(AdoptedSSInsertRuleURLBased(sheetID, newText, j, app.getBaseHref()));
8078
8095
  }
8079
8096
  ruleSnapshots.set(key, newText);
@@ -8083,7 +8100,6 @@ function CSSRules (app, opts) {
8083
8100
  /* Skip inaccessible rules */
8084
8101
  }
8085
8102
  }
8086
- // Check for deleted rules
8087
8103
  const keysToCheck = Array.from(ruleSnapshots.keys()).filter((key) => key.startsWith(`${sheetID}:`));
8088
8104
  for (const key of keysToCheck) {
8089
8105
  const index = parseInt(key.split(':')[1], 10);
@@ -8094,21 +8110,30 @@ function CSSRules (app, opts) {
8094
8110
  }
8095
8111
  catch (e) {
8096
8112
  /* Skip inaccessible sheets */
8113
+ trackedSheets.delete(sheet);
8097
8114
  }
8098
8115
  }
8099
8116
  }
8100
- // Standard API hooks
8117
+ const emptyRuleReg = /{\s*}/;
8118
+ function isRuleEmpty(rule) {
8119
+ return emptyRuleReg.test(rule);
8120
+ }
8101
8121
  const sendInsertDeleteRule = app.safe((sheet, index, rule) => {
8102
8122
  const sheetID = styleSheetIDMap.get(sheet);
8103
8123
  if (!sheetID)
8104
8124
  return;
8105
8125
  if (typeof rule === 'string') {
8106
8126
  app.send(AdoptedSSInsertRuleURLBased(sheetID, rule, index, app.getBaseHref()));
8107
- ruleSnapshots.set(`${sheetID}:${index}`, rule);
8127
+ if (isRuleEmpty(rule)) {
8128
+ ruleSnapshots.set(`${sheetID}:${index}`, rule);
8129
+ trackedSheets.add(sheet);
8130
+ }
8108
8131
  }
8109
8132
  else {
8110
8133
  app.send(AdoptedSSDeleteRule(sheetID, index));
8111
- ruleSnapshots.delete(`${sheetID}:${index}`);
8134
+ if (ruleSnapshots.has(`${sheetID}:${index}`)) {
8135
+ ruleSnapshots.delete(`${sheetID}:${index}`);
8136
+ }
8112
8137
  }
8113
8138
  });
8114
8139
  const sendReplaceGroupingRule = app.safe((rule) => {
@@ -8126,7 +8151,10 @@ function CSSRules (app, opts) {
8126
8151
  if (idx >= 0) {
8127
8152
  app.send(AdoptedSSInsertRuleURLBased(sheetID, cssText, idx, app.getBaseHref()));
8128
8153
  app.send(AdoptedSSDeleteRule(sheetID, idx + 1));
8129
- ruleSnapshots.set(`${sheetID}:${idx}`, cssText);
8154
+ if (isRuleEmpty(cssText)) {
8155
+ ruleSnapshots.set(`${sheetID}:${idx}`, cssText);
8156
+ trackedSheets.add(sheet);
8157
+ }
8130
8158
  }
8131
8159
  });
8132
8160
  // Patch prototype methods
@@ -8156,10 +8184,8 @@ function CSSRules (app, opts) {
8156
8184
  return result;
8157
8185
  };
8158
8186
  });
8159
- // Apply patches
8160
8187
  patchContext(window);
8161
8188
  app.observer.attachContextCallback(patchContext);
8162
- // Track style nodes
8163
8189
  app.nodes.attachNodeCallback((node) => {
8164
8190
  if (!hasTag(node, 'style') || !node.sheet)
8165
8191
  return;
@@ -8181,9 +8207,8 @@ function CSSRules (app, opts) {
8181
8207
  }
8182
8208
  }
8183
8209
  });
8184
- // Start checking and setup cleanup
8185
8210
  function startChecking() {
8186
- if (checkInterval)
8211
+ if (checkInterval || !options.scanInMemoryCSS)
8187
8212
  return;
8188
8213
  checkInterval = window.setInterval(checkRuleChanges, checkIntervalMs);
8189
8214
  }
@@ -9758,7 +9783,7 @@ class API {
9758
9783
  this.signalStartIssue = (reason, missingApi) => {
9759
9784
  const doNotTrack = this.checkDoNotTrack();
9760
9785
  console.log("Tracker couldn't start due to:", JSON.stringify({
9761
- trackerVersion: '16.2.2-beta.19',
9786
+ trackerVersion: '16.3.0-beta.0',
9762
9787
  projectKey: this.options.projectKey,
9763
9788
  doNotTrack,
9764
9789
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
@@ -9857,7 +9882,7 @@ class API {
9857
9882
  Mouse(app, options.mouse);
9858
9883
  // inside iframe, we ignore viewport scroll
9859
9884
  Scroll(app, this.crossdomainMode);
9860
- CSSRules(app, options);
9885
+ CSSRules(app, options.css);
9861
9886
  ConstructedStyleSheets(app);
9862
9887
  Console(app, options);
9863
9888
  Exception(app, options);