@newrelic/browser-agent 1.233.0 → 1.234.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 (115) hide show
  1. package/dist/cjs/cdn/experimental.js +27 -0
  2. package/dist/cjs/common/config/state/init.js +1 -1
  3. package/dist/cjs/common/constants/env.cdn.js +1 -1
  4. package/dist/cjs/common/constants/env.npm.js +1 -1
  5. package/dist/cjs/common/event-emitter/contextual-ee.test.js +10 -10
  6. package/dist/cjs/common/harvest/harvest-scheduler.js +18 -3
  7. package/dist/cjs/common/harvest/harvest-scheduler.test.js +39 -0
  8. package/dist/cjs/common/harvest/harvest.js +14 -34
  9. package/dist/cjs/common/harvest/harvest.test.js +224 -0
  10. package/dist/cjs/common/url/encode.js +2 -2
  11. package/dist/cjs/common/util/console.test.js +30 -0
  12. package/dist/cjs/common/util/get-or-set.js +8 -1
  13. package/dist/cjs/common/util/get-or-set.test.js +47 -0
  14. package/dist/cjs/common/util/stringify.test.js +48 -0
  15. package/dist/cjs/common/util/submit-data.js +15 -15
  16. package/dist/cjs/common/util/submit-data.test.js +221 -0
  17. package/dist/cjs/common/util/traverse.js +19 -27
  18. package/dist/cjs/common/util/traverse.test.js +44 -0
  19. package/dist/cjs/features/metrics/aggregate/endpoint-map.js +14 -0
  20. package/dist/cjs/features/metrics/aggregate/index.js +3 -2
  21. package/dist/cjs/features/metrics/instrument/index.js +0 -2
  22. package/dist/cjs/features/page_view_event/aggregate/index.js +58 -44
  23. package/dist/cjs/features/session_replay/aggregate/index.js +10 -7
  24. package/dist/cjs/loaders/configure/configure.js +0 -1
  25. package/dist/esm/cdn/experimental.js +24 -0
  26. package/dist/esm/common/config/state/init.js +1 -1
  27. package/dist/esm/common/constants/env.cdn.js +1 -1
  28. package/dist/esm/common/constants/env.npm.js +1 -1
  29. package/dist/esm/common/event-emitter/contextual-ee.test.js +10 -10
  30. package/dist/esm/common/harvest/harvest-scheduler.js +18 -3
  31. package/dist/esm/common/harvest/harvest-scheduler.test.js +37 -0
  32. package/dist/esm/common/harvest/harvest.js +14 -34
  33. package/dist/esm/common/harvest/harvest.test.js +222 -0
  34. package/dist/esm/common/url/encode.js +2 -2
  35. package/dist/esm/common/util/console.test.js +28 -0
  36. package/dist/esm/common/util/get-or-set.js +8 -1
  37. package/dist/esm/common/util/get-or-set.test.js +45 -0
  38. package/dist/esm/common/util/stringify.test.js +46 -0
  39. package/dist/esm/common/util/submit-data.js +15 -15
  40. package/dist/esm/common/util/submit-data.test.js +219 -0
  41. package/dist/esm/common/util/traverse.js +19 -27
  42. package/dist/esm/common/util/traverse.test.js +42 -0
  43. package/dist/esm/features/metrics/aggregate/endpoint-map.js +7 -0
  44. package/dist/esm/features/metrics/aggregate/index.js +3 -2
  45. package/dist/esm/features/metrics/instrument/index.js +0 -2
  46. package/dist/esm/features/page_view_event/aggregate/index.js +58 -44
  47. package/dist/esm/features/session_replay/aggregate/index.js +10 -7
  48. package/dist/esm/loaders/configure/configure.js +0 -1
  49. package/dist/types/cdn/experimental.d.ts +2 -0
  50. package/dist/types/cdn/experimental.d.ts.map +1 -0
  51. package/dist/types/common/config/state/init.d.ts.map +1 -1
  52. package/dist/types/common/context/shared-context.d.ts.map +1 -1
  53. package/dist/types/common/harvest/harvest-scheduler.d.ts +26 -3
  54. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  55. package/dist/types/common/harvest/harvest.d.ts +2 -2
  56. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  57. package/dist/types/common/timer/timer.d.ts.map +1 -1
  58. package/dist/types/common/util/get-or-set.d.ts +9 -1
  59. package/dist/types/common/util/get-or-set.d.ts.map +1 -1
  60. package/dist/types/common/util/submit-data.d.ts +14 -10
  61. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  62. package/dist/types/common/util/traverse.d.ts +10 -1
  63. package/dist/types/common/util/traverse.d.ts.map +1 -1
  64. package/dist/types/common/window/nreum.d.ts.map +1 -1
  65. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts +8 -0
  66. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts.map +1 -0
  67. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  68. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -1
  69. package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
  70. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  71. package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
  72. package/dist/types/features/session_replay/aggregate/index.d.ts +4 -0
  73. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  74. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  75. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  76. package/package.json +8 -3
  77. package/src/cdn/experimental.js +36 -0
  78. package/src/common/config/state/init.js +1 -2
  79. package/src/common/context/shared-context.js +0 -1
  80. package/src/common/event-emitter/contextual-ee.test.js +10 -10
  81. package/src/common/harvest/harvest-scheduler.js +18 -3
  82. package/src/common/harvest/harvest-scheduler.test.js +25 -0
  83. package/src/common/harvest/harvest.js +15 -20
  84. package/src/common/harvest/harvest.test.js +169 -0
  85. package/src/common/session/session-entity.test.js +0 -1
  86. package/src/common/timer/timer.js +0 -1
  87. package/src/common/url/encode.js +2 -2
  88. package/src/common/util/console.test.js +34 -0
  89. package/src/common/util/get-or-set.js +8 -1
  90. package/src/common/util/get-or-set.test.js +58 -0
  91. package/src/common/util/stringify.test.js +49 -0
  92. package/src/common/util/submit-data.js +15 -16
  93. package/src/common/util/submit-data.test.js +218 -0
  94. package/src/common/util/traverse.js +18 -27
  95. package/src/common/util/traverse.test.js +50 -0
  96. package/src/common/window/nreum.js +0 -1
  97. package/src/features/metrics/aggregate/endpoint-map.js +7 -0
  98. package/src/features/metrics/aggregate/index.js +3 -2
  99. package/src/features/metrics/aggregate/polyfill-detection.es5.js +0 -1
  100. package/src/features/metrics/instrument/index.js +0 -2
  101. package/src/features/page_view_event/aggregate/index.js +48 -51
  102. package/src/features/page_view_event/instrument/index.js +0 -1
  103. package/src/features/session_replay/aggregate/index.js +12 -7
  104. package/src/features/utils/handler-cache.js +0 -1
  105. package/src/loaders/configure/configure.js +0 -1
  106. package/dist/cjs/common/util/s-hash.js +0 -19
  107. package/dist/cjs/features/metrics/instrument/workers-helper.js +0 -124
  108. package/dist/esm/common/util/s-hash.js +0 -13
  109. package/dist/esm/features/metrics/instrument/workers-helper.js +0 -119
  110. package/dist/types/common/util/s-hash.d.ts +0 -2
  111. package/dist/types/common/util/s-hash.d.ts.map +0 -1
  112. package/dist/types/features/metrics/instrument/workers-helper.d.ts +0 -7
  113. package/dist/types/features/metrics/instrument/workers-helper.d.ts.map +0 -1
  114. package/src/common/util/s-hash.js +0 -14
  115. package/src/features/metrics/instrument/workers-helper.js +0 -113
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ var _stringify = require("./stringify");
4
+ var mockEmit = jest.fn();
5
+ jest.mock('../event-emitter/contextual-ee', () => ({
6
+ __esModule: true,
7
+ get ee() {
8
+ return {
9
+ emit: mockEmit
10
+ };
11
+ }
12
+ }));
13
+ test('should return a JSON string representation of the value', () => {
14
+ const obj = {
15
+ a: 1,
16
+ b: {
17
+ nested: true
18
+ }
19
+ };
20
+ const expected = '{"a":1,"b":{"nested":true}}';
21
+ const result = (0, _stringify.stringify)(obj);
22
+ expect(result).toBe(expected);
23
+ });
24
+ test('should handle circular references and exclude them from the JSON output', () => {
25
+ const obj = {
26
+ a: 1
27
+ };
28
+ obj.b = obj; // Create a circular reference
29
+ const expected = '{"a":1}';
30
+ const result = (0, _stringify.stringify)(obj);
31
+ expect(result).toBe(expected);
32
+ });
33
+ test('should handle non-object values and return their string representation', () => {
34
+ const value = 42;
35
+ const expected = '42';
36
+ const result = (0, _stringify.stringify)(value);
37
+ expect(result).toBe(expected);
38
+ });
39
+ test('should emit an "internal-error" event if an error occurs during JSON.stringify', () => {
40
+ const obj = {
41
+ a: 1
42
+ };
43
+ jest.spyOn(JSON, 'stringify').mockImplementation(() => {
44
+ throw new Error('message');
45
+ });
46
+ (0, _stringify.stringify)(obj);
47
+ expect(mockEmit).toHaveBeenCalledWith('internal-error', expect.any(Array));
48
+ });
@@ -50,6 +50,14 @@ submitData.jsonp = function jsonp(_ref) {
50
50
  // do nothing
51
51
  }
