@openreplay/tracker 4.1.10 → 4.1.11

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.
Files changed (71) hide show
  1. package/.eslintignore +0 -3
  2. package/README.md +18 -22
  3. package/cjs/app/guards.d.ts +12 -11
  4. package/cjs/app/guards.js +1 -2
  5. package/cjs/app/index.d.ts +8 -11
  6. package/cjs/app/index.js +8 -27
  7. package/cjs/app/logger.d.ts +3 -3
  8. package/cjs/app/messages.d.ts +52 -0
  9. package/cjs/app/messages.gen.d.ts +6 -8
  10. package/cjs/app/messages.gen.js +94 -116
  11. package/cjs/app/messages.js +234 -0
  12. package/cjs/app/nodes.d.ts +1 -1
  13. package/cjs/app/observer/iframe_offsets.d.ts +1 -1
  14. package/cjs/app/observer/observer.js +5 -5
  15. package/cjs/app/observer/top_observer.d.ts +2 -2
  16. package/cjs/app/observer/top_observer.js +1 -1
  17. package/cjs/app/session.d.ts +2 -2
  18. package/cjs/app/ticker.d.ts +1 -1
  19. package/cjs/common/interaction.d.ts +5 -5
  20. package/cjs/common/messages.gen.d.ts +86 -104
  21. package/cjs/index.d.ts +2 -6
  22. package/cjs/index.js +5 -7
  23. package/cjs/modules/cssrules.js +1 -1
  24. package/cjs/modules/focus.js +2 -2
  25. package/cjs/modules/fonts.js +2 -2
  26. package/cjs/modules/img.js +5 -6
  27. package/cjs/modules/input.d.ts +1 -1
  28. package/cjs/modules/input.js +23 -15
  29. package/cjs/modules/mouse.js +1 -1
  30. package/cjs/modules/timing.js +3 -7
  31. package/cjs/modules/viewport.js +1 -3
  32. package/cjs/vendors/finder/finder.d.ts +1 -1
  33. package/lib/app/guards.d.ts +12 -11
  34. package/lib/app/guards.js +1 -2
  35. package/lib/app/index.d.ts +8 -11
  36. package/lib/app/index.js +9 -28
  37. package/lib/app/logger.d.ts +3 -3
  38. package/lib/app/messages.d.ts +52 -0
  39. package/lib/app/messages.gen.d.ts +6 -8
  40. package/lib/app/messages.gen.js +87 -107
  41. package/lib/app/messages.js +181 -0
  42. package/lib/app/nodes.d.ts +1 -1
  43. package/lib/app/observer/iframe_offsets.d.ts +1 -1
  44. package/lib/app/observer/observer.js +5 -5
  45. package/lib/app/observer/top_observer.d.ts +2 -2
  46. package/lib/app/observer/top_observer.js +1 -1
  47. package/lib/app/session.d.ts +2 -2
  48. package/lib/app/ticker.d.ts +1 -1
  49. package/lib/common/interaction.d.ts +5 -5
  50. package/lib/common/messages.gen.d.ts +86 -104
  51. package/lib/common/tsconfig.tsbuildinfo +1 -1
  52. package/lib/index.d.ts +2 -6
  53. package/lib/index.js +6 -8
  54. package/lib/modules/cssrules.js +1 -1
  55. package/lib/modules/focus.js +2 -2
  56. package/lib/modules/fonts.js +2 -2
  57. package/lib/modules/img.js +5 -6
  58. package/lib/modules/input.d.ts +1 -1
  59. package/lib/modules/input.js +23 -15
  60. package/lib/modules/mouse.js +1 -1
  61. package/lib/modules/timing.js +4 -8
  62. package/lib/modules/viewport.js +1 -3
  63. package/lib/vendors/finder/finder.d.ts +1 -1
  64. package/package.json +3 -8
  65. package/tsconfig-base.json +1 -2
  66. package/CHANGELOG.md +0 -19
  67. package/cjs/modules/network.d.ts +0 -28
  68. package/cjs/modules/network.js +0 -203
  69. package/jest.config.js +0 -11
  70. package/lib/modules/network.d.ts +0 -28
  71. package/lib/modules/network.js +0 -200
package/lib/index.d.ts CHANGED
@@ -9,16 +9,14 @@ import type { Options as ExceptionOptions } from './modules/exception.js';
9
9
  import type { Options as InputOptions } from './modules/input.js';
