@openreplay/tracker 16.3.0-beta.0 → 16.3.0-beta.2

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
@@ -1469,6 +1469,43 @@ function simpleMerge(defaultObj, givenObj) {
1469
1469
  }
1470
1470
  return result;
1471
1471
  }
1472
+ function throttleWithTrailing(fn, interval) {
1473
+ const lastCalls = new Map();
1474
+ const timeouts = new Map();
1475
+ const lastArgs = new Map();
1476
+ const throttled = function (key, ...args) {
1477
+ const now = Date.now();
1478
+ const lastCall = lastCalls.get(key) ?? 0;
1479
+ const remaining = interval - (now - lastCall);
1480
+ lastArgs.set(key, args);
1481
+ if (remaining <= 0) {
1482
+ if (timeouts.has(key)) {
1483
+ clearTimeout(timeouts.get(key));
1484
+ timeouts.delete(key);
1485
+ }
1486
+ lastCalls.set(key, now);
1487
+ fn(key, ...args);
1488
+ }
1489
+ else if (!timeouts.has(key)) {
1490
+ const timeoutId = setTimeout(() => {
1491
+ lastCalls.set(key, Date.now());
1492
+ timeouts.delete(key);
1493
+ const finalArgs = lastArgs.get(key);
1494
+ fn(key, ...finalArgs);
1495
+ }, remaining);
1496
+ timeouts.set(key, timeoutId);
1497
+ }
1498
+ };
1499
+ throttled.clear = () => {
1500
+ for (const timeout of timeouts.values()) {
1501
+ clearTimeout(timeout);
1502
+ }
1503
+ timeouts.clear();
1504
+ lastArgs.clear();
1505
+ lastCalls.clear();
1506
+ };
1507
+ return throttled;
1508
+ }
1472
1509
 
1473
1510
  // Auto-generated, do not edit
1474
1511
  /* eslint-disable */
@@ -4219,6 +4256,7 @@ class Observer {
4219
4256
  this.inlineRemoteCss = false;
4220
4257
  this.inlinerOptions = undefined;
4221
4258
  this.domParser = new DOMParser();
4259
+ this.throttledSetNodeData = throttleWithTrailing((id, parentElement, data) => this.sendNodeData(id, parentElement, data), 30);
4222
4260
  this.disableSprites = Boolean(options.disableSprites);
4223
4261
  this.inlineRemoteCss = Boolean(options.inlineRemoteCss);
4224
4262
  this.inlinerOptions = options.inlinerOptions;
@@ -4530,7 +4568,7 @@ class Observer {
4530
4568
  else if (isTextNode(node)) {
4531
4569
  // for text node id != 0, hence parentID !== undefined and parent is Element
4532
4570
  this.app.send(CreateTextNode(id, parentID, index));
4533
- this.sendNodeData(id, parent, node.data);
4571
+ this.throttledSetNodeData(id, parent, node.data);
4534
4572
  }
4535
4573
  return true;
4536
4574
  }
@@ -4551,7 +4589,7 @@ class Observer {
4551
4589
  throw 'commitNode: node is not a text';
4552
4590
  }
4553
4591
  // for text node id != 0, hence parent is Element
4554
- this.sendNodeData(id, parent, node.data);
4592
+ this.throttledSetNodeData(id, parent, node.data);
4555
4593
  }
4556
4594
  return true;
4557
4595
  }
@@ -4594,6 +4632,7 @@ class Observer {
4594
4632
  disconnect() {
4595
4633
  this.observer.disconnect();
4596
4634
  this.clear();
4635
+ this.throttledSetNodeData.clear();
4597
4636
  }
4598
4637
  }
4599
4638
 
