@openreplay/tracker 16.2.1 → 16.2.2-beta.19

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/entry.js CHANGED
@@ -4046,6 +4046,7 @@ function ConstructedStyleSheets (app) {
4046
4046
  return replace.call(this, text).then((sheet) => {
4047
4047
  const sheetID = styleSheetIDMap.get(this);
4048
4048
  if (sheetID) {
4049
+ console.log('replace');
4049
4050
  app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
4050
4051
  }
4051
4052
  return sheet;
@@ -4055,6 +4056,7 @@ function ConstructedStyleSheets (app) {
4055
4056
  context.CSSStyleSheet.prototype.replaceSync = function (text) {
4056
4057
  const sheetID = styleSheetIDMap.get(this);
4057
4058
  if (sheetID) {
4059
+ console.log('replaceSync');
4058
4060
  app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
4059
4061
  }
4060
4062
  return replaceSync.call(this, text);
@@ -5206,7 +5208,7 @@ class App {
5206
5208
  this.stopCallbacks = [];
5207
5209
  this.commitCallbacks = [];
5208
5210
  this.activityState = ActivityState.NotActive;
5209
- this.version = '16.2.1'; // TODO: version compatability check inside each plugin.
5211
+ this.version = '16.2.2-beta.19'; // TODO: version compatability check inside each plugin.
5210
5212
  this.socketMode = false;
5211
5213
  this.compressionThreshold = 24 * 1000;
5212
5214
  this.bc = null;
@@ -8041,60 +8043,107 @@ function Viewport (app) {
8041
8043
  app.ticker.attach(sendSetViewportSize, 5, false);
8042
8044
  }
8043
8045
 
8044
- function CSSRules (app) {
8045
- if (app === null) {
8046
+ function CSSRules (app, opts) {
8047
+ if (app === null)
8046
8048
  return;
8047
- }
8048
8049
  if (!window.CSSStyleSheet) {
8049
8050
  app.send(TechnicalInfo('no_stylesheet_prototype_in_window', ''));
8050
8051
  return;
8051
8052
  }
8053
+ // Track CSS rule snapshots by sheetID:index
8054
+ const ruleSnapshots = new Map();
8055
+ let checkInterval = null;
8056
+ const checkIntervalMs = opts.checkCssInterval || 200; // Check every 200ms
8057
+ // Check all rules for changes
8058
+ function checkRuleChanges() {
8059
+ for (let i = 0; i < document.styleSheets.length; i++) {
8060
+ try {
8061
+ const sheet = document.styleSheets[i];
8062
+ const sheetID = styleSheetIDMap.get(sheet);
8063
+ if (!sheetID)
8064
+ continue;
8065
+ // Check each rule in the sheet
8066
+ for (let j = 0; j < sheet.cssRules.length; j++) {
8067
+ try {
8068
+ const rule = sheet.cssRules[j];
8069
+ const key = `${sheetID}:${j}`;
8070
+ const newText = rule.cssText;
8071
+ const oldText = ruleSnapshots.get(key);
8072
+ if (oldText !== newText) {
8073
+ // Rule is new or changed
8074
+ if (oldText !== undefined) {
8075
+ // Rule changed - send update
8076
+ app.send(AdoptedSSDeleteRule(sheetID, j));
8077
+ app.send(AdoptedSSInsertRuleURLBased(sheetID, newText, j, app.getBaseHref()));
8078
+ }
8079
+ else {
8080
+ // Rule added - send insert
8081
+ app.send(AdoptedSSInsertRuleURLBased(sheetID, newText, j, app.getBaseHref()));
8082
+ }
8083
+ ruleSnapshots.set(key, newText);
8084
+ }
8085
+ }
8086
+ catch (e) {
8087
+ /* Skip inaccessible rules */
8088
+ }
8089
+ }
8090
+ // Check for deleted rules
8091
+ const keysToCheck = Array.from(ruleSnapshots.keys()).filter((key) => key.startsWith(`${sheetID}:`));
8092
+ for (const key of keysToCheck) {
8093
+ const index = parseInt(key.split(':')[1], 10);
8094
+ if (index >= sheet.cssRules.length) {
8095
+ ruleSnapshots.delete(key);
8096
+ }
8097
+ }
8098
+ }
8099
+ catch (e) {
8100
+ /* Skip inaccessible sheets */
8101
+ }
8102
+ }
8103
+ }
8104
+ // Standard API hooks
8052
8105
  const sendInsertDeleteRule = app.safe((sheet, index, rule) => {
8053
8106
  const sheetID = styleSheetIDMap.get(sheet);
8054
- if (!sheetID) {
8055
- // OK-case. Sheet haven't been registered yet. Rules will be sent on registration.
8107
+ if (!sheetID)
8056
8108
  return;
8057
- }
8058
8109
  if (typeof rule === 'string') {
8059
8110
  app.send(AdoptedSSInsertRuleURLBased(sheetID, rule, index, app.getBaseHref()));
8111
+ ruleSnapshots.set(`${sheetID}:${index}`, rule);
8060
8112
  }
8061
8113
  else {
8062
8114
  app.send(AdoptedSSDeleteRule(sheetID, index));
8115
+ ruleSnapshots.delete(`${sheetID}:${index}`);
8063
8116
  }
8064
8117
  });
8065
- // TODO: proper rule insertion/removal (how?)
8066
8118
  const sendReplaceGroupingRule = app.safe((rule) => {
8067
8119
  let topmostRule = rule;
8068
- while (topmostRule.parentRule) {
8120
+ while (topmostRule.parentRule)
8069
8121
  topmostRule = topmostRule.parentRule;
8070
- }
8071
8122
  const sheet = topmostRule.parentStyleSheet;
8072
- if (!sheet) {
8073
- app.debug.warn('No parent StyleSheet found for', topmostRule, rule);
8123
+ if (!sheet)
8074
8124
  return;
8075
- }
8076
8125
  const sheetID = styleSheetIDMap.get(sheet);
8077
- if (!sheetID) {
8078
- app.debug.warn('No sheedID found for', sheet, styleSheetIDMap);
8126
+ if (!sheetID)
8079
8127
  return;
8080
- }
8081
8128
  const cssText = topmostRule.cssText;
8082
- const ruleList = sheet.cssRules;
8083
- const idx = Array.from(ruleList).indexOf(topmostRule);
8129
+ const idx = Array.from(sheet.cssRules).indexOf(topmostRule);
8084
8130
  if (idx >= 0) {
8085
8131
  app.send(AdoptedSSInsertRuleURLBased(sheetID, cssText, idx, app.getBaseHref()));
8086
- app.send(AdoptedSSDeleteRule(sheetID, idx + 1)); // Remove previous clone
8087
- }
8088
- else {
8089
- app.debug.warn('Rule index not found in', sheet, topmostRule);
8132
+ app.send(AdoptedSSDeleteRule(sheetID, idx + 1));
8133
+ ruleSnapshots.set(`${sheetID}:${idx}`, cssText);
8090
8134
  }
8091
8135
  });
8136
+ // Patch prototype methods
8092
8137
  const patchContext = app.safe((context) => {
8138
+ if (context.__css_tracking_patched__)
8139
+ return;
8140
+ context.__css_tracking_patched__ = true;
8093
8141
  const { insertRule, deleteRule } = context.CSSStyleSheet.prototype;
8094
8142
  const { insertRule: groupInsertRule, deleteRule: groupDeleteRule } = context.CSSGroupingRule.prototype;
8095
8143
  context.CSSStyleSheet.prototype.insertRule = function (rule, index = 0) {
8096
- sendInsertDeleteRule(this, index, rule);
8097
- return insertRule.call(this, rule, index);
8144
+ const result = insertRule.call(this, rule, index);
8145
+ sendInsertDeleteRule(this, result, rule);
8146
+ return result;
8098
8147
  };
8099
8148
  context.CSSStyleSheet.prototype.deleteRule = function (index) {
8100
8149
  sendInsertDeleteRule(this, index);
@@ -8105,33 +8154,50 @@ function CSSRules (app) {
8105
8154
  sendReplaceGroupingRule(this);
8106
8155
  return result;
8107
8156
  };
8108
- context.CSSGroupingRule.prototype.deleteRule = function (index = 0) {
8157
+ context.CSSGroupingRule.prototype.deleteRule = function (index) {
8109
8158
  const result = groupDeleteRule.call(this, index);
8110
8159
  sendReplaceGroupingRule(this);
8111
8160
  return result;
8112
8161
  };
8113
8162
  });
8163
+ // Apply patches
8114
8164
  patchContext(window);
8115
8165
  app.observer.attachContextCallback(patchContext);
8166
+ // Track style nodes
8116
8167
  app.nodes.attachNodeCallback((node) => {
8117
- if (!hasTag(node, 'style') || !node.sheet) {
8168
+ if (!hasTag(node, 'style') || !node.sheet)
8169
+ return;
8170
+ if (node.textContent !== null && node.textContent.trim().length > 0)
8118
8171
  return;
8119
- }
8120
- if (node.textContent !== null && node.textContent.trim().length > 0) {
8121
- return; // Non-virtual styles captured by the observer as a text
8122
- }
8123
8172
  const nodeID = app.nodes.getID(node);
8124
- if (!nodeID) {
8173
+ if (!nodeID)
8125
8174
  return;
8126
- }
8127
8175
  const sheet = node.sheet;
8128
8176
  const sheetID = nextID();
8129
8177
  styleSheetIDMap.set(sheet, sheetID);
8130
8178
  app.send(AdoptedSSAddOwner(sheetID, nodeID));
8131
- const rules = sheet.cssRules;
8132
- for (let i = 0; i < rules.length; i++) {
8133
- sendInsertDeleteRule(sheet, i, rules[i].cssText);
8179
+ for (let i = 0; i < sheet.cssRules.length; i++) {
8180
+ try {
8181
+ sendInsertDeleteRule(sheet, i, sheet.cssRules[i].cssText);
8182
+ }
8183
+ catch (e) {
8184
+ // Skip inaccessible rules
8185
+ }
8186
+ }
8187
+ });
8188
+ // Start checking and setup cleanup
8189
+ function startChecking() {
8190
+ if (checkInterval)
8191
+ return;
8192
+ checkInterval = window.setInterval(checkRuleChanges, checkIntervalMs);
8193
+ }
8194
+ setTimeout(startChecking, 50);
8195
+ app.attachStopCallback(() => {
8196
+ if (checkInterval) {
8197
+ clearInterval(checkInterval);
8198
+ checkInterval = null;
8134
8199
  }
8200
+ ruleSnapshots.clear();
8135
8201
  });
8136
8202
  }
8137
8203
 
@@ -9696,7 +9762,7 @@ class API {
9696
9762
  this.signalStartIssue = (reason, missingApi) => {
9697
9763
  const doNotTrack = this.checkDoNotTrack();
9698
9764
  console.log("Tracker couldn't start due to:", JSON.stringify({
9699
- trackerVersion: '16.2.1',
9765
+ trackerVersion: '16.2.2-beta.19',
9700
9766
  projectKey: this.options.projectKey,
9701
9767
  doNotTrack,
9702
9768
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
@@ -9795,7 +9861,7 @@ class API {
9795
9861
  Mouse(app, options.mouse);
9796
9862
  // inside iframe, we ignore viewport scroll
9797
9863
  Scroll(app, this.crossdomainMode);
9798
- CSSRules(app);
9864
+ CSSRules(app, options);
9799
9865
  ConstructedStyleSheets(app);
9800
9866
  Console(app, options);
9801
9867
  Exception(app, options);