52
52
  };
53
+
54
+ /**
55
+ * Performs an asynchronous GET request using XMLHttpRequest.
56
+ *
57
+ * @param {Object} args - An object containing a `url` property.
58
+ * @param {string} args.url - The URL to send the GET request to.
59
+ * @returns {XMLHttpRequest} - An XMLHttpRequest object.
60
+ */
53
61
  submitData.xhrGet = function xhrGet(_ref2) {
54
62
  let {
55
63
  url
@@ -63,18 +71,18 @@ submitData.xhrGet = function xhrGet(_ref2) {
63
71
 
64
72
  /**
65
73
  * Send via XHR
66
- * @param {Object} args - The args
67
- * @param {string} args.url - The URL to send to
68
- * @param {string=} args.body - The Stringified body
69
- * @param {boolean=} args.sync - Run XHR as Synchronous
70
- * @param {string=} [args.method=POST] - The XHR method to use
71
- * @param {{key: string, value: string}[]} [args.headers] - The headers to attach
74
+ * @param {Object} args - The args.
75
+ * @param {string} args.url - The URL to send to.
76
+ * @param {string=} args.body - The Stringified body. Default null to prevent IE11 from breaking.
77
+ * @param {boolean=} args.sync - Run XHR synchronously.
78
+ * @param {string=} [args.method=POST] - The XHR method to use.
79
+ * @param {{key: string, value: string}[]} [args.headers] - The headers to attach.
72
80
  * @returns {XMLHttpRequest}
73
81
  */
74
82
  submitData.xhr = function xhr(_ref3) {
75
83
  let {
76
84
  url,
77
- body,
85
+ body = null,
78
86
  sync,
79
87
  method = 'POST',
80
88
  headers = [{
@@ -97,13 +105,6 @@ submitData.xhr = function xhr(_ref3) {
97
105
  return request;
98
106
  };
99
107
 
100
- /**
101
- * Unused at the moment -- DEPRECATED
102
- */
103
- // submitData.xhrSync = function xhrSync (url, body) {
104
- // return submitData.xhr(url, body, true)
105
- // }
106
-
107
108
  /**
108
109
  * Send by appending an <img> element to the page. Do NOT call this function outside of a guaranteed web window environment.
109
110
  * @param {Object} args - The args
@@ -114,7 +115,6 @@ submitData.img = function img(_ref4) {
114
115
  let {
115
116
  url
116
117
  } = _ref4;
117
- console.log('img url', url);
118
118
  var element = new Image();
119
119
  element.src = url;
120
120
  return element;
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+
3
+ var _submitData = require("./submit-data");
4
+ /**
5
+ * @jest-environment jsdom
6
+ * @jest-environment-options {"html": "<html><head><script></script></head><body></body></html>", "url": "https://example.com/"}
7
+ */
8
+
9
+ const mockWorkerScope = jest.fn().mockImplementation(() => false);
10
+ jest.mock('./global-scope', () => ({
11
+ __esModule: true,
12
+ get isWorkerScope() {
13
+ return mockWorkerScope();
14
+ }
15
+ }));
16
+ const url = 'https://example.com/api';
17
+ beforeEach(() => {
18
+ jest.restoreAllMocks();
19
+ mockWorkerScope.mockReturnValue(false);
20
+ });
21
+ describe('submitData.jsonp', () => {
22
+ // This test requires a script tag to exist in the html set by this file's jest-environment-options header block.
23
+ test('should return an HTMLScriptElement when called from a web window environment', () => {
24
+ mockWorkerScope.mockReturnValue(false);
25
+ const jsonp = 'callback';
26
+ const result = _submitData.submitData.jsonp({
27
+ url,
28
+ jsonp
29
+ });
30
+ expect(result).toBeInstanceOf(HTMLScriptElement);
31
+ expect(result.type).toBe('text/javascript');
32
+ expect(result.src).toBe(url + '&jsonp=' + jsonp);
33
+ });
34
+ test('should try to use importScripts when called from a worker scope', () => {
35
+ mockWorkerScope.mockReturnValueOnce(true);
36
+ const jsonp = 'callback';
37
+ global.importScripts = jest.fn();
38
+ _submitData.submitData.jsonp({
39
+ url,
40
+ jsonp
41
+ });
42
+ expect(importScripts).toHaveBeenCalledWith(url + '&jsonp=' + jsonp);
43
+ delete global.importScripts;
44
+ });
45
+ test('should fall back to an xhrGet call and return false when called from a worker scope', () => {
46
+ mockWorkerScope.mockReturnValueOnce(true);
47
+ const jsonp = 'callback';
48
+ jest.spyOn(_submitData.submitData, 'xhrGet').mockImplementation(jest.fn());
49
+ const result = _submitData.submitData.jsonp({
50
+ url,
51
+ jsonp
52
+ });
53
+ expect(result).toBe(false);
54
+ expect(_submitData.submitData.xhrGet).toHaveBeenCalledTimes(1);
55
+ });
56
+ test('should not throw an error if any error occurs during execution', () => {
57
+ jest.spyOn(document, 'createElement').mockImplementation(() => {
58
+ throw new Error('message');
59
+ });
60
+ const jsonp = 'callback';
61
+ expect(() => {
62
+ _submitData.submitData.jsonp({
63
+ url,
64
+ jsonp
65
+ });
66
+ }).not.toThrow();
67
+ });
68
+ });
69
+ describe('submitData.xhrGet', () => {
70
+ test('should return an XMLHttpRequest object', () => {
71
+ const result = _submitData.submitData.xhrGet({
72
+ url
73
+ });
74
+ expect(result).toBeInstanceOf(XMLHttpRequest);
75
+ });
76
+ test('should not throw an error if URL is not provided', () => {
77
+ expect(() => {
78
+ _submitData.submitData.xhrGet({});
79
+ }).not.toThrow();
80
+ });
81
+ test('should not throw an error if an invalid URL is provided', () => {
82
+ expect(() => {
83
+ _submitData.submitData.xhrGet({
84
+ url: 'invalid url'
85
+ });
86
+ }).not.toThrow();
87
+ });
88
+ });
89
+ describe('submitData.xhr', () => {
90
+ test('should return an XMLHttpRequest object', () => {
91
+ const result = _submitData.submitData.xhrGet({
92
+ url
93
+ });
94
+ expect(result).toBeInstanceOf(XMLHttpRequest);
95
+ });
96
+ test('should not throw an error if URL is not provided', () => {
97
+ expect(() => {
98
+ _submitData.submitData.xhr({});
99
+ }).not.toThrow();
100
+ });
101
+ test('should not throw an error if an invalid URL is provided', () => {
102
+ expect(() => {
103
+ _submitData.submitData.xhr({
104
+ url: 'invalid url'
105
+ });
106
+ }).not.toThrow();
107
+ });
108
+ test('should send a POST request by default', () => {
109
+ jest.spyOn(XMLHttpRequest.prototype, 'open');
110
+ _submitData.submitData.xhr({
111
+ url
112
+ });
113
+ expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('POST', url, true);
114
+ });
115
+ test('should send a GET request if specified', () => {
116
+ jest.spyOn(XMLHttpRequest.prototype, 'open');
117
+ _submitData.submitData.xhr({
118
+ url,
119
+ method: 'GET'
120
+ });
121
+ expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('GET', url, true);
122
+ });
123
+
124
+ // This test requires a same-origin url to be set by this file's jest-environment-options header block.
125
+ test('should send a request synchronously if specified', () => {
126
+ jest.spyOn(XMLHttpRequest.prototype, 'open');
127
+ _submitData.submitData.xhr({
128
+ url,
129
+ sync: true
130
+ });
131
+ expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('POST', url, false);
132
+ });
133
+ test('should set custom headers if provided', () => {
134
+ const headers = [{
135
+ key: 'Content-Type',
136
+ value: 'application/json'
137
+ }];
138
+ jest.spyOn(XMLHttpRequest.prototype, 'setRequestHeader');
139
+ _submitData.submitData.xhr({
140
+ url,
141
+ headers
142
+ });
143
+ headers.forEach(header => {
144
+ expect(XMLHttpRequest.prototype.setRequestHeader).toHaveBeenCalledWith(header.key, header.value);
145
+ });
146
+ });
147
+ test('should send a request with the specified body', () => {
148
+ const body = JSON.stringify({
149
+ key: 'value'
150
+ });
151
+ jest.spyOn(XMLHttpRequest.prototype, 'send');
152
+ _submitData.submitData.xhr({
153
+ url,
154
+ body
155
+ });
156
+ expect(XMLHttpRequest.prototype.send).toHaveBeenCalledWith(body);
157
+ });
158
+ });
159
+ describe('submitData.img', () => {
160
+ test('should return an HTMLImageElement', () => {
161
+ const imageUrl = 'https://example.com/image.png';
162
+ const result = _submitData.submitData.img({
163
+ url: imageUrl
164
+ });
165
+ expect(result).toBeInstanceOf(HTMLImageElement);
166
+ });
167
+ test('should not throw an error if URL is not provided', () => {
168
+ expect(() => {
169
+ _submitData.submitData.img({});
170
+ }).not.toThrow();
171
+ });
172
+ test('should set the src attribute of the image element to the provided URL', () => {
173
+ const imageUrl = 'https://example.com/image.png';
174
+ const result = _submitData.submitData.img({
175
+ url: imageUrl
176
+ });
177
+ expect(result.src).toBe(imageUrl);
178
+ });
179
+ });
180
+ describe('submitData.beacon', () => {
181
+ test('should return true when beacon request succeeds', () => {
182
+ const body = JSON.stringify({
183
+ key: 'value'
184
+ });
185
+ window.navigator.sendBeacon = {
186
+ bind: jest.fn(() => () => true)
187
+ };
188
+ const result = _submitData.submitData.beacon({
189
+ url,
190
+ body
191
+ });
192
+ expect(result).toBe(true);
193
+ });
194
+ test('should return false when beacon request fails', () => {
195
+ const body = JSON.stringify({
196
+ key: 'value'
197
+ });
198
+ window.navigator.sendBeacon = {
199
+ bind: jest.fn(() => () => {
200
+ throw new Error('message');
201
+ })
202
+ };
203
+ const result = _submitData.submitData.beacon({
204
+ url,
205
+ body
206
+ });
207
+ expect(result).toBe(false);
208
+ });
209
+ test('should error if sendBeacon is not supported', () => {
210
+ const body = JSON.stringify({
211
+ key: 'value'
212
+ });
213
+ window.navigator.sendBeacon = undefined;
214
+ expect(() => {
215
+ _submitData.submitData.beacon({
216
+ url,
217
+ body
218
+ });
219
+ }).toThrow();
220
+ });
221
+ });
@@ -9,33 +9,25 @@ exports.applyFnToProps = applyFnToProps;
9
9
  * SPDX-License-Identifier: Apache-2.0
10
10
  */
11
11
 
12
- // traverses an object and applies a fn to property values of a certain type
13
- function applyFnToProps(obj, fn, type, ignoreKeys) {
12
+ /**
13
+ * Applies a function to properties of a specified type in an object, recursively.
14
+ *
15
+ * @param {Object} obj - The object to apply the function to.
16
+ * @param {Function} fn - The function to apply to matching properties.
17
+ * @param {string} [type='string'] - The type of properties to apply the function to.
18
+ * @param {Array<string>} [ignoreKeys=[]] - The keys of properties to ignore and not modify.
19
+ * @returns {Object} - The object with function recursively applied.
20
+ */
21
+ function applyFnToProps(obj, fn) {
22
+ let type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'string';
23
+ let ignoreKeys = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
14
24
  if (!obj || typeof obj !== 'object') return obj;
15
- type = type || 'string';
16
- ignoreKeys = ignoreKeys || [];
17
- return traverse(obj);
18
- function traverse(obj) {
19
- for (var property in obj) {
20
- // eslint-disable-next-line
21
- if (obj.hasOwnProperty(property)) {
22
- if (typeof obj[property] === 'object') {
23
- traverse(obj[property]);
24
- } else {
25
- if (typeof obj[property] === type && !shouldIgnore(property)) obj[property] = fn(obj[property]);
26
- }
27
- }
28
- }
29
- return obj;
30
- }
31
- function shouldIgnore(key) {
32
- var ignore = false;
33
- for (var i = 0; i < ignoreKeys.length; i++) {
34
- if (ignoreKeys[i] === key) {
35
- ignore = true;
36
- break;
37
- }
25
+ Object.keys(obj).forEach(property => {
26
+ if (typeof obj[property] === 'object') {
27
+ applyFnToProps(obj[property], fn, type, ignoreKeys);
28
+ } else {
29
+ if (typeof obj[property] === type && !ignoreKeys.includes(property)) obj[property] = fn(obj[property]);
38
30
  }
39
- return ignore;
40
- }
31
+ });
32
+ return obj;
41
33
  }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ var _traverse = require("./traverse");
4
+ test.each(['not an object', null, undefined])('should return input unchanged when input is %p', input => {
5
+ const result = (0, _traverse.applyFnToProps)(input, jest.fn());
6
+ expect(result).toEqual(input);
7
+ });
8
+ test('should apply the provided function only to properties of the specified type', () => {
9
+ const obj = {
10
+ stringProp: 'Hello',
11
+ numberProp: 42,
12
+ arrayProp: [1, 2, 3],
13
+ objectProp: {
14
+ foo: 'bar'
15
+ }
16
+ };
17
+ const fn = jest.fn(value => value.toUpperCase());
18
+ const result = (0, _traverse.applyFnToProps)(obj, fn, 'string');
19
+ expect(result.stringProp).toBe('HELLO');
20
+ expect(result.numberProp).toBe(42);
21
+ expect(result.arrayProp).toEqual([1, 2, 3]);
22
+ expect(result.objectProp).toEqual({
23
+ foo: 'BAR'
24
+ });
25
+ expect(fn).toHaveBeenCalledTimes(2);
26
+ expect(fn).toHaveBeenCalledWith('Hello');
27
+ expect(fn).toHaveBeenCalledWith('bar');
28
+ });
29
+ test('should ignore properties specified in ignoreKeys', () => {
30
+ const obj = {
31
+ a: 1,
32
+ b: 2,
33
+ c: 3
34
+ };
35
+ const fn = jest.fn(value => value + 1);
36
+ const ignoreKeys = ['c'];
37
+ const result = (0, _traverse.applyFnToProps)(obj, fn, 'number', ignoreKeys);
38
+ expect(result.a).toBe(2);
39
+ expect(result.b).toBe(3);
40
+ expect(result.c).toBe(3);
41
+ expect(fn).toHaveBeenCalledTimes(2);
42
+ expect(fn).toHaveBeenCalledWith(1);
43
+ expect(fn).toHaveBeenCalledWith(2);
44
+ });
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.endpointMap = void 0;
7
+ const endpointMap = {
8
+ rum: '1',
9
+ events: 'Events',
10
+ ins: 'Ins',
11
+ jserrors: 'Jserrors',
12
+ resources: 'Resources'
13
+ };
14
+ exports.endpointMap = endpointMap;
@@ -19,6 +19,7 @@ var _eventListenerOpts = require("../../../common/event-listener/event-listener-
19
19
  var _globalScope = require("../../../common/util/global-scope");
20
20
  var _aggregateBase = require("../../utils/aggregate-base");
21
21
  var _stringify = require("../../../common/util/stringify");
22
+ var _endpointMap = require("./endpoint-map");
22
23
  class Aggregate extends _aggregateBase.AggregateBase {
23
24
  static featureName = _constants.FEATURE_NAME;
24
25
  constructor(agentIdentifier, aggregator) {
@@ -137,12 +138,12 @@ class Aggregate extends _aggregateBase.AggregateBase {
137
138
 
138
139
  // Capture per-agent bytes sent for each endpoint (see harvest) and RUM call (see page_view_event aggregator).
139
140
  Object.keys(agentRuntime.bytesSent).forEach(endpoint => {
140
- this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(endpoint.charAt(0).toUpperCase() + endpoint.slice(1), "/BytesSent"), agentRuntime.bytesSent[endpoint]);
141
+ this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(_endpointMap.endpointMap[endpoint], "/BytesSent"), agentRuntime.bytesSent[endpoint]);
141
142
  });
142
143
 
143
144
  // Capture per-agent query bytes sent for each endpoint (see harvest) and RUM call (see page_view_event aggregator).
144
145
  Object.keys(agentRuntime.bytesSent).forEach(endpoint => {
145
- this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(endpoint.charAt(0).toUpperCase() + endpoint.slice(1), "/QueryBytesSent"), agentRuntime.queryBytesSent[endpoint]);
146
+ this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(_endpointMap.endpointMap[endpoint], "/QueryBytesSent"), agentRuntime.queryBytesSent[endpoint]);
146
147
  });
147
148
 
148
149
  // Capture metrics for session trace if active (`ptid` is set when returned by replay ingest).
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.Instrument = void 0;
7
7
  var _instrumentBase = require("../../utils/instrument-base");
8
- var _workersHelper = require("./workers-helper");
9
8
  var _constants = require("../constants");
10
9
  var _handle = require("../../../common/event-emitter/handle");
11
10
  var _features = require("../../../loaders/features/features");
@@ -14,7 +13,6 @@ class Instrument extends _instrumentBase.InstrumentBase {
14
13
  constructor(agentIdentifier, aggregator) {
15
14
  let auto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
16
15
  super(agentIdentifier, aggregator, _constants.FEATURE_NAME, auto);
17
- (0, _workersHelper.insertSupportMetrics)(tag => (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, [tag], undefined, _features.FEATURE_NAMES.metrics, this.ee));
18
16
  this.importAggregator();
19
17
  }
20
18
  }
@@ -8,22 +8,20 @@ var _handle = require("../../../common/event-emitter/handle");
8
8
  var _features = require("../../../loaders/features/features");
9
9
  var _iosVersion = require("../../../common/browser-version/ios-version");
10
10
  var _webVitals = require("web-vitals");
11
- var _mapOwn = require("../../../common/util/map-own");
12
- var _encode = require("../../../common/url/encode");
13
11
  var _navTiming = require("../../../common/timing/nav-timing");
14
12
  var _stringify = require("../../../common/util/stringify");
15
13
  var _paintMetrics = require("../../../common/metrics/paint-metrics");
16
- var _submitData = require("../../../common/util/submit-data");
17
14
  var _config = require("../../../common/config/config");
18
- var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
15
+ var _harvest = require("../../../common/harvest/harvest");
19
16
  var CONSTANTS = _interopRequireWildcard(require("../constants"));
20
17
  var _initializedFeatures = require("./initialized-features");
21
18
  var _globalScope = require("../../../common/util/global-scope");
22
19
  var _drain = require("../../../common/drain/drain");
20
+ var _featureFlags = require("../../../common/util/feature-flags");
21
+ var _console = require("../../../common/util/console");
23
22
  var _aggregateBase = require("../../utils/aggregate-base");
24
23
  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); }
25
24
  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; }
26
- const jsonp = 'NREUM.setToken';
27
25
  class Aggregate extends _aggregateBase.AggregateBase {
28
26
  static featureName = CONSTANTS.FEATURE_NAME;
29
27
  constructor(agentIdentifier, aggregator) {
@@ -62,6 +60,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
62
60
  }
63
61
  sendRum() {
64
62
  const info = (0, _config.getInfo)(this.agentIdentifier);
63
+ const agentRuntime = (0, _config.getRuntime)(this.agentIdentifier);
64
+ const harvester = new _harvest.Harvest(this);
65
65
  if (!info.beacon) return;
66
66
  if (info.queueTime) this.aggregator.store('measures', 'qt', {
67
67
  value: info.queueTime
@@ -69,7 +69,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
69
69
  if (info.applicationTime) this.aggregator.store('measures', 'ap', {
70
70
  value: info.applicationTime
71
71
  });
72
- const agentRuntime = (0, _config.getRuntime)(this.agentIdentifier);
73
72
 
74
73
  // These 3 values should've been recorded after load and before this func runs. They are part of the minimum required for PageView events to be created.
75
74
  // Following PR #428, which demands that all agents send RUM call, these need to be sent even outside of the main window context where PerformanceTiming
@@ -83,22 +82,27 @@ class Aggregate extends _aggregateBase.AggregateBase {
83
82
  this.aggregator.store('measures', 'dc', {
84
83
  value: _globalScope.isBrowserScope ? agentRuntime[CONSTANTS.FBTDC] : 0
85
84
  });
86
- var measuresMetrics = this.aggregator.get('measures');
87
- var measuresQueryString = (0, _mapOwn.mapOwn)(measuresMetrics, function (metricName, measure) {
88
- return '&' + metricName + '=' + measure.params.value;
89
- }).join('');
90
-
91
- // currently we only have one version of our protocol
92
- // in the future we may add more
93
- var protocol = '1';
94
- var scheduler = new _harvestScheduler.HarvestScheduler('page_view_event', {}, this);
95
- var chunksForQueryString = [scheduler.harvest.baseQueryString()];
96
- chunksForQueryString.push(measuresQueryString);
97
- chunksForQueryString.push((0, _encode.param)('tt', info.ttGuid));
98
- chunksForQueryString.push((0, _encode.param)('us', info.user));
99
- chunksForQueryString.push((0, _encode.param)('ac', info.account));
100
- chunksForQueryString.push((0, _encode.param)('pr', info.product));
101
- chunksForQueryString.push((0, _encode.param)('af', (0, _initializedFeatures.getActivatedFeaturesFlags)(this.agentIdentifier).join(',')));
85
+ const queryParameters = {
86
+ tt: info.ttGuid,
87
+ us: info.user,
88
+ ac: info.account,
89
+ pr: info.product,
90
+ af: (0, _initializedFeatures.getActivatedFeaturesFlags)(this.agentIdentifier).join(','),
91
+ ...Object.entries(this.aggregator.get('measures') || {}).reduce((aggregator, _ref2) => {
92
+ let [metricName, measure] = _ref2;
93
+ aggregator[metricName] = measure.params?.value;
94
+ return aggregator;
95
+ }, {}),
96
+ xx: info.extra,
97
+ ua: info.userAttributes,
98
+ at: info.atts
99
+ };
100
+ let body;
101
+ if (typeof info.jsAttributes === 'object' && Object.keys(info.jsAttributes).length > 0) {
102
+ body = {
103
+ ja: info.jsAttributes
104
+ };
105
+ }
102
106
  if (_globalScope.globalScope.performance) {
103
107
  if (typeof PerformanceNavigationTiming !== 'undefined') {
104
108
  // Navigation Timing level 2 API that replaced PerformanceTiming & PerformanceNavigation
@@ -107,14 +111,14 @@ class Aggregate extends _aggregateBase.AggregateBase {
107
111
  timing: (0, _navTiming.addPT)(agentRuntime.offset, navTimingEntry, {}),
108
112
  navigation: (0, _navTiming.addPN)(navTimingEntry, {})
109
113
  };
110
- chunksForQueryString.push((0, _encode.param)('perf', (0, _stringify.stringify)(perf)));
114
+ queryParameters.perf = (0, _stringify.stringify)(perf);
111
115
  } else if (typeof PerformanceTiming !== 'undefined') {
112
116
  // Safari pre-15 did not support level 2 timing
113
117
  const perf = {
114
118
  timing: (0, _navTiming.addPT)(agentRuntime.offset, _globalScope.globalScope.performance.timing, {}, true),
115
119
  navigation: (0, _navTiming.addPN)(_globalScope.globalScope.performance.navigation, {})
116
120
  };
117
- chunksForQueryString.push((0, _encode.param)('perf', (0, _stringify.stringify)(perf)));
121
+ queryParameters.perf = (0, _stringify.stringify)(perf);
118
122
  }
119
123
  }
120
124
  try {
@@ -123,32 +127,42 @@ class Aggregate extends _aggregateBase.AggregateBase {
123
127
  entries.forEach(function (entry) {
124
128
  if (!entry.startTime || entry.startTime <= 0) return;
125
129
  if (entry.name === 'first-paint') {
126
- chunksForQueryString.push((0, _encode.param)('fp', String(Math.floor(entry.startTime))));
130
+ queryParameters.fp = String(Math.floor(entry.startTime));
127
131
  } else if (entry.name === 'first-contentful-paint') {
128
- chunksForQueryString.push((0, _encode.param)('fcp', String(Math.floor(entry.startTime))));
132
+ queryParameters.fcp = String(Math.floor(entry.startTime));
129
133
  }
130
134
  _paintMetrics.paintMetrics[entry.name] = Math.floor(entry.startTime); // this is consumed by Spa module
131
135
  });
132
136
  } catch (e) {}
133
- chunksForQueryString.push((0, _encode.param)('xx', info.extra));
134
- chunksForQueryString.push((0, _encode.param)('ua', info.userAttributes));
135
- chunksForQueryString.push((0, _encode.param)('at', info.atts));
136
- var customJsAttributes = (0, _stringify.stringify)(info.jsAttributes);
137
- chunksForQueryString.push((0, _encode.param)('ja', customJsAttributes === '{}' ? null : customJsAttributes));
138
- var queryString = (0, _encode.fromArray)(chunksForQueryString, agentRuntime.maxBytes);
139
-
140
- // Capture bytes sent to RUM call endpoint (currently `1`) as a supportability metric. See metrics aggregator (on unload).
141
- agentRuntime.bytesSent[protocol] = 0; // Set to zero for now until RUM is moved to POST
142
-
143
- // Capture query bytes sent to RUM call endpoint (currently `1`) as a supportability metric. See metrics aggregator (on unload).
144
- agentRuntime.queryBytesSent[protocol] = (agentRuntime.queryBytesSent[protocol] || 0) + queryString?.length || 0;
145
- const isValidJsonp = _submitData.submitData.jsonp({
146
- url: this.getScheme() + '://' + info.beacon + '/' + protocol + '/' + info.licenseKey + '?' + queryString,
147
- jsonp
137
+ harvester.send({
138
+ endpoint: 'rum',
139
+ payload: {
140
+ qs: queryParameters,
141
+ body
142
+ },
143
+ opts: {
144
+ needResponse: true,
145
+ sendEmptyBody: true
146
+ },
147
+ cbFinished: _ref3 => {
148
+ let {
149
+ status,
150
+ responseText
151
+ } = _ref3;
152
+ if (status >= 400) {
153
+ // Adding retry logic for the rum call will be a separate change
154
+ this.ee.abort();
155
+ return;
156
+ }
157
+ try {
158
+ (0, _featureFlags.activateFeatures)(JSON.parse(responseText), this.agentIdentifier);
159
+ (0, _drain.drain)(this.agentIdentifier, this.featureName);
160
+ } catch (err) {
161
+ this.ee.abort();
162
+ (0, _console.warn)('RUM call failed. Agent shutting down.');
163
+ }
164
+ }
148
165
  });
149
- // Usually `drain` is invoked automatically after processing feature flags contained in the JSONP callback from
150
- // ingest (see `activateFeatures`), so when JSONP cannot execute (as with module workers), we drain manually.
151
- if (!isValidJsonp) (0, _drain.drain)(this.agentIdentifier, CONSTANTS.FEATURE_NAME);
152
166
  }
153
167
  }
154
168
  exports.Aggregate = Aggregate;