@@ -5206,7 +5245,7 @@ class App {
5206
5245
  this.stopCallbacks = [];
5207
5246
  this.commitCallbacks = [];
5208
5247
  this.activityState = ActivityState.NotActive;
5209
- this.version = '16.3.0-beta.0'; // TODO: version compatability check inside each plugin.
5248
+ this.version = '16.3.0-beta.2'; // TODO: version compatability check inside each plugin.
5210
5249
  this.socketMode = false;
5211
5250
  this.compressionThreshold = 24 * 1000;
5212
5251
  this.bc = null;
@@ -8438,152 +8477,6 @@ function isObject(thing) {
8438
8477
  return thing !== null && typeof thing === 'object';
8439
8478
  }
8440
8479
 
8441
- const sensitiveParams = new Set([
8442
- "password",
8443
- "pass",
8444
- "pwd",
8445
- "mdp",
8446
- "token",
8447
- "bearer",
8448
- "jwt",
8449
- "api_key",
8450
- "api-key",
8451
- "apiKey",
8452
- "secret",
8453
- "ssn",
8454
- "zip",
8455
- "zipcode",
8456
- "x-api-key",
8457
- "www-authenticate",
8458
- "x-csrf-token",
8459
- "x-requested-with",
8460
- "x-forwarded-for",
8461
- "x-real-ip",
8462
- "cookie",
8463
- "authorization",
8464
- "auth",
8465
- "proxy-authorization",
8466
- "set-cookie",
8467
- "account_key",
8468
- ]);
8469
- function numDigits(x) {
8470
- return (Math.log10((x ^ (x >> 31)) - (x >> 31)) | 0) + 1;
8471
- }
8472
- function obscure(value) {
8473
- if (typeof value === "number") {
8474
- const digits = numDigits(value);
8475
- return "9".repeat(digits);
8476
- }
8477
- if (typeof value === "string") {
8478
- return value.replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff\s]/g, '*');
8479
- }
8480
- return value;
8481
- }
8482
- function filterHeaders(headers) {
8483
- const filteredHeaders = {};
8484
- if (Array.isArray(headers)) {
8485
- headers.forEach(({ name, value }) => {
8486
- if (sensitiveParams.has(name.toLowerCase())) {
8487
- filteredHeaders[name] = obscure(value);
8488
- }
8489
- else {
8490
- filteredHeaders[name] = value;
8491
- }
8492
- });
8493
- }
8494
- else {
8495
- for (const [key, value] of Object.entries(headers)) {
8496
- if (sensitiveParams.has(key.toLowerCase())) {
8497
- filteredHeaders[key] = obscure(value);
8498
- }
8499
- else {
8500
- filteredHeaders[key] = value;
8501
- }
8502
- }
8503
- }
8504
- return filteredHeaders;
8505
- }
8506
- function filterBody(body) {
8507
- if (!body) {
8508
- return body;
8509
- }
8510
- let parsedBody;
8511
- let isJSON = false;
8512
- try {
8513
- parsedBody = JSON.parse(body);
8514
- isJSON = true;
8515
- }
8516
- catch (e) {
8517
- // not json
8518
- }
8519
- if (isJSON) {
8520
- obscureSensitiveData(parsedBody);
8521
- return JSON.stringify(parsedBody);
8522
- }
8523
- else {
8524
- const isUrlSearch = typeof body === "string" && body.includes("?") && body.includes("=");
8525
- if (isUrlSearch) {
8526
- try {
8527
- const params = new URLSearchParams(body);
8528
- for (const key of params.keys()) {
8529
- if (sensitiveParams.has(key.toLowerCase())) {
8530
- const value = obscure(params.get(key));
8531
- params.set(key, value);
8532
- }
8533
- }
8534
- return params.toString();
8535
- }
8536
- catch (e) {
8537
- // not url query ?
8538
- return body;
8539
- }
8540
- }
8541
- else {
8542
- // not json or url query
8543
- return body;
8544
- }
8545
- }
8546
- }
8547
- function sanitizeObject(obj) {
8548
- obscureSensitiveData(obj);
8549
- return obj;
8550
- }
8551
- function obscureSensitiveData(obj) {
8552
- if (Array.isArray(obj)) {
8553
- obj.forEach(obscureSensitiveData);
8554
- }
8555
- else if (obj && typeof obj === "object") {
8556
- for (const key in obj) {
8557
- if (Object.hasOwn(obj, key)) {
8558
- if (sensitiveParams.has(key.toLowerCase())) {
8559
- obj[key] = obscure(obj[key]);
8560
- }
8561
- else if (obj[key] !== null && typeof obj[key] === "object") {
8562
- obscureSensitiveData(obj[key]);
8563
- }
8564
- }
8565
- }
8566
- }
8567
- }
8568
- function tryFilterUrl(url) {
8569
- if (!url)
8570
- return "";
8571
- try {
8572
- const urlObj = new URL(url);
8573
- if (urlObj.searchParams) {
8574
- for (const key of urlObj.searchParams.keys()) {
8575
- if (sensitiveParams.has(key.toLowerCase())) {
8576
- urlObj.searchParams.set(key, "******");
8577
- }
8578
- }
8579
- }
8580
- return urlObj.toString();
8581
- }
8582
- catch (e) {
8583
- return url;
8584
- }
8585
- }
8586
-
8587
8480
  /**
8588
8481
  * I know we're not using most of the information from this class
8589
8482
  * but it can be useful in the future if we will decide to display more stuff in our ui
@@ -8615,18 +8508,13 @@ class NetworkMessage {
8615
8508
  }
8616
8509
  getMessage() {
8617
8510
  const { reqHs, resHs } = this.writeHeaders();
8618
- const reqBody = this.method === 'GET'
8619
- ? JSON.stringify(sanitizeObject(this.getData)) : filterBody(this.requestData);
8620
8511
  const request = {
8621
- headers: filterHeaders(reqHs),
8622
- body: reqBody,
8623
- };
8624
- const response = {
8625
- headers: filterHeaders(resHs),
8626
- body: filterBody(this.response)
8512
+ headers: reqHs,
8513
+ body: this.method === 'GET' ? JSON.stringify(this.getData) : this.requestData,
8627
8514
  };
8515
+ const response = { headers: resHs, body: this.response };
8628
8516
  const messageInfo = this.sanitize({
8629
- url: tryFilterUrl(this.url),
8517
+ url: this.url,
8630
8518
  method: this.method,
8631
8519
  status: this.status,
8632
8520
  request,
@@ -8942,10 +8830,9 @@ class ResponseProxyHandler {
8942
8830
  if (typeof this.resp.body.getReader !== 'function') {
8943
8831
  return;
8944
8832
  }
8945
- const clonedResp = this.resp.clone();
8946
- const _getReader = clonedResp.body.getReader;
8833
+ const _getReader = this.resp.body.getReader;
8947
8834
  // @ts-ignore
8948
- clonedResp.body.getReader = () => {
8835
+ this.resp.body.getReader = () => {
8949
8836
  const reader = _getReader.apply(this.resp.body);
8950
8837
  // when readyState is already 4,
8951
8838
  // it's not a chunked stream, or it had already been read.
@@ -9787,7 +9674,7 @@ class API {
9787
9674
  this.signalStartIssue = (reason, missingApi) => {
9788
9675
  const doNotTrack = this.checkDoNotTrack();
9789
9676
  console.log("Tracker couldn't start due to:", JSON.stringify({
9790
- trackerVersion: '16.3.0-beta.0',
9677
+ trackerVersion: '16.3.0-beta.2',
9791
9678
  projectKey: this.options.projectKey,
9792
9679
  doNotTrack,
9793
9680
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,