@newrelic/browser-agent 1.250.0 → 1.251.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.
Files changed (98) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/common/config/state/init.js +0 -2
  3. package/dist/cjs/common/config/state/originals.js +1 -2
  4. package/dist/cjs/common/constants/env.cdn.js +4 -8
  5. package/dist/cjs/common/constants/env.js +4 -8
  6. package/dist/cjs/common/constants/env.npm.js +4 -8
  7. package/dist/cjs/common/constants/runtime.js +13 -24
  8. package/dist/cjs/common/constants/shared-channel.js +2 -3
  9. package/dist/cjs/common/event-emitter/contextual-ee.js +2 -4
  10. package/dist/cjs/common/event-emitter/handle.js +1 -2
  11. package/dist/cjs/common/harvest/harvest-scheduler.js +2 -2
  12. package/dist/cjs/common/harvest/harvest.js +2 -2
  13. package/dist/cjs/common/harvest/types.js +1 -2
  14. package/dist/cjs/common/ids/bundle-id.js +1 -2
  15. package/dist/cjs/common/session/constants.js +7 -13
  16. package/dist/cjs/common/timer/interaction-timer.js +0 -1
  17. package/dist/cjs/common/timing/nav-timing.js +1 -2
  18. package/dist/cjs/common/util/feature-flags.js +1 -2
  19. package/dist/cjs/common/vitals/constants.js +2 -3
  20. package/dist/cjs/common/vitals/cumulative-layout-shift.js +1 -2
  21. package/dist/cjs/common/vitals/first-contentful-paint.js +1 -2
  22. package/dist/cjs/common/vitals/first-input-delay.js +1 -2
  23. package/dist/cjs/common/vitals/first-paint.js +1 -2
  24. package/dist/cjs/common/vitals/interaction-to-next-paint.js +1 -2
  25. package/dist/cjs/common/vitals/largest-contentful-paint.js +1 -2
  26. package/dist/cjs/common/vitals/long-task.js +1 -3
  27. package/dist/cjs/common/vitals/time-to-first-byte.js +1 -2
  28. package/dist/cjs/common/window/nreum.js +1 -2
  29. package/dist/cjs/common/wrap/wrap-function.js +2 -4
  30. package/dist/cjs/features/ajax/aggregate/index.js +0 -2
  31. package/dist/cjs/features/ajax/constants.js +1 -2
  32. package/dist/cjs/features/jserrors/aggregate/index.js +0 -1
  33. package/dist/cjs/features/jserrors/aggregate/string-hash-code.js +0 -1
  34. package/dist/cjs/features/jserrors/constants.js +1 -2
  35. package/dist/cjs/features/metrics/constants.js +5 -10
  36. package/dist/cjs/features/page_action/constants.js +1 -2
  37. package/dist/cjs/features/page_view_event/aggregate/index.js +2 -2
  38. package/dist/cjs/features/page_view_event/constants.js +1 -2
  39. package/dist/cjs/features/page_view_event/instrument/index.js +2 -2
  40. package/dist/cjs/features/page_view_timing/constants.js +1 -2
  41. package/dist/cjs/features/session_replay/aggregate/index.js +14 -12
  42. package/dist/cjs/features/session_replay/constants.js +8 -16
  43. package/dist/cjs/features/session_replay/instrument/index.js +11 -11
  44. package/dist/cjs/features/session_replay/shared/recorder-events.js +2 -0
  45. package/dist/cjs/features/session_replay/shared/recorder.js +50 -4
  46. package/dist/cjs/features/session_replay/shared/stylesheet-evaluator.js +94 -0
  47. package/dist/cjs/features/session_trace/aggregate/index.js +0 -2
  48. package/dist/cjs/features/session_trace/constants.js +8 -16
  49. package/dist/cjs/features/session_trace/instrument/index.js +2 -2
  50. package/dist/cjs/features/spa/aggregate/index.js +2 -2
  51. package/dist/cjs/features/spa/aggregate/interaction-node.js +0 -1
  52. package/dist/cjs/features/spa/constants.js +22 -44
  53. package/dist/cjs/features/spa/instrument/index.js +2 -2
  54. package/dist/cjs/features/utils/instrument-base.js +6 -7
  55. package/dist/cjs/features/utils/lazy-feature-loader.js +2 -2
  56. package/dist/cjs/loaders/agent-base.js +61 -15
  57. package/dist/cjs/loaders/agent.js +0 -38
  58. package/dist/cjs/loaders/api/api.js +7 -7
  59. package/dist/cjs/loaders/api/interaction-types.js +1 -2
  60. package/dist/cjs/loaders/features/features.js +3 -5
  61. package/dist/cjs/loaders/micro-agent.js +2 -2
  62. package/dist/esm/common/config/state/init.js +0 -2
  63. package/dist/esm/common/constants/env.cdn.js +1 -1
  64. package/dist/esm/common/constants/env.npm.js +1 -1
  65. package/dist/esm/common/timer/interaction-timer.js +0 -1
  66. package/dist/esm/common/vitals/long-task.js +0 -1
  67. package/dist/esm/features/ajax/aggregate/index.js +0 -2
  68. package/dist/esm/features/jserrors/aggregate/index.js +0 -1
  69. package/dist/esm/features/jserrors/aggregate/string-hash-code.js +0 -1
  70. package/dist/esm/features/session_replay/aggregate/index.js +3 -1
  71. package/dist/esm/features/session_replay/shared/recorder-events.js +2 -0
  72. package/dist/esm/features/session_replay/shared/recorder.js +50 -4
  73. package/dist/esm/features/session_replay/shared/stylesheet-evaluator.js +88 -0
  74. package/dist/esm/features/session_trace/aggregate/index.js +0 -2
  75. package/dist/esm/features/spa/aggregate/interaction-node.js +0 -1
  76. package/dist/esm/features/utils/instrument-base.js +0 -1
  77. package/dist/esm/loaders/agent-base.js +62 -15
  78. package/dist/esm/loaders/agent.js +0 -38
  79. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  80. package/dist/types/features/session_replay/shared/recorder-events.d.ts +2 -0
  81. package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -1
  82. package/dist/types/features/session_replay/shared/recorder.d.ts +14 -1
  83. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  84. package/dist/types/features/session_replay/shared/stylesheet-evaluator.d.ts +22 -0
  85. package/dist/types/features/session_replay/shared/stylesheet-evaluator.d.ts.map +1 -0
  86. package/dist/types/loaders/agent-base.d.ts +48 -12
  87. package/dist/types/loaders/agent-base.d.ts.map +1 -1
  88. package/dist/types/loaders/agent.d.ts +0 -33
  89. package/dist/types/loaders/agent.d.ts.map +1 -1
  90. package/package.json +49 -49
  91. package/src/common/ids/__mocks__/bundle-id.js +1 -1
  92. package/src/common/ids/__mocks__/unique-id.js +2 -2
  93. package/src/features/session_replay/aggregate/index.js +3 -0
  94. package/src/features/session_replay/shared/recorder-events.js +2 -0
  95. package/src/features/session_replay/shared/recorder.js +50 -5
  96. package/src/features/session_replay/shared/stylesheet-evaluator.js +84 -0
  97. package/src/loaders/agent-base.js +59 -15
  98. package/src/loaders/agent.js +0 -38