10
10
  import type { Options as PerformanceOptions } from './modules/performance.js';
11
11
  import type { Options as TimingOptions } from './modules/timing.js';
12
- import type { Options as NetworkOptions } from './modules/network.js';
13
12
  import type { StartOptions } from './app/index.js';
14
13
  import type { StartPromiseReturn } from './app/index.js';
15
- export type Options = Partial<AppOptions & ConsoleOptions & ExceptionOptions & InputOptions & PerformanceOptions & TimingOptions> & {
14
+ export declare type Options = Partial<AppOptions & ConsoleOptions & ExceptionOptions & InputOptions & PerformanceOptions & TimingOptions> & {
16
15
  projectID?: number;
17
16
  projectKey: string;
18
17
  sessionToken?: string;
19
18
  respectDoNotTrack?: boolean;
20
19
  autoResetOnWindowOpen?: boolean;
21
- network?: NetworkOptions;
22
20
  __DISABLE_SECURE_MODE?: boolean;
23
21
  };
24
22
  export default class API {
@@ -32,9 +30,7 @@ export default class API {
32
30
  getSessionToken(): string | null | undefined;
33
31
  getSessionID(): string | null | undefined;
34
32
  sessionID(): string | null | undefined;
35
- getSessionURL(options?: {
36
- withCurrentTime?: boolean;
37
- }): string | undefined;
33
+ getSessionURL(): string | undefined;
38
34
  setUserID(id: string): void;
39
35
  userID(id: string): void;
40
36
  setUserAnonymousID(id: string): void;
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import App, { DEFAULT_INGEST_POINT } from './app/index.js';
2
2
  export { default as App } from './app/index.js';
3
- import { UserAnonymousID, CustomEvent, CustomIssue } from './app/messages.gen.js';
3
+ import { UserAnonymousID, RawCustomEvent, CustomIssue } from './app/messages.gen.js';
4
4
  import * as _Messages from './app/messages.gen.js';
5
5
  export const Messages = _Messages;
6
6
  export { SanitizeLevel } from './app/sanitizer.js';
@@ -17,10 +17,9 @@ import Viewport from './modules/viewport.js';
17
17
  import CSSRules from './modules/cssrules.js';
18
18
  import Focus from './modules/focus.js';
19
19
  import Fonts from './modules/fonts.js';
20
- import Network from './modules/network.js';
21
20
  import ConstructedStyleSheets from './modules/constructedStyleSheets.js';
22
21
  import { IN_BROWSER, deprecationWarn, DOCS_HOST } from './utils.js';
23
- const DOCS_SETUP = '/installation/javascript-sdk';
22
+ const DOCS_SETUP = '/installation/setup-or';
24
23
  function processOptions(obj) {
25
24
  if (obj == null) {
26
25
  console.error(`OpenReplay: invalid options argument type. Please, check documentation on ${DOCS_HOST}${DOCS_SETUP}`);
@@ -110,7 +109,6 @@ export default class API {
110
109
  Scroll(app);
111
110
  Focus(app);
112
111
  Fonts(app);
113
- Network(app, options.network);
114
112
  window.__OPENREPLAY__ = this;
115
113
  if (options.autoResetOnWindowOpen) {
116
114
  const wOpen = window.open;
@@ -135,7 +133,7 @@ export default class API {
135
133
  // no-cors issue only with text/plain or not-set Content-Type
136
134
  // req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
137
135
  req.send(JSON.stringify({
138
- trackerVersion: '4.1.10',
136
+ trackerVersion: '4.1.11',
139
137
  projectKey: options.projectKey,
140
138
  doNotTrack,
141
139
  // TODO: add precise reason (an exact API missing)
@@ -185,11 +183,11 @@ export default class API {
185
183
  deprecationWarn("'sessionID' method", "'getSessionID' method", '/');
186
184
  return this.getSessionID();
187
185
  }
188
- getSessionURL(options) {
186
+ getSessionURL() {
189
187
  if (this.app === null) {
190
188
  return undefined;
191
189
  }
192
- return this.app.getSessionURL(options);
190
+ return this.app.getSessionURL();
193
191
  }
194
192
  setUserID(id) {
195
193
  if (typeof id === 'string' && this.app !== null) {
@@ -230,7 +228,7 @@ export default class API {
230
228
  catch (e) {
231
229
  return;
232
230
  }
233
- this.app.send(CustomEvent(key, payload));
231
+ this.app.send(RawCustomEvent(key, payload));
234
232
  }
235
233
  }
236
234
  }
@@ -75,7 +75,7 @@ export default function (app) {
75
75
  patchContext(window);
76
76
  app.observer.attachContextCallback(patchContext);
77
77
  app.nodes.attachNodeCallback((node) => {
78
- if (!hasTag(node, 'style') || !node.sheet) {
78
+ if (!(hasTag(node, 'STYLE') || hasTag(node, 'style')) || !node.sheet) {
79
79
  return;
80
80
  }
81
81
  if (node.textContent !== null && node.textContent.trim().length > 0) {
@@ -9,7 +9,7 @@ export default function (app) {
9
9
  }
10
10
  let blurred = false;
11
11
  app.nodes.attachNodeCallback((node) => {
12
- if (!hasTag(node, 'body')) {
12
+ if (!hasTag(node, 'BODY')) {
13
13
  return;
14
14
  }
15
15
  app.nodes.attachNodeListener(node, 'focus', (e) => {
@@ -32,7 +32,7 @@ export default function (app) {
32
32
  });
33
33
  app.attachStartCallback(() => {
34
34
  let elem = document.activeElement;
35
- while (elem && hasTag(elem, 'iframe') && elem.contentDocument) {
35
+ while (elem && hasTag(elem, 'IFRAME') && elem.contentDocument) {
36
36
  elem = elem.contentDocument.activeElement;
37
37
  }
38
38
  if (elem && elem !== elem.ownerDocument.body) {
@@ -35,7 +35,7 @@ export default function (app) {
35
35
  };
36
36
  app.observer.attachContextCallback(patchWindow);
37
37
  patchWindow(window);
38
- app.nodes.attachNodeCallback(app.safe((node) => {
38
+ app.nodes.attachNodeCallback((node) => {
39
39
  if (!isDocument(node)) {
40
40
  return;
41
41
  }
@@ -50,5 +50,5 @@ export default function (app) {
50
50
  ffDataArr.forEach((ffData) => {
51
51
  app.send(LoadFontFace(parentID, ...ffData));
52
52
  });
53
- }));
53
+ });
54
54
  }
@@ -3,16 +3,15 @@ import { ResourceTiming, SetNodeAttributeURLBased, SetNodeAttribute } from '../a
3
3
  import { hasTag } from '../app/guards.js';
4
4
  function resolveURL(url, location = document.location) {
5
5
  url = url.trim();
6
- if (url.startsWith('//') ||
7
- url.startsWith('http://') ||
6
+ if (url.startsWith('/')) {
7
+ return location.origin + url;
8
+ }
9
+ else if (url.startsWith('http://') ||
8
10
  url.startsWith('https://') ||
9
11
  url.startsWith('data:') // any other possible value here? https://bugzilla.mozilla.org/show_bug.cgi?id=1758035
10
12
  ) {
11
13
  return url;
12
14
  }
13
- else if (url.startsWith('/')) {
14
- return location.origin + url;
15
- }
16
15
  else {
17
16
  return location.origin + location.pathname + url;
18
17
  }
@@ -96,7 +95,7 @@ export default function (app) {
96
95
  observer.disconnect();
97
96
  });
98
97
  app.nodes.attachNodeCallback((node) => {
99
- if (!hasTag(node, 'img')) {
98
+ if (!hasTag(node, 'IMG')) {
100
99
  return;
101
100
  }
102
101
  app.nodes.attachNodeListener(node, 'error', () => sendImgError(node));
@@ -1,5 +1,5 @@
1
1
  import type App from '../app/index.js';
2
- type TextEditableElement = HTMLInputElement | HTMLTextAreaElement;
2
+ declare type TextEditableElement = HTMLInputElement | HTMLTextAreaElement;
3
3
  export declare function getInputLabel(node: TextEditableElement): string;
4
4
  export declare const enum InputMode {
5
5
  Plain = 0,
@@ -1,18 +1,18 @@
1
1
  import { normSpaces, IN_BROWSER, getLabelAttribute } from '../utils.js';
2
2
  import { hasTag } from '../app/guards.js';
3
3
  import { SetInputTarget, SetInputValue, SetInputChecked } from '../app/messages.gen.js';
4
- const INPUT_TYPES = ['text', 'password', 'email', 'search', 'number', 'range', 'date', 'tel'];
4
+ const INPUT_TYPES = ['text', 'password', 'email', 'search', 'number', 'range', 'date'];
5
5
  function isTextEditable(node) {
6
- if (hasTag(node, 'textarea')) {
6
+ if (hasTag(node, 'TEXTAREA')) {
7
7
  return true;
8
8
  }
9
- if (!hasTag(node, 'input')) {
9
+ if (!hasTag(node, 'INPUT')) {
10
10
  return false;
11
11
  }
12
12
  return INPUT_TYPES.includes(node.type);
13
13
  }
14
14
  function isCheckable(node) {
15
- if (!hasTag(node, 'input')) {
15
+ if (!hasTag(node, 'INPUT')) {
16
16
  return false;
17
17
  }
18
18
  const type = node.type;
@@ -22,7 +22,7 @@ const labelElementFor = IN_BROWSER && 'labels' in HTMLInputElement.prototype
22
22
  ? (node) => {
23
23
  let p = node;
24
24
  while ((p = p.parentNode) !== null) {
25
- if (hasTag(p, 'label')) {
25
+ if (hasTag(p, 'LABEL')) {
26
26
  return p;
27
27
  }
28
28
  }
@@ -34,7 +34,7 @@ const labelElementFor = IN_BROWSER && 'labels' in HTMLInputElement.prototype
34
34
  : (node) => {
35
35
  let p = node;
36
36
  while ((p = p.parentNode) !== null) {
37
- if (hasTag(p, 'label')) {
37
+ if (hasTag(p, 'LABEL')) {
38
38
  return p;
39
39
  }
40
40
  }
@@ -64,7 +64,7 @@ export default function (app, opts) {
64
64
  const options = Object.assign({
65
65
  obscureInputNumbers: true,
66
66
  obscureInputEmails: true,
67
- defaultInputMode: 0 /* InputMode.Plain */,
67
+ defaultInputMode: 0 /* Plain */,
68
68
  obscureInputDates: false,
69
69
  }, opts);
70
70
  function sendInputTarget(id, node) {
@@ -77,22 +77,22 @@ export default function (app, opts) {
77
77
  let value = node.value;
78
78
  let inputMode = options.defaultInputMode;
79
79
  if (node.type === 'password' || app.sanitizer.isHidden(id)) {
80
- inputMode = 2 /* InputMode.Hidden */;
80
+ inputMode = 2 /* Hidden */;
81
81
  }
82
82
  else if (app.sanitizer.isObscured(id) ||
83
- (inputMode === 0 /* InputMode.Plain */ &&
83
+ (inputMode === 0 /* Plain */ &&
84
84
  ((options.obscureInputNumbers && node.type !== 'date' && /\d\d\d\d/.test(value)) ||
85
85
  (options.obscureInputDates && node.type === 'date') ||
86
86
  (options.obscureInputEmails && (node.type === 'email' || !!~value.indexOf('@')))))) {
87
- inputMode = 1 /* InputMode.Obscured */;
87
+ inputMode = 1 /* Obscured */;
88
88
  }
89
89
  let mask = 0;
90
90
  switch (inputMode) {
91
- case 2 /* InputMode.Hidden */:
91
+ case 2 /* Hidden */:
92
92
  mask = -1;
93
93
  value = '';
94
94
  break;
95
- case 1 /* InputMode.Obscured */:
95
+ case 1 /* Obscured */:
96
96
  mask = value.length;
97
97
  value = '';
98
98
  break;
@@ -111,7 +111,11 @@ export default function (app, opts) {
111
111
  inputValues.forEach((value, id) => {
112
112
  const node = app.nodes.getNode(id);
113
113
  if (!node)
114
- return inputValues.delete(id);
114
+ return;
115
+ if (!isTextEditable(node)) {
116
+ inputValues.delete(id);
117
+ return;
118
+ }
115
119
  if (value !== node.value) {
116
120
  inputValues.set(id, node.value);
117
121
  if (!registeredTargets.has(id)) {
@@ -124,7 +128,11 @@ export default function (app, opts) {
124
128
  checkableValues.forEach((checked, id) => {
125
129
  const node = app.nodes.getNode(id);
126
130
  if (!node)
127
- return checkableValues.delete(id);
131
+ return;
132
+ if (!isCheckable(node)) {
133
+ checkableValues.delete(id);
134
+ return;
135
+ }
128
136
  if (checked !== node.checked) {
129
137
  checkableValues.set(id, node.checked);
130
138
  app.send(SetInputChecked(id, node.checked));
@@ -138,7 +146,7 @@ export default function (app, opts) {
138
146
  return;
139
147
  }
140
148
  // TODO: support multiple select (?): use selectedOptions; Need send target?
141
- if (hasTag(node, 'select')) {
149
+ if (hasTag(node, 'SELECT')) {
142
150
  sendInputValue(id, node);
143
151
  app.attachEventListener(node, 'change', () => {
144
152
  sendInputValue(id, node);
@@ -78,7 +78,7 @@ export default function (app) {
78
78
  if (dl !== null) {
79
79
  return dl;
80
80
  }
81
- if (hasTag(target, 'input')) {
81
+ if (hasTag(target, 'INPUT')) {
82
82
  return getInputLabel(target);
83
83
  }
84
84
  if (isClickable(target)) {
@@ -1,5 +1,5 @@
1
1
  import { hasTag } from '../app/guards.js';
2
- import { isURL, getTimeOrigin } from '../utils.js';
2
+ import { isURL } from '../utils.js';
3
3
  import { ResourceTiming, PageLoadTiming, PageRenderTiming } from '../app/messages.gen.js';
4
4
  function getPaintBlocks(resources) {
5
5
  const paintBlocks = [];
@@ -8,7 +8,7 @@ function getPaintBlocks(resources) {
8
8
  for (let i = 0; i < elements.length; i++) {
9
9
  const element = elements[i];
10
10
  let src = '';
11
- if (hasTag(element, 'img')) {
11
+ if (hasTag(element, 'IMG')) {
12
12
  src = element.currentSrc || element.src;
13
13
  }
14
14
  if (!src) {
@@ -73,7 +73,7 @@ export default function (app, opts) {
73
73
  if (resources !== null) {
74
74
  resources[entry.name] = entry.startTime + entry.duration;
75
75
  }
76
- app.send(ResourceTiming(entry.startTime + getTimeOrigin(), entry.duration, entry.responseStart && entry.startTime ? entry.responseStart - entry.startTime : 0, entry.transferSize > entry.encodedBodySize ? entry.transferSize - entry.encodedBodySize : 0, entry.encodedBodySize || 0, entry.decodedBodySize || 0, entry.name, entry.initiatorType));
76
+ app.send(ResourceTiming(entry.startTime + performance.timing.navigationStart, entry.duration, entry.responseStart && entry.startTime ? entry.responseStart - entry.startTime : 0, entry.transferSize > entry.encodedBodySize ? entry.transferSize - entry.encodedBodySize : 0, entry.encodedBodySize || 0, entry.decodedBodySize || 0, entry.name, entry.initiatorType));
77
77
  }
78
78
  const observer = new PerformanceObserver((list) => list.getEntries().forEach(resourceTiming));
79
79
  let prevSessionID;
@@ -110,11 +110,7 @@ export default function (app, opts) {
110
110
  }
111
111
  if (performance.timing.loadEventEnd || performance.now() > 30000) {
112
112
  pageLoadTimingSent = true;
113
- const {
114
- // should be ok to use here, (https://github.com/mdn/content/issues/4713)
115
- // since it is compared with the values obtained on the page load (before any possible sleep state)
116
- // deprecated though
117
- navigationStart, requestStart, responseStart, responseEnd, domContentLoadedEventStart, domContentLoadedEventEnd, loadEventStart, loadEventEnd, } = performance.timing;
113
+ const { navigationStart, requestStart, responseStart, responseEnd, domContentLoadedEventStart, domContentLoadedEventEnd, loadEventStart, loadEventEnd, } = performance.timing;
118
114
  app.send(PageLoadTiming(requestStart - navigationStart || 0, responseStart - navigationStart || 0, responseEnd - navigationStart || 0, domContentLoadedEventStart - navigationStart || 0, domContentLoadedEventEnd - navigationStart || 0, loadEventStart - navigationStart || 0, loadEventEnd - navigationStart || 0, firstPaint, firstContentfulPaint));
119
115
  }
120
116
  }, 30);
@@ -3,14 +3,12 @@ import { SetPageLocation, SetViewportSize, SetPageVisibility } from '../app/mess
3
3
  export default function (app) {
4
4
  let url, width, height;
5
5
  let navigationStart;
6
- let referrer = document.referrer;
7
6
  const sendSetPageLocation = app.safe(() => {
8
7
  const { URL } = document;
9
8
  if (URL !== url) {
10
9
  url = URL;
11
- app.send(SetPageLocation(url, referrer, navigationStart));
10
+ app.send(SetPageLocation(url, document.referrer, navigationStart));
12
11
  navigationStart = 0;
13
- referrer = url;
14
12
  }
15
13
  });
16
14
  const sendSetViewportSize = app.safe(() => {
@@ -1,4 +1,4 @@
1
- export type Options = {
1
+ export declare type Options = {
2
2
  root: Element;
3
3
  idName: (name: string) => boolean;
4
4
  className: (name: string) => boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openreplay/tracker",
3
3
  "description": "The OpenReplay tracker main package",
4
- "version": "4.1.10",
4
+ "version": "4.1.11",
5
5
  "keywords": [
6
6
  "logging",
7
7
  "replay"
@@ -21,12 +21,10 @@
21
21
  "compile": "node --experimental-modules --experimental-json-modules scripts/compile.cjs",
22
22
  "build": "npm run clean && npm run tscRun && npm run rollup && npm run compile",
23
23
  "prepare": "cd ../../ && husky install tracker/.husky/",
24
- "lint-front": "lint-staged",
25
- "test": "jest"
24
+ "lint-front": "lint-staged"
26
25
  },
27
26
  "devDependencies": {
28
27
  "@babel/core": "^7.10.2",
29
- "@jest/globals": "^29.3.1",
30
28
  "@rollup/plugin-babel": "^5.0.3",
31
29
  "@rollup/plugin-node-resolve": "^10.0.0",
32
30
  "@typescript-eslint/eslint-plugin": "^5.30.0",
@@ -35,16 +33,13 @@
35
33
  "eslint-config-prettier": "^8.5.0",
36
34
  "eslint-plugin-prettier": "^4.2.1",
37
35
  "husky": "^8.0.1",
38
- "jest": "^29.3.1",
39
- "jest-environment-jsdom": "^29.3.1",
40
36
  "lint-staged": "^13.0.3",
41
37
  "prettier": "^2.7.1",
42
38
  "replace-in-files": "^2.0.3",
43
39
  "rollup": "^2.17.0",
44
40
  "rollup-plugin-terser": "^6.1.0",
45
41
  "semver": "^6.3.0",
46
- "ts-jest": "^29.0.3",
47
- "typescript": "^4.9.4"
42
+ "typescript": "4.6.0-dev.20211126"
48
43
  },
49
44
  "dependencies": {
50
45
  "error-stack-parser": "^2.0.6"
@@ -10,6 +10,5 @@
10
10
  "target": "es6",
11
11
  "module": "es6",
12
12
  "moduleResolution": "nodenext"
13
- },
14
- "exclude": ["**/*.test.ts"]
13
+ }
15
14
  }
package/CHANGELOG.md DELETED
@@ -1,19 +0,0 @@
1
- ## 4.1.10
2
-
3
- - Added "tel" to supported input types
4
- - Added `{ withCurrentTime: true }` to `tracker.getSessionURL` method which will return sessionURL with current session's timestamp
5
- - Added Network module that captures fetch/xhr by default (with no plugin required)
6
- - Use `timeOrigin()` instead of `performance.timing.navigationStart` in ResourceTiming messages
7
- - Added app restart when service worker died after inactivity (mobile safari)
8
-
9
- ## 4.1.8
10
-
11
- - recalculate timeOrigin on start to prevent wrong timestamps on "sleeping" sessions
12
-
13
- ## 4.1.7
14
-
15
- - resend metadata on start
16
-
17
- ## 4.1.6
18
-
19
- - remove log that potentially caused crashed during slow initial render
@@ -1,28 +0,0 @@
1
- import type App from '../app/index.js';
2
- type XHRRequestBody = Parameters<XMLHttpRequest['send']>[0];
3
- type FetchRequestBody = RequestInit['body'];
4
- interface RequestData {
5
- body: XHRRequestBody | FetchRequestBody;
6
- headers: Record<string, string>;
7
- }
8
- interface ResponseData {
9
- body: any;
10
- headers: Record<string, string>;
11
- }
12
- interface RequestResponseData {
13
- readonly status: number;
14
- readonly method: string;
15
- url: string;
16
- request: RequestData;
17
- response: ResponseData;
18
- }
19
- type Sanitizer = (data: RequestResponseData) => RequestResponseData | null;
20
- export interface Options {
21
- sessionTokenHeader: string | boolean;
22
- failuresOnly: boolean;
23
- ignoreHeaders: Array<string> | boolean;
24
- capturePayload: boolean;
25
- sanitizer?: Sanitizer;
26
- }
27
- export default function (app: App, opts?: Partial<Options>): void;
28
- export {};
@@ -1,203 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const messages_gen_js_1 = require("../app/messages.gen.js");
4
- const utils_js_1 = require("../utils.js");
5
- function getXHRRequestDataObject(xhr) {
6
- // @ts-ignore this is 3x faster than using Map<XHR, XHRRequestData>
7
- if (!xhr.__or_req_data__) {
8
- // @ts-ignore
9
- xhr.__or_req_data__ = { body: undefined, headers: {} };
10
- }
11
- // @ts-ignore
12
- return xhr.__or_req_data__;
13
- }
14
- function strMethod(method) {
15
- return typeof method === 'string' ? method.toUpperCase() : 'GET';
16
- }
17
- function default_1(app, opts = {}) {
18
- const options = Object.assign({
19
- failuresOnly: false,
20
- ignoreHeaders: ['Cookie', 'Set-Cookie', 'Authorization'],
21
- capturePayload: false,
22
- sessionTokenHeader: false,
23
- }, opts);
24
- const ignoreHeaders = options.ignoreHeaders;
25
- const isHIgnored = Array.isArray(ignoreHeaders)
26
- ? (name) => ignoreHeaders.includes(name)
27
- : () => ignoreHeaders;
28
- const stHeader = options.sessionTokenHeader === true ? 'X-OpenReplay-SessionToken' : options.sessionTokenHeader;
29
- function setSessionTokenHeader(setRequestHeader) {
30
- if (stHeader) {
31
- const sessionToken = app.getSessionToken();
32
- if (sessionToken) {
33
- app.safe(setRequestHeader)(stHeader, sessionToken);
34
- }
35
- }
36
- }
37
- function sanitize(reqResInfo) {
38
- if (!options.capturePayload) {
39
- delete reqResInfo.request.body;
40
- delete reqResInfo.response.body;
41
- }
42
- if (options.sanitizer) {
43
- const resBody = reqResInfo.response.body;
44
- if (typeof resBody === 'string') {
45
- // Parse response in order to have handy view in sanitisation function
46
- try {
47
- reqResInfo.response.body = JSON.parse(resBody);
48
- }
49
- catch (_a) { }
50
- }
51
- return options.sanitizer(reqResInfo);
52
- }
53
- return reqResInfo;
54
- }
55
- function stringify(r) {
56
- if (r && typeof r.body !== 'string') {
57
- try {
58
- r.body = JSON.stringify(r.body);
59
- }
60
- catch (_a) {
61
- r.body = '<unable to stringify>';
62
- app.notify.warn("Openreplay fetch couldn't stringify body:", r.body);
63
- }
64
- }
65
- return JSON.stringify(r);
66
- }
67
- /* ====== Fetch ====== */
68
- const origFetch = window.fetch.bind(window);
69
- window.fetch = (input, init = {}) => {
70
- if (!(typeof input === 'string' || input instanceof URL) || app.isServiceURL(String(input))) {
71
- return origFetch(input, init);
72
- }
73
- setSessionTokenHeader(function (name, value) {
74
- if (init.headers === undefined) {
75
- init.headers = {};
76
- }
77
- if (init.headers instanceof Headers) {
78
- init.headers.append(name, value);
79
- }
80
- else if (Array.isArray(init.headers)) {
81
- init.headers.push([name, value]);
82
- }
83
- else {
84
- init.headers[name] = value;
85
- }
86
- });
87
- const startTime = performance.now();
88
- return origFetch(input, init).then((response) => {
89
- const duration = performance.now() - startTime;
90
- if (options.failuresOnly && response.status < 400) {
91
- return response;
92
- }
93
- const r = response.clone();
94
- r.text()
95
- .then((text) => {
96
- const reqHs = {};
97
- const resHs = {};
98
- if (ignoreHeaders !== true) {
99
- // request headers
100
- const writeReqHeader = ([n, v]) => {
101
- if (!isHIgnored(n)) {
102
- reqHs[n] = v;
103
- }
104
- };
105
- if (init.headers instanceof Headers) {
106
- init.headers.forEach((v, n) => writeReqHeader([n, v]));
107
- }
108
- else if (Array.isArray(init.headers)) {
109
- init.headers.forEach(writeReqHeader);
110
- }
111
- else if (typeof init.headers === 'object') {
112
- Object.entries(init.headers).forEach(writeReqHeader);
113
- }
114
- // response headers
115
- r.headers.forEach((v, n) => {
116
- if (!isHIgnored(n))
117
- resHs[n] = v;
118
- });
119
- }
120
- const method = strMethod(init.method);
121
- const reqResInfo = sanitize({
122
- url: String(input),
123
- method,
124
- status: r.status,
125
- request: {
126
- headers: reqHs,
127
- body: init.body,
128
- },
129
- response: {
130
- headers: resHs,
131
- body: text,
132
- },
133
- });
134
- if (!reqResInfo) {
135
- return;
136
- }
137
- app.send((0, messages_gen_js_1.NetworkRequest)('fetch', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), r.status, startTime + (0, utils_js_1.getTimeOrigin)(), duration));
138
- })
139
- .catch((e) => app.debug.error('Could not process Fetch response:', e));
140
- return response;
141
- });
142
- };
143
- /* ====== <> ====== */
144
- /* ====== XHR ====== */
145
- const nativeOpen = XMLHttpRequest.prototype.open;
146
- XMLHttpRequest.prototype.open = function (initMethod, url) {
147
- const xhr = this;
148
- setSessionTokenHeader((name, value) => xhr.setRequestHeader(name, value));
149
- let startTime = 0;
150
- xhr.addEventListener('loadstart', (e) => {
151
- startTime = e.timeStamp;
152
- });
153
- xhr.addEventListener('load', app.safe((e) => {
154
- const { headers: reqHs, body: reqBody } = getXHRRequestDataObject(xhr);
155
- const duration = startTime > 0 ? e.timeStamp - startTime : 0;
156
- const hString = ignoreHeaders ? '' : xhr.getAllResponseHeaders(); // might be null (though only if no response received though)
157
- const resHs = hString
158
- ? hString
159
- .split('\r\n')
160
- .map((h) => h.split(':'))
161
- .filter((entry) => !isHIgnored(entry[0]))
162
- .reduce((hds, [name, value]) => (Object.assign(Object.assign({}, hds), { [name]: value })), {})
163
- : {};
164
- const method = strMethod(initMethod);
165
- const reqResInfo = sanitize({
166
- url: String(url),
167
- method,
168
- status: xhr.status,
169
- request: {
170
- headers: reqHs,
171
- body: reqBody,
172
- },
173
- response: {
174
- headers: resHs,
175
- body: xhr.response,
176
- },
177
- });
178
- if (!reqResInfo) {
179
- return;
180
- }
181
- app.send((0, messages_gen_js_1.NetworkRequest)('xhr', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), xhr.status, startTime + (0, utils_js_1.getTimeOrigin)(), duration));
182
- }));
183
- //TODO: handle error (though it has no Error API nor any useful information)
184
- //xhr.addEventListener('error', (e) => {})
185
- return nativeOpen.apply(this, arguments);
186
- };
187
- const nativeSend = XMLHttpRequest.prototype.send;
188
- XMLHttpRequest.prototype.send = function (body) {
189
- const rdo = getXHRRequestDataObject(this);
190
- rdo.body = body;
191
- return nativeSend.apply(this, arguments);
192
- };
193
- const nativeSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
194
- XMLHttpRequest.prototype.setRequestHeader = function (name, value) {
195
- if (!isHIgnored(name)) {
196
- const rdo = getXHRRequestDataObject(this);
197
- rdo.headers[name] = value;
198
- }
199
- return nativeSetRequestHeader.apply(this, arguments);
200
- };
201
- /* ====== <> ====== */
202
- }
203
- exports.default = default_1;