@@ -5,8 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.lazyFeatureLoader = lazyFeatureLoader;
7
7
  var _features = require("../../loaders/features/features");
8
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
9
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
8
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
9
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
10
10
  /**
11
11
  * Centralizes the lazy loading of agent feature aggregate and instrument sources.
12
12
  *
@@ -7,10 +7,21 @@ exports.AgentBase = void 0;
7
7
  var _console = require("../common/util/console");
8
8
  /* eslint-disable n/handle-callback-err */
9
9
 
10
+ /**
11
+ * @typedef {import('./api/interaction-types').InteractionInstance} InteractionInstance
12
+ */
13
+
10
14
  class AgentBase {
11
- /** Generates a generic warning message with the api name injected */
12
- #warnMessage(api) {
13
- return "Call to agent api ".concat(api, " failed. The agent is not currently initialized.");
15
+ /**
16
+ * Tries to execute the api and generates a generic warning message with the api name injected if unsuccessful
17
+ * @param {string} methodName
18
+ * @param {...any} args
19
+ */
20
+ #callMethod(methodName) {
21
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
22
+ args[_key - 1] = arguments[_key];
23
+ }
24
+ if (typeof this.api?.[methodName] !== 'function') (0, _console.warn)("Call to agent api ".concat(methodName, " failed. The API is not currently initialized."));else return this.api[methodName](...args);
14
25
  }
15
26
 
16
27
  /**
@@ -20,7 +31,7 @@ class AgentBase {
20
31
  * @param {object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}. The key is reported as its own PageAction attribute with the specified values.
21
32
  */
22
33
  addPageAction(name, attributes) {
23
- (0, _console.warn)(this.#warnMessage('addPageAction'));
34
+ return this.#callMethod('addPageAction', name, attributes);
24
35
  }
25
36
 
26
37
  /**
@@ -30,7 +41,7 @@ class AgentBase {
30
41
  * @param {string} [host] Default is http://custom.transaction. Typically set host to your site's domain URI.
31
42
  */
32
43
  setPageViewName(name, host) {
33
- (0, _console.warn)(this.#warnMessage('setPageViewName'));
44
+ return this.#callMethod('setPageViewName', name, host);
34
45
  }
35
46
 
36
47
  /**
@@ -41,7 +52,7 @@ class AgentBase {
41
52
  * @param {boolean} [persist] Default false. f set to true, the name-value pair will also be set into the browser's storage API. Then on the following instrumented pages that load within the same session, the pair will be re-applied as a custom attribute.
42
53
  */
43
54
  setCustomAttribute(name, value, persist) {
44
- (0, _console.warn)(this.#warnMessage('setCustomAttribute'));
55
+ return this.#callMethod('setCustomAttribute', name, value, persist);
45
56
  }
46
57
 
47
58
  /**
@@ -51,7 +62,7 @@ class AgentBase {
51
62
  * @param {object} [customAttributes] An object containing name/value pairs representing custom attributes.
52
63
  */
53
64
  noticeError(error, customAttributes) {
54
- (0, _console.warn)(this.#warnMessage('noticeError'));
65
+ return this.#callMethod('noticeError', error, customAttributes);
55
66
  }
56
67
 
57
68
  /**
@@ -60,7 +71,7 @@ class AgentBase {
60
71
  * @param {string|null} value A string identifier for the end-user, useful for tying all browser events to specific users. The value parameter does not have to be unique. If IDs should be unique, the caller is responsible for that validation. Passing a null value unsets any existing user ID.
61
72
  */
62
73
  setUserId(value) {
63
- (0, _console.warn)(this.#warnMessage('setUserId'));
74
+ return this.#callMethod('setUserId', value);
64
75
  }
65
76
 
66
77
  /**
@@ -72,7 +83,7 @@ class AgentBase {
72
83
  * have to be unique. Passing a null value unsets any existing value.
73
84
  */
74
85
  setApplicationVersion(value) {
75
- (0, _console.warn)(this.#warnMessage('setApplicationVersion'));
86
+ return this.#callMethod('setApplicationVersion', value);
76
87
  }
77
88
 
78
89
  /**
@@ -81,7 +92,7 @@ class AgentBase {
81
92
  * @param {(error: Error|string) => boolean | { group: string }} callback When an error occurs, the callback is called with the error object as a parameter. The callback will be called with each error, so it is not specific to one error.
82
93
  */
83
94
  setErrorHandler(callback) {
84
- (0, _console.warn)(this.#warnMessage('setErrorHandler'));
95
+ return this.#callMethod('setErrorHandler', callback);
85
96
  }
86
97
 
87
98
  /**
@@ -90,7 +101,7 @@ class AgentBase {
90
101
  * @param {number} [timeStamp] Defaults to the current time of the call. If used, this marks the time that the page is "finished" according to your own criteria.
91
102
  */
92
103
  finished(timeStamp) {
93
- (0, _console.warn)(this.#warnMessage('finished'));
104
+ return this.#callMethod('finished', timeStamp);
94
105
  }
95
106
 
96
107
  /**
@@ -100,7 +111,7 @@ class AgentBase {
100
111
  * @param {string} id The ID or version of this release; for example, a version number, build number from your CI environment, GitHub SHA, GUID, or a hash of the contents.
101
112
  */
102
113
  addRelease(name, id) {
103
- (0, _console.warn)(this.#warnMessage('addRelease'));
114
+ return this.#callMethod('addRelease', name, id);
104
115
  }
105
116
 
106
117
  /**
@@ -109,7 +120,7 @@ class AgentBase {
109
120
  * @param {string|string[]} [featureNames] The name(s) of the features to start. If no name(s) are passed, all features will be started
110
121
  */
111
122
  start(featureNames) {
112
- (0, _console.warn)(this.#warnMessage('start'));
123
+ return this.#callMethod('start', featureNames);
113
124
  }
114
125
 
115
126
  /**
@@ -118,7 +129,7 @@ class AgentBase {
118
129
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/recordReplay/}
119
130
  */
120
131
  recordReplay() {
121
- (0, _console.warn)(this.#warnMessage('recordReplay'));
132
+ return this.#callMethod('recordReplay');
122
133
  }
123
134
 
124
135
  /**
@@ -128,7 +139,42 @@ class AgentBase {
128
139
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/recordReplay/}
129
140
  */
130
141
  pauseReplay() {
131
- (0, _console.warn)(this.#warnMessage('pauseReplay'));
142
+ return this.#callMethod('pauseReplay');
143
+ }
144
+
145
+ /**
146
+ * Adds a JavaScript object with a custom name, start time, etc. to an in-progress session trace.
147
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addtotrace/}
148
+ * @param {{name: string, start: number, end?: number, origin?: string, type?: string}} customAttributes Supply a JavaScript object with these required and optional name/value pairs:
149
+ *
150
+ * - Required name/value pairs: name, start
151
+ * - Optional name/value pairs: end, origin, type
152
+ * - Note: Does not apply to MicroAgent
153
+ *
154
+ * If you are sending the same event object to New Relic as a PageAction, omit the TYPE attribute. (type is a string to describe what type of event you are marking inside of a session trace.) If included, it will override the event type and cause the PageAction event to be sent incorrectly. Instead, use the name attribute for event information.
155
+ */
156
+ addToTrace(customAttributes) {
157
+ return this.#callMethod('addToTrace', customAttributes);
158
+ }
159
+
160
+ /**
161
+ * Gives SPA routes more accurate names than default names. Monitors specific routes rather than by default grouping.
162
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setcurrentroutename/}
163
+ * @param {string} name Current route name for the page.
164
+ * - Note: Does not apply to MicroAgent
165
+ */
166
+ setCurrentRouteName(name) {
167
+ return this.#callMethod('setCurrentRouteName', name);
168
+ }
169
+
170
+ /**
171
+ * Returns a new API object that is bound to the current SPA interaction.
172
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
173
+ * @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
174
+ * - Note: Does not apply to MicroAgent
175
+ */
176
+ interaction() {
177
+ return this.#callMethod('interaction');
132
178
  }
133
179
  }
134
180
  exports.AgentBase = AgentBase;
@@ -27,10 +27,6 @@ var _runtime = require("../common/constants/runtime");
27
27
 
28
28
  // common files
29
29
 
30
- /**
31
- * @typedef {import('./api/interaction-types').InteractionInstance} InteractionInstance
32
- */
33
-
34
30
  /**
35
31
  * A flexible class that may be used to compose an agent from a select subset of feature modules. In applications
36
32
  * sensitive to network load, this may result in smaller builds with slightly lower performance impact.
@@ -100,39 +96,5 @@ class Agent extends _agentBase.AgentBase {
100
96
  return false;
101
97
  }
102
98
  }
103
-
104
- /* Below API methods are only available on a standard agent and not the micro agent */
105
-
106
- /**
107
- * Adds a JavaScript object with a custom name, start time, etc. to an in-progress session trace.
108
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addtotrace/}
109
- * @param {{name: string, start: number, end?: number, origin?: string, type?: string}} customAttributes Supply a JavaScript object with these required and optional name/value pairs:
110
- *
111
- * - Required name/value pairs: name, start
112
- * - Optional name/value pairs: end, origin, type
113
- *
114
- * If you are sending the same event object to New Relic as a PageAction, omit the TYPE attribute. (type is a string to describe what type of event you are marking inside of a session trace.) If included, it will override the event type and cause the PageAction event to be sent incorrectly. Instead, use the name attribute for event information.
115
- */
116
- addToTrace(customAttributes) {
117
- (0, _console.warn)('Call to agent api addToTrace failed. The session trace feature is not currently initialized.');
118
- }
119
-
120
- /**
121
- * Gives SPA routes more accurate names than default names. Monitors specific routes rather than by default grouping.
122
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setcurrentroutename/}
123
- * @param {string} name Current route name for the page.
124
- */
125
- setCurrentRouteName(name) {
126
- (0, _console.warn)('Call to agent api setCurrentRouteName failed. The spa feature is not currently initialized.');
127
- }
128
-
129
- /**
130
- * Returns a new API object that is bound to the current SPA interaction.
131
- * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
132
- * @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
133
- */
134
- interaction() {
135
- (0, _console.warn)('Call to agent api interaction failed. The spa feature is not currently initialized.');
136
- }
137
99
  }
138
100
  exports.Agent = Agent;
@@ -17,13 +17,13 @@ var _runtime = require("../../common/constants/runtime");
17
17
  var _console = require("../../common/util/console");
18
18
  var _constants = require("../../features/metrics/constants");
19
19
  var _nreum = require("../../common/window/nreum");
20
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
21
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /*
22
- * Copyright 2020 New Relic Corporation. All rights reserved.
23
- * SPDX-License-Identifier: Apache-2.0
24
- */
25
- const CUSTOM_ATTR_GROUP = 'CUSTOM/'; // the subgroup items should be stored under in storage API
26
- exports.CUSTOM_ATTR_GROUP = CUSTOM_ATTR_GROUP;
20
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
21
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /*
22
+ * Copyright 2020 New Relic Corporation. All rights reserved.
23
+ * SPDX-License-Identifier: Apache-2.0
24
+ */
25
+ const CUSTOM_ATTR_GROUP = exports.CUSTOM_ATTR_GROUP = 'CUSTOM/'; // the subgroup items should be stored under in storage API
26
+
27
27
  function setTopLevelCallers() {
28
28
  const nr = (0, _nreum.gosCDN)();
29
29
  const funcs = ['setErrorHandler', 'finished', 'addToTrace', 'addRelease', 'addPageAction', 'setCurrentRouteName', 'setPageViewName', 'setCustomAttribute', 'interaction', 'noticeError', 'setUserId', 'setApplicationVersion', 'start', 'recordReplay', 'pauseReplay'];
@@ -90,5 +90,4 @@ exports.unused = void 0;
90
90
  */
91
91
 
92
92
  /* istanbul ignore next */
93
- const unused = {};
94
- exports.unused = unused;
93
+ const unused = exports.unused = {};
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.featurePriority = exports.FEATURE_NAMES = void 0;
7
- const FEATURE_NAMES = {
7
+ const FEATURE_NAMES = exports.FEATURE_NAMES = {
8
8
  ajax: 'ajax',
9
9
  jserrors: 'jserrors',
10
10
  metrics: 'metrics',
@@ -20,8 +20,7 @@ const FEATURE_NAMES = {
20
20
  * The order in which features will be instrumented. This is the traditional order. It's unclear if the order of
21
21
  * wrapping events has any ramifications, so we are enforcing this order intentionally for now.
22
22
  */
23
- exports.FEATURE_NAMES = FEATURE_NAMES;
24
- const featurePriority = {
23
+ const featurePriority = exports.featurePriority = {
25
24
  [FEATURE_NAMES.pageViewEvent]: 1,
26
25
  [FEATURE_NAMES.pageViewTiming]: 2,
27
26
  [FEATURE_NAMES.metrics]: 3,
@@ -31,5 +30,4 @@ const featurePriority = {
31
30
  [FEATURE_NAMES.pageAction]: 7,
32
31
  [FEATURE_NAMES.spa]: 8,
33
32
  [FEATURE_NAMES.sessionReplay]: 9
34
- };
35
- exports.featurePriority = featurePriority;
33
+ };
@@ -15,8 +15,8 @@ var _features = require("./features/features");
15
15
  var _console = require("../common/util/console");
16
16
  var _load = require("../common/window/load");
17
17
  var _agentBase = require("./agent-base");
18
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
19
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } // loader files
18
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
19
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } // loader files
20
20
  // core files
21
21
  const nonAutoFeatures = [_features.FEATURE_NAMES.jserrors, _features.FEATURE_NAMES.pageAction, _features.FEATURE_NAMES.metrics];
22
22
 
@@ -28,7 +28,6 @@ const model = () => {
28
28
  password: true // This will be enforced to always be true in the setter
29
29
  }
30
30
  };
31
-
32
31
  return {
33
32
  feature_flags: [],
34
33
  proxy: {
@@ -36,7 +35,6 @@ const model = () => {
36
35
  // if this value is set, it will be used to overwrite the webpack asset path used to fetch assets
37
36
  beacon: undefined // likewise for the url to which we send analytics
38
37
  },
39
-
40
38
  privacy: {
41
39
  cookies_enabled: true
42
40
  },
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.250.0";
9
+ export const VERSION = "1.251.0";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.250.0";
9
+ export const VERSION = "1.251.0";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -65,7 +65,6 @@ export class InteractionTimer extends Timer {
65
65
  this.refresh();
66
66
  this.onResume(); // emit resume event after state updated
67
67
  }
68
-
69
68
  refresh(cb, ms) {
70
69
  this.clear();
71
70
  this.timer = this.create(cb, ms);
@@ -27,7 +27,6 @@ if (isBrowserScope) {
27
27
  });
28
28
  });
29
29
  };
30
-
31
30
  let observer;
32
31
  try {
33
32
  if (PerformanceObserver.supportedEntryTypes.includes('longtask')) {
@@ -25,7 +25,6 @@ export class Aggregate extends AggregateBase {
25
25
  this.drain();
26
26
  return; // feature will only collect timeslice metrics & ajax trace nodes if it's not fully enabled
27
27
  }
28
-
29
28
  const denyList = getRuntime(agentIdentifier).denyList;
30
29
  setDenyList(denyList);
31
30
  let ajaxEvents = [];
@@ -202,7 +201,6 @@ export class Aggregate extends AggregateBase {
202
201
  // traceId
203
202
  nullable(event.spanTimestamp, numeric, false) // timestamp
204
203
  ];
205
-
206
204
  var insert = '2,';
207
205
 
208
206
  // add custom attributes
@@ -144,7 +144,6 @@ export class Aggregate extends AggregateBase {
144
144
  }
145
145
  // Again as with previous usage, all falsey values would include the error.
146
146
  }
147
-
148
147
  var stackInfo = computeStackTrace(err);
149
148
  var canonicalStackString = this.buildCanonicalStackString(stackInfo);
150
149
  const params = {
@@ -12,6 +12,5 @@ export function stringHashCode(string) {
12
12
  hash = (hash << 5) - hash + charVal;
13
13
  hash = hash | 0; // Convert to 32bit integer
14
14
  }
15
-
16
15
  return hash;
17
16
  }
@@ -26,6 +26,7 @@ import { RRWEB_VERSION } from "../../../common/constants/env.npm";
26
26
  import { now } from '../../../common/timing/now';
27
27
  import { MODE, SESSION_EVENTS, SESSION_EVENT_TYPES } from '../../../common/session/constants';
28
28
  import { stringify } from '../../../common/util/stringify';
29
+ import { stylesheetEvaluator } from '../shared/stylesheet-evaluator';
29
30
  let gzipper, u8;
30
31
  export class Aggregate extends AggregateBase {
31
32
  static featureName = FEATURE_NAME;
@@ -304,6 +305,8 @@ export class Aggregate extends AggregateBase {
304
305
  hasError: recorderEvents.hasError || false,
305
306
  isFirstChunk: agentRuntime.session.state.sessionReplaySentFirstChunk === false,
306
307
  decompressedBytes: recorderEvents.payloadBytesEstimation,
308
+ invalidStylesheetsDetected: stylesheetEvaluator.invalidStylesheetsDetected,
309
+ inlinedAllStylesheets: recorderEvents.inlinedAllStylesheets,
307
310
  'rrweb.version': RRWEB_VERSION,
308
311
  // customer-defined data should go last so that if it exceeds the query param padding limit it will be truncated instead of important attrs
309
312
  ...(endUserId && {
@@ -312,7 +315,6 @@ export class Aggregate extends AggregateBase {
312
315
  // The Query Param is being arbitrarily limited in length here. It is also applied when estimating the size of the payload in getPayloadSize()
313
316
  }, QUERY_PARAM_PADDING).substring(1) // remove the leading '&'
314
317
  },
315
-
316
318
  body: events
317
319
  };
318
320
  }
@@ -17,6 +17,8 @@ export class RecorderEvents {
17
17
  this.hasMeta = false;
18
18
  /** Payload metadata -- Should indicate that the payload being sent contains an error. Used for query/filter purposes in UI */
19
19
  this.hasError = false;
20
+ /** Payload metadata -- Denotes whether all stylesheet elements were able to be inlined */
21
+ this.inlinedAllStylesheets = true;
20
22
  }
21
23
  add(event) {
22
24
  this.events.push(event);
@@ -4,6 +4,10 @@ import { AVG_COMPRESSION, CHECKOUT_MS, IDEAL_PAYLOAD_SIZE, QUERY_PARAM_PADDING,
4
4
  import { getConfigurationValue } from '../../../common/config/config';
5
5
  import { RecorderEvents } from './recorder-events';
6
6
  import { MODE } from '../../../common/session/constants';
7
+ import { stylesheetEvaluator } from './stylesheet-evaluator';
8
+ import { handle } from '../../../common/event-emitter/handle';
9
+ import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
10
+ import { FEATURE_NAMES } from '../../../loaders/features/features';
7
11
  export class Recorder {
8
12
  /** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
9
13
  #events = new RecorderEvents();
@@ -11,14 +15,21 @@ export class Recorder {
11
15
  #backloggedEvents = new RecorderEvents();
12
16
  /** array of recorder events -- Will be filled only if forced harvest was triggered and harvester does not exist */
13
17
  #preloaded = [new RecorderEvents()];
18
+ /** flag that if true, blocks events from being "stored". Only set to true when a full snapshot has incomplete nodes (only stylesheets ATM) */
19
+ #fixing = false;
14
20
  constructor(parent) {
15
21
  /** True when actively recording, false when paused or stopped */
16
22
  this.recording = false;
23
+ /** The pointer to the current bucket holding rrweb events */
17
24
  this.currentBufferTarget = this.#events;
18
25
  /** Hold on to the last meta node, so that it can be re-inserted if the meta and snapshot nodes are broken up due to harvesting */
19
26
  this.lastMeta = false;
27
+ /** The parent class that instantiated the recorder */
20
28
  this.parent = parent;
21
-
29
+ /** Config to inform to inline stylesheet contents (true default) */
30
+ this.shouldInlineStylesheets = getConfigurationValue(this.parent.agentIdentifier, 'session_replay.inline_stylesheet');
31
+ /** A flag that can be set to false by failing conversions to stop the fetching process */
32
+ this.shouldFix = this.shouldInlineStylesheets;
22
33
  /** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
23
34
  this.stopRecording = () => {/* no-op until set by rrweb initializer */};
24
35
  }
@@ -34,7 +45,8 @@ export class Recorder {
34
45
  payloadBytesEstimation: this.#backloggedEvents.payloadBytesEstimation + this.#events.payloadBytesEstimation,
35
46
  hasError: this.#backloggedEvents.hasError || this.#events.hasError,
36
47
  hasMeta: this.#backloggedEvents.hasMeta || this.#events.hasMeta,
37
- hasSnapshot: this.#backloggedEvents.hasSnapshot || this.#events.hasSnapshot
48
+ hasSnapshot: this.#backloggedEvents.hasSnapshot || this.#events.hasSnapshot,
49
+ inlinedAllStylesheets: !!this.#backloggedEvents.events.length && this.#backloggedEvents.inlinedAllStylesheets || this.#events.inlinedAllStylesheets
38
50
  };
39
51
  }
40
52
 
@@ -62,7 +74,7 @@ export class Recorder {
62
74
  // set up rrweb configurations for maximum privacy --
63
75
  // https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
64
76
  const stop = recorder({
65
- emit: this.store.bind(this),
77
+ emit: this.audit.bind(this),
66
78
  blockClass: block_class,
67
79
  ignoreClass: ignore_class,
68
80
  maskTextClass: mask_text_class,
@@ -81,10 +93,44 @@ export class Recorder {
81
93
  };
82
94
  }
83
95
 
96
+ /**
97
+ * audit - Checks if the event node payload is missing certain attributes
98
+ * will forward on to the "store" method if nothing needs async fixing
99
+ * @param {*} event - An RRWEB event node
100
+ * @param {*} isCheckout - Flag indicating if the payload was triggered as a checkout
101
+ */
102
+ audit(event, isCheckout) {
103
+ /** only run the audit if inline_stylesheets is configured as on (default behavior) */
104
+ if (this.shouldInlineStylesheets === false || !this.shouldFix) {
105
+ this.currentBufferTarget.inlinedAllStylesheets = false;
106
+ return this.store(event, isCheckout);
107
+ }
108
+ /** An count of stylesheet objects that were blocked from accessing contents via JS */
109
+ const incompletes = stylesheetEvaluator.evaluate();
110
+ /** Only stop ignoring data if already ignoring and a new valid snapshap is taking place (0 incompletes and we get a meta node for the snap) */
111
+ if (!incompletes && this.#fixing && event.type === RRWEB_EVENT_TYPES.Meta) this.#fixing = false;
112
+ if (incompletes) {
113
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Payload/Missing-Inline-Css', incompletes], undefined, FEATURE_NAMES.metrics, this.parent.ee);
114
+ /** wait for the evaluator to download/replace the incompletes' src code and then take a new snap */
115
+ stylesheetEvaluator.fix().then(failedToFix => {
116
+ if (failedToFix) {
117
+ this.currentBufferTarget.inlinedAllStylesheets = false;
118
+ this.shouldFix = false;
119
+ }
120
+ this.takeFullSnapshot();
121
+ });
122
+ /** Only start ignoring data if got a faulty snapshot */
123
+ if (event.type === RRWEB_EVENT_TYPES.FullSnapshot || event.type === RRWEB_EVENT_TYPES.Meta) this.#fixing = true;
124
+ }
125
+ /** Only store the data if not being "fixed" (full snapshots that have broken css) */
126
+ if (!this.#fixing) this.store(event, isCheckout);
127
+ }
128
+
84
129
  /** Store a payload in the buffer (this.#events). This should be the callback to the recording lib noticing a mutation */
85
130
  store(event, isCheckout) {
131
+ if (!event) return;
86
132
  event.__serialized = stringify(event);
87
- if (!this.parent.scheduler) this.currentBufferTarget = this.#preloaded[this.#preloaded.length - 1];else this.currentBufferTarget = this.#events;
133
+ if (!this.parent.scheduler && this.#preloaded.length) this.currentBufferTarget = this.#preloaded[this.#preloaded.length - 1];else this.currentBufferTarget = this.#events;
88
134
  if (this.parent.blocked) return;
89
135
  const eventBytes = event.__serialized.length;
90
136
  /** The estimated size of the payload after compression */
@@ -0,0 +1,88 @@
1
+ import { originals } from '../../../common/config/config';
2
+ import { isBrowserScope } from '../../../common/constants/runtime';
3
+ class StylesheetEvaluator {
4
+ #evaluated = new WeakSet();
5
+ #fetchProms = [];
6
+ /**
7
+ * Flipped to true if stylesheets that cannot be natively inlined are detected by the stylesheetEvaluator class
8
+ * Used at harvest time to denote that all subsequent payloads are subject to this and customers should be advised to handle crossorigin decoration
9
+ * */
10
+ invalidStylesheetsDetected = false;
11
+ failedToFix = false;
12
+
13
+ /**
14
+ * this works by checking (only ever once) each cssRules obj in the style sheets array. The try/catch will catch an error if the cssRules obj blocks access, triggering the module to try to "fix" the asset`. Returns the count of incomplete assets discovered.
15
+ * @returns {Number}
16
+ */
17
+ evaluate() {
18
+ let incompletes = 0;
19
+ if (isBrowserScope) {
20
+ for (let i = 0; i < Object.keys(document.styleSheets).length; i++) {
21
+ const ss = document.styleSheets[i];
22
+ if (!this.#evaluated.has(ss)) {
23
+ this.#evaluated.add(ss);
24
+ try {
25
+ // eslint-disable-next-line
26
+ const temp = ss.cssRules;
27
+ } catch (err) {
28
+ incompletes++;
29
+ this.#fetchProms.push(this.#fetchAndOverride(document.styleSheets[i], ss.href));
30
+ }
31
+ }
32
+ }
33
+ }
34
+ if (incompletes) this.invalidStylesheetsDetected = true;
35
+ return incompletes;
36
+ }
37
+
38
+ /**
39
+ * Resolves promise once all stylesheets have been fetched and overridden
40
+ * @returns {Promise}
41
+ */
42
+ async fix() {
43
+ await Promise.all(this.#fetchProms);
44
+ this.#fetchProms = [];
45
+ const failedToFix = this.failedToFix;
46
+ this.failedToFix = false;
47
+ return failedToFix;
48
+ }
49
+
50
+ /**
51
+ * Fetches stylesheet contents and overrides the target getters
52
+ * @param {*} target - The stylesheet object target - ex. document.styleSheets[0]
53
+ * @param {*} href - The asset href to fetch
54
+ * @returns {Promise}
55
+ */
56
+ async #fetchAndOverride(target, href) {
57
+ const stylesheetContents = await originals.FETCH.bind(window)(href);
58
+ if (!stylesheetContents.ok) {
59
+ this.failedToFix = true;
60
+ return;
61
+ }
62
+ const stylesheetText = await stylesheetContents.text();
63
+ try {
64
+ const cssSheet = new CSSStyleSheet();
65
+ await cssSheet.replace(stylesheetText);
66
+ Object.defineProperty(target, 'cssRules', {
67
+ get() {
68
+ return cssSheet.cssRules;
69
+ }
70
+ });
71
+ Object.defineProperty(target, 'rules', {
72
+ get() {
73
+ return cssSheet.rules;
74
+ }
75
+ });
76
+ } catch (err) {
77
+ // cant make new dynamic stylesheets, browser likely doesn't support `.replace()`...
78
+ // this is appended in prep of forking rrweb
79
+ Object.defineProperty(target, 'cssText', {
80
+ get() {
81
+ return stylesheetText;
82
+ }
83
+ });
84
+ this.failedToFix = true;
85
+ }
86
+ }
87
+ }
88
+ export const stylesheetEvaluator = new StylesheetEvaluator();
@@ -244,7 +244,6 @@ export class Aggregate extends AggregateBase {
244
244
  }); // sends first stn harvest immediately
245
245
  startupBuffer.decide(true); // signal to ALLOW & process data in EE's buffer into internal nodes queued for next harvest
246
246
  }
247
-
248
247
  #onHarvestFinished(result) {
249
248
  if (result.sent && result.responseText && !this.ptid) {
250
249
  // continue interval harvest only if ptid was returned by server on the first
@@ -283,7 +282,6 @@ export class Aggregate extends AggregateBase {
283
282
  if (currentMode === MODE.OFF && Object.keys(this.trace).length === 0) return;
284
283
  if (currentMode === MODE.ERROR) return; // Trace in this mode should never be harvesting, even on unload
285
284
  }
286
-
287
285
  return this.takeSTNs(options.retry);
288
286
  }
289
287