@newrelic/browser-agent 1.302.0 → 1.303.0-rc.1

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 (122) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/common/config/init-types.js +2 -0
  3. package/dist/cjs/common/config/init.js +3 -0
  4. package/dist/cjs/common/config/runtime.js +9 -0
  5. package/dist/cjs/common/constants/env.cdn.js +1 -1
  6. package/dist/cjs/common/constants/env.npm.js +1 -1
  7. package/dist/cjs/common/harvest/harvester.js +13 -9
  8. package/dist/cjs/common/harvest/types.js +0 -1
  9. package/dist/cjs/common/session/session-entity.js +4 -2
  10. package/dist/cjs/common/util/mfe.js +8 -5
  11. package/dist/cjs/common/wrap/wrap-promise.js +10 -5
  12. package/dist/cjs/features/generic_events/aggregate/index.js +4 -4
  13. package/dist/cjs/features/logging/aggregate/index.js +1 -2
  14. package/dist/cjs/features/page_view_event/aggregate/index.js +84 -22
  15. package/dist/cjs/features/page_view_event/instrument/index.js +0 -4
  16. package/dist/cjs/features/session_replay/aggregate/index.js +3 -2
  17. package/dist/cjs/features/session_replay/constants.js +2 -6
  18. package/dist/cjs/features/session_replay/instrument/index.js +3 -2
  19. package/dist/cjs/features/utils/agent-session.js +5 -0
  20. package/dist/cjs/features/utils/instrument-base.js +7 -8
  21. package/dist/cjs/interfaces/registered-entity.js +21 -0
  22. package/dist/cjs/loaders/agent.js +2 -0
  23. package/dist/cjs/loaders/api/consent.js +37 -0
  24. package/dist/cjs/loaders/api/constants.js +3 -2
  25. package/dist/cjs/loaders/api/measure.js +36 -35
  26. package/dist/cjs/loaders/api/recordCustomEvent.js +5 -3
  27. package/dist/cjs/loaders/api/register-api-types.js +14 -10
  28. package/dist/cjs/loaders/api/register.js +25 -10
  29. package/dist/cjs/loaders/api-base.js +14 -7
  30. package/dist/esm/common/config/init-types.js +2 -0
  31. package/dist/esm/common/config/init.js +3 -0
  32. package/dist/esm/common/config/runtime.js +9 -0
  33. package/dist/esm/common/constants/env.cdn.js +1 -1
  34. package/dist/esm/common/constants/env.npm.js +1 -1
  35. package/dist/esm/common/harvest/harvester.js +13 -9
  36. package/dist/esm/common/harvest/types.js +0 -1
  37. package/dist/esm/common/session/session-entity.js +4 -2
  38. package/dist/esm/common/util/mfe.js +7 -5
  39. package/dist/esm/common/wrap/wrap-promise.js +10 -5
  40. package/dist/esm/features/generic_events/aggregate/index.js +4 -4
  41. package/dist/esm/features/logging/aggregate/index.js +1 -2
  42. package/dist/esm/features/page_view_event/aggregate/index.js +84 -22
  43. package/dist/esm/features/page_view_event/instrument/index.js +0 -4
  44. package/dist/esm/features/session_replay/aggregate/index.js +4 -3
  45. package/dist/esm/features/session_replay/constants.js +1 -5
  46. package/dist/esm/features/session_replay/instrument/index.js +4 -3
  47. package/dist/esm/features/utils/agent-session.js +5 -0
  48. package/dist/esm/features/utils/instrument-base.js +7 -8
  49. package/dist/esm/interfaces/registered-entity.js +21 -0
  50. package/dist/esm/loaders/agent.js +2 -0
  51. package/dist/esm/loaders/api/consent.js +30 -0
  52. package/dist/esm/loaders/api/constants.js +2 -1
  53. package/dist/esm/loaders/api/measure.js +35 -35
  54. package/dist/esm/loaders/api/recordCustomEvent.js +4 -3
  55. package/dist/esm/loaders/api/register-api-types.js +14 -10
  56. package/dist/esm/loaders/api/register.js +26 -10
  57. package/dist/esm/loaders/api-base.js +15 -8
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/dist/types/common/config/init-types.d.ts +6 -0
  60. package/dist/types/common/config/init.d.ts.map +1 -1
  61. package/dist/types/common/config/runtime.d.ts.map +1 -1
  62. package/dist/types/common/harvest/harvester.d.ts.map +1 -1
  63. package/dist/types/common/harvest/types.d.ts +0 -2
  64. package/dist/types/common/harvest/types.d.ts.map +1 -1
  65. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  66. package/dist/types/common/util/mfe.d.ts +3 -0
  67. package/dist/types/common/util/mfe.d.ts.map +1 -1
  68. package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
  69. package/dist/types/features/page_view_event/aggregate/index.d.ts +22 -3
  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.map +1 -1
  73. package/dist/types/features/session_replay/constants.d.ts +1 -5
  74. package/dist/types/features/session_replay/constants.d.ts.map +1 -1
  75. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
  76. package/dist/types/features/utils/agent-session.d.ts.map +1 -1
  77. package/dist/types/features/utils/instrument-base.d.ts +1 -0
  78. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  79. package/dist/types/interfaces/registered-entity.d.ts +25 -0
  80. package/dist/types/interfaces/registered-entity.d.ts.map +1 -1
  81. package/dist/types/loaders/agent.d.ts.map +1 -1
  82. package/dist/types/loaders/api/consent.d.ts +2 -0
  83. package/dist/types/loaders/api/consent.d.ts.map +1 -0
  84. package/dist/types/loaders/api/constants.d.ts +1 -0
  85. package/dist/types/loaders/api/constants.d.ts.map +1 -1
  86. package/dist/types/loaders/api/measure.d.ts +3 -0
  87. package/dist/types/loaders/api/measure.d.ts.map +1 -1
  88. package/dist/types/loaders/api/recordCustomEvent.d.ts +1 -0
  89. package/dist/types/loaders/api/recordCustomEvent.d.ts.map +1 -1
  90. package/dist/types/loaders/api/register-api-types.d.ts +43 -12
  91. package/dist/types/loaders/api/register-api-types.d.ts.map +1 -1
  92. package/dist/types/loaders/api/register.d.ts +0 -16
  93. package/dist/types/loaders/api/register.d.ts.map +1 -1
  94. package/dist/types/loaders/api-base.d.ts +20 -15
  95. package/dist/types/loaders/api-base.d.ts.map +1 -1
  96. package/package.json +4 -4
  97. package/src/common/config/init-types.js +2 -0
  98. package/src/common/config/init.js +1 -0
  99. package/src/common/config/runtime.js +10 -0
  100. package/src/common/harvest/harvester.js +11 -8
  101. package/src/common/harvest/types.js +0 -1
  102. package/src/common/session/session-entity.js +6 -2
  103. package/src/common/util/mfe.js +10 -4
  104. package/src/common/wrap/wrap-promise.js +16 -6
  105. package/src/features/generic_events/aggregate/index.js +4 -4
  106. package/src/features/logging/aggregate/index.js +1 -1
  107. package/src/features/page_view_event/aggregate/index.js +79 -15
  108. package/src/features/page_view_event/instrument/index.js +0 -4
  109. package/src/features/session_replay/aggregate/index.js +4 -3
  110. package/src/features/session_replay/constants.js +1 -5
  111. package/src/features/session_replay/instrument/index.js +4 -3
  112. package/src/features/utils/agent-session.js +4 -0
  113. package/src/features/utils/instrument-base.js +7 -9
  114. package/src/interfaces/registered-entity.js +21 -0
  115. package/src/loaders/agent.js +2 -0
  116. package/src/loaders/api/consent.js +31 -0
  117. package/src/loaders/api/constants.js +1 -0
  118. package/src/loaders/api/measure.js +34 -33
  119. package/src/loaders/api/recordCustomEvent.js +5 -3
  120. package/src/loaders/api/register-api-types.js +14 -10
  121. package/src/loaders/api/register.js +17 -10
  122. package/src/loaders/api-base.js +15 -8
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.setupConsentAPI = setupConsentAPI;
7
+ var _constants = require("./constants");
8
+ var _sharedHandlers = require("./sharedHandlers");
9
+ var _handle = require("../../common/event-emitter/handle");
10
+ var _console = require("../../common/util/console");
11
+ /**
12
+ * Copyright 2020-2025 New Relic, Inc. All rights reserved.
13
+ * SPDX-License-Identifier: Apache-2.0
14
+ */
15
+
16
+ function setupConsentAPI(agent) {
17
+ (0, _sharedHandlers.setupAPI)(_constants.CONSENT, function (accept = true) {
18
+ if (typeof accept !== 'boolean') {
19
+ (0, _console.warn)(65, typeof accept);
20
+ return;
21
+ }
22
+ /** harvester, by way of "consented" getter, checks session state first, and falls back on runtime state if not available. Set both here */
23
+ (0, _handle.handle)(_constants.prefix + _constants.CONSENT, [accept], undefined, 'session', agent.ee); // sets session state (if available)
24
+ agent.runtime.consented = accept; // sets runtime state
25
+
26
+ /** if consent is granted, attempt to make a PageView event harvest if one has not already been made */
27
+ if (accept) {
28
+ const pveInst = agent.features.page_view_event;
29
+ pveInst.onAggregateImported.then(loaded => {
30
+ const pveAgg = pveInst.featAggregate;
31
+ if (loaded && !pveAgg.sentRum) {
32
+ pveAgg.sendRum();
33
+ }
34
+ });
35
+ }
36
+ }, agent);
37
+ }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.spaPrefix = exports.prefix = exports.WRAP_LOGGER = exports.START = exports.SET_USER_ID = exports.SET_PAGE_VIEW_NAME = exports.SET_ERROR_HANDLER = exports.SET_CUSTOM_ATTRIBUTE = exports.SET_CURRENT_ROUTE_NAME = exports.SET_APPLICATION_VERSION = exports.REGISTER = exports.RECORD_REPLAY = exports.RECORD_CUSTOM_EVENT = exports.PAUSE_REPLAY = exports.NOTICE_ERROR = exports.MEASURE = exports.LOG = exports.INTERACTION = exports.FINISHED = exports.ADD_TO_TRACE = exports.ADD_RELEASE = exports.ADD_PAGE_ACTION = void 0;
6
+ exports.spaPrefix = exports.prefix = exports.WRAP_LOGGER = exports.START = exports.SET_USER_ID = exports.SET_PAGE_VIEW_NAME = exports.SET_ERROR_HANDLER = exports.SET_CUSTOM_ATTRIBUTE = exports.SET_CURRENT_ROUTE_NAME = exports.SET_APPLICATION_VERSION = exports.REGISTER = exports.RECORD_REPLAY = exports.RECORD_CUSTOM_EVENT = exports.PAUSE_REPLAY = exports.NOTICE_ERROR = exports.MEASURE = exports.LOG = exports.INTERACTION = exports.FINISHED = exports.CONSENT = exports.ADD_TO_TRACE = exports.ADD_RELEASE = exports.ADD_PAGE_ACTION = void 0;
7
7
  /**
8
8
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
9
9
  * SPDX-License-Identifier: Apache-2.0
@@ -29,4 +29,5 @@ const SET_PAGE_VIEW_NAME = exports.SET_PAGE_VIEW_NAME = 'setPageViewName';
29
29
  const SET_USER_ID = exports.SET_USER_ID = 'setUserId';
30
30
  const START = exports.START = 'start';
31
31
  const WRAP_LOGGER = exports.WRAP_LOGGER = 'wrapLogger';
32
- const MEASURE = exports.MEASURE = 'measure';
32
+ const MEASURE = exports.MEASURE = 'measure';
33
+ const CONSENT = exports.CONSENT = 'consent';
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.measure = measure;
6
7
  exports.setupMeasureAPI = setupMeasureAPI;
7
8
  var _handle = require("../../common/event-emitter/handle");
8
9
  var _now = require("../../common/timing/now");
@@ -16,45 +17,45 @@ var _sharedHandlers = require("./sharedHandlers");
16
17
  */
17
18
 
18
19
  function setupMeasureAPI(agent) {
19
- (0, _sharedHandlers.setupAPI)(_constants.MEASURE, function (name, options) {
20
- const n = (0, _now.now)();
21
- const {
22
- start,
23
- end,
24
- customAttributes
25
- } = options || {};
26
- const returnObj = {
27
- customAttributes: customAttributes || {}
28
- };
29
- if (typeof returnObj.customAttributes !== 'object' || typeof name !== 'string' || name.length === 0) {
30
- (0, _console.warn)(57);
31
- return;
32
- }
20
+ (0, _sharedHandlers.setupAPI)(_constants.MEASURE, (name, options) => measure(name, options, agent), agent);
21
+ }
22
+ function measure(name, options, agentRef, target, timestamp = (0, _now.now)()) {
23
+ const {
24
+ start,
25
+ end,
26
+ customAttributes
27
+ } = options || {};
28
+ const returnObj = {
29
+ customAttributes: customAttributes || {}
30
+ };
31
+ if (typeof returnObj.customAttributes !== 'object' || typeof name !== 'string' || name.length === 0) {
32
+ (0, _console.warn)(57);
33
+ return;
34
+ }
33
35
 
34
- /**
36
+ /**
35
37
  * getValueFromTiming - Helper function to extract a numeric value from a supplied option.
36
38
  * @param {Number|PerformanceMark} [timing] The timing value
37
39
  * @param {Number} [d] The default value to return if timing is invalid
38
40
  * @returns {Number} The timing value or the default value
39
41
  */
40
- const getValueFromTiming = (timing, d) => {
41
- if (timing == null) return d;
42
- if (typeof timing === 'number') return timing;
43
- if (timing instanceof PerformanceMark) return timing.startTime;
44
- return Number.NaN;
45
- };
46
- returnObj.start = getValueFromTiming(start, 0);
47
- returnObj.end = getValueFromTiming(end, n);
48
- if (Number.isNaN(returnObj.start) || Number.isNaN(returnObj.end)) {
49
- (0, _console.warn)(57);
50
- return;
51
- }
52
- returnObj.duration = returnObj.end - returnObj.start;
53
- if (returnObj.duration < 0) {
54
- (0, _console.warn)(58);
55
- return;
56
- }
57
- (0, _handle.handle)(_constants.prefix + _constants.MEASURE, [returnObj, name], undefined, _features.FEATURE_NAMES.genericEvents, agent.ee);
58
- return returnObj;
59
- }, agent);
42
+ const getValueFromTiming = (timing, d) => {
43
+ if (timing == null) return d;
44
+ if (typeof timing === 'number') return timing;
45
+ if (timing instanceof PerformanceMark) return timing.startTime;
46
+ return Number.NaN;
47
+ };
48
+ returnObj.start = getValueFromTiming(start, 0);
49
+ returnObj.end = getValueFromTiming(end, timestamp);
50
+ if (Number.isNaN(returnObj.start) || Number.isNaN(returnObj.end)) {
51
+ (0, _console.warn)(57);
52
+ return;
53
+ }
54
+ returnObj.duration = returnObj.end - returnObj.start;
55
+ if (returnObj.duration < 0) {
56
+ (0, _console.warn)(58);
57
+ return;
58
+ }
59
+ (0, _handle.handle)(_constants.prefix + _constants.MEASURE, [returnObj, name, target], undefined, _features.FEATURE_NAMES.genericEvents, agentRef.ee);
60
+ return returnObj;
60
61
  }
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.recordCustomEvent = recordCustomEvent;
6
7
  exports.setupRecordCustomEventAPI = setupRecordCustomEventAPI;
7
8
  var _handle = require("../../common/event-emitter/handle");
8
9
  var _now = require("../../common/timing/now");
@@ -15,7 +16,8 @@ var _sharedHandlers = require("./sharedHandlers");
15
16
  */
16
17
 
17
18
  function setupRecordCustomEventAPI(agent) {
18
- (0, _sharedHandlers.setupAPI)(_constants.RECORD_CUSTOM_EVENT, function () {
19
- (0, _handle.handle)(_constants.prefix + _constants.RECORD_CUSTOM_EVENT, [(0, _now.now)(), ...arguments], undefined, _features.FEATURE_NAMES.genericEvents, agent.ee);
20
- }, agent);
19
+ (0, _sharedHandlers.setupAPI)(_constants.RECORD_CUSTOM_EVENT, (eventType, attributes) => recordCustomEvent(eventType, attributes, agent), agent);
20
+ }
21
+ function recordCustomEvent(eventType, attributes = {}, agentRef, target, timestamp = (0, _now.now)()) {
22
+ (0, _handle.handle)(_constants.prefix + _constants.RECORD_CUSTOM_EVENT, [timestamp, eventType, attributes, target], undefined, _features.FEATURE_NAMES.genericEvents, agentRef.ee);
21
23
  }
@@ -10,26 +10,30 @@ exports.default = void 0;
10
10
  */
11
11
  /**
12
12
  * @typedef {Object} RegisterAPI
13
- * @property {Function} addPageAction - Add a page action for the registered entity.
14
- * @property {Function} log - Capture a log for the registered entity.
15
- * @property {Function} noticeError - Notice an error for the registered entity.
16
- * @property {Function} setApplicationVersion - Add an application.version attribute to all outgoing data for the registered entity.
17
- * @property {Function} setCustomAttribute - Add a custom attribute to outgoing data for the registered entity.
18
- * @property {Function} setUserId - Add an enduser.id attribute to all outgoing API data for the registered entity.
13
+ * @property {(name: string, attributes?: object) => void} addPageAction - Add a page action for the registered entity.
14
+ * @property {(message: string, options?: { customAttributes?: object, level?: 'ERROR' | 'TRACE' | 'DEBUG' | 'INFO' | 'WARN'}) => void} log - Capture a log for the registered entity.
15
+ * @property {(error: Error | string, customAttributes?: object) => void} noticeError - Notice an error for the registered entity.
16
+ * @property {(target: RegisterAPIConstructor) => RegisterAPI} register - Record a custom event for the registered entity.
17
+ * @property {(eventType: string, attributes?: Object) => void} recordCustomEvent - Record a custom event for the registered entity.
18
+ * @property {(eventType: string, options?: {start: number, end: number, duration: number, customAttributes: object}) => ({start: number, end: number, duration: number, customAttributes: object})} measure - Measures a task that is recorded as a BrowserPerformance event.
19
+ * @property {(value: string | null) => void} setApplicationVersion - Add an application.version attribute to all outgoing data for the registered entity.
20
+ * @property {(name: string, value: string | number | boolean | null, persist?: boolean) => void} setCustomAttribute - Add a custom attribute to outgoing data for the registered entity.
21
+ * @property {(value: string | null) => void} setUserId - Add an enduser.id attribute to all outgoing API data for the registered entity.
19
22
  * @property {RegisterAPIMetadata} metadata - The metadata object containing the custom attributes and target information for the registered entity.
20
23
  */
21
24
  /**
22
25
  * @typedef {Object} RegisterAPIConstructor
23
- * @property {Object} opts - The options for the registered entity.
24
- * @property {string} opts.id - The unique id for the registered entity. This will be assigned to any synthesized entities.
25
- * @property {string} opts.name - The readable name for the registered entity. This will be assigned to any synthesized entities.
26
+ * @property {string|number} id - The unique id for the registered entity. This will be assigned to any synthesized entities.
27
+ * @property {string} name - The readable name for the registered entity. This will be assigned to any synthesized entities.
28
+ * @property {string} [parentId] - The parentId for the registered entity. If none was supplied, it will assume the entity guid from the main agent.
26
29
  */
27
30
  /**
28
31
  * @typedef {Object} RegisterAPIMetadata
29
32
  * @property {Object} customAttributes - The custom attributes for the registered entity.
30
33
  * @property {Object} target - The options for the registered entity.
31
- * @property {string} target.licenseKey - The license key for the registered entity. If none was supplied, it will assume the license key from the main agent.
34
+ * @property {string} [target.licenseKey] - The license key for the registered entity. If none was supplied, it will assume the license key from the main agent.
32
35
  * @property {string} target.id - The ID for the registered entity.
33
36
  * @property {string} target.name - The name returned for the registered entity.
37
+ * @property {string} [target.parentId] - The parentId for the registered entity. If none was supplied, it will assume the entity guid from the main agent.
34
38
  */
35
39
  var _default = exports.default = {};
@@ -3,7 +3,6 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.buildRegisterApi = buildRegisterApi;
7
6
  exports.setupRegisterAPI = setupRegisterAPI;
8
7
  var _handle = require("../../common/event-emitter/handle");
9
8
  var _console = require("../../common/util/console");
@@ -17,6 +16,8 @@ var _log = require("./log");
17
16
  var _addPageAction = require("./addPageAction");
18
17
  var _noticeError = require("./noticeError");
19
18
  var _invoke = require("../../common/util/invoke");
19
+ var _measure = require("./measure");
20
+ var _recordCustomEvent = require("./recordCustomEvent");
20
21
  /**
21
22
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
22
23
  * SPDX-License-Identifier: Apache-2.0
@@ -33,7 +34,7 @@ var _invoke = require("../../common/util/invoke");
33
34
  */
34
35
  function setupRegisterAPI(agent) {
35
36
  (0, _sharedHandlers.setupAPI)(_constants2.REGISTER, function (target) {
36
- return buildRegisterApi(agent, target);
37
+ return register(agent, target);
37
38
  }, agent);
38
39
  }
39
40
 
@@ -41,19 +42,18 @@ function setupRegisterAPI(agent) {
41
42
  * Builds the api object that will be returned from the register api method.
42
43
  * Also conducts certain side-effects, such as harvesting a PageView event when triggered and gathering metadata for the registered entity.
43
44
  * @param {Object} agentRef the reference to the base agent instance
44
- * @param {Object} handlers the shared handlers to be used by both the base agent's API and the external target's API
45
- * @param {Object} target the target information to be used by the external target's API to send data to the correct location
46
- * @param {string} [target.licenseKey] the license key of the target to report data to
47
- * @param {string} target.id the entity ID of the target to report data to
48
- * @param {string} target.name the entity name of the target to report data to
45
+ * @param {import('./register-api-types').RegisterAPIConstructor} target
46
+ * @param {import('./register-api-types').RegisterAPIConstructor} [parent]
49
47
  * @returns {RegisterAPI} the api object to be returned from the register api method
50
48
  */
51
- function buildRegisterApi(agentRef, target) {
49
+ function register(agentRef, target, parent) {
52
50
  const attrs = {};
53
51
  (0, _console.warn)(54, 'newrelic.register');
54
52
  target ||= {};
53
+ target.eventSource = 'MicroFrontendBrowserAgent';
55
54
  target.licenseKey ||= agentRef.info.licenseKey; // will inherit the license key from the container agent if not provided for brevity. A future state may dictate that we need different license keys to do different things.
56
55
  target.blocked = false;
56
+ target.parent = parent || {};
57
57
 
58
58
  /** @type {Function} a function that is set and reports when APIs are triggered -- warns the customer of the invalid state */
59
59
  let invalidApiResponse = () => {};
@@ -86,6 +86,9 @@ function buildRegisterApi(agentRef, target) {
86
86
  /** primary cases that can block the register API from working at init time */
87
87
  if (!agentRef.init.api.allow_registered_children) block((0, _invoke.single)(() => (0, _console.warn)(55)));
88
88
  if (!(0, _mfe.isValidMFETarget)(target)) block((0, _invoke.single)(() => (0, _console.warn)(48, target)));
89
+ if (!(0, _mfe.hasValidValue)(target.id) || !(0, _mfe.hasValidValue)(target.name)) {
90
+ block((0, _invoke.single)(() => (0, _console.warn)(48, target)));
91
+ }
89
92
 
90
93
  /** @type {RegisterAPI} */
91
94
  const api = {
@@ -100,10 +103,22 @@ function buildRegisterApi(agentRef, target) {
100
103
  ...(options.customAttributes || {})
101
104
  }
102
105
  }, agentRef], target),
106
+ measure: (name, options = {}) => report(_measure.measure, [name, {
107
+ ...options,
108
+ customAttributes: {
109
+ ...attrs,
110
+ ...(options.customAttributes || {})
111
+ }
112
+ }, agentRef], target),
103
113
  noticeError: (error, attributes = {}) => report(_noticeError.noticeError, [error, {
104
114
  ...attrs,
105
115
  ...attributes
106
116
  }, agentRef], target),
117
+ register: (target = {}) => report(register, [agentRef, target], api.metadata.target),
118
+ recordCustomEvent: (eventType, attributes = {}) => report(_recordCustomEvent.recordCustomEvent, [eventType, {
119
+ ...attrs,
120
+ ...attributes
121
+ }, agentRef], target),
107
122
  setApplicationVersion: value => setLocalValue('application.version', value),
108
123
  setCustomAttribute: (key, value) => setLocalValue(key, value),
109
124
  setUserId: value => setLocalValue('enduser.id', value),
@@ -151,8 +166,8 @@ function buildRegisterApi(agentRef, target) {
151
166
  const timestamp = (0, _now.now)();
152
167
  (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ["API/register/".concat(methodToCall.name, "/called")], undefined, _features.FEATURE_NAMES.metrics, agentRef.ee);
153
168
  try {
154
- const shouldDuplicate = agentRef.init.api.duplicate_registered_data;
155
- if (shouldDuplicate === true || Array.isArray(shouldDuplicate)) {
169
+ const shouldDuplicate = agentRef.init.api.duplicate_registered_data && methodToCall.name !== 'register';
170
+ if (shouldDuplicate) {
156
171
  // also report to container by providing undefined target
157
172
  methodToCall(...args, undefined, timestamp);
158
173
  }
@@ -37,11 +37,8 @@ class ApiBase {
37
37
  * It is not recommended for use in production environments and will not receive support for issues.
38
38
  *
39
39
  * Registers an external caller to report through the base agent to a different target than the base agent.
40
- * @param {object} target the target object to report data to
41
- * @param {string} target.licenseKey The licenseKey to report data to
42
- * @param {string} target.applicationID The applicationID to report data to
43
- * @param {string=} target.entityGuid The entityGuid to report data to
44
- * @returns {object} Returns an object that contains the available API methods and configurations to use with the external caller. See loaders/api/api.js for more information.
40
+ * @param {import('./api/register-api-types').RegisterAPIConstructor} target the target object to report data to
41
+ @returns {import('./api/register-api-types').RegisterAPI} Returns an object that contains the available API methods and configurations to use with the external caller. See loaders/api/api.js for more information.
45
42
  */
46
43
  register(target) {
47
44
  return this.#callMethod(_constants.REGISTER, target);
@@ -51,7 +48,7 @@ class ApiBase {
51
48
  * Records a custom event with a specified eventType and attributes.
52
49
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/recordCustomEvent/}
53
50
  * @param {string} eventType The eventType to store the event as.
54
- * @param {object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}.
51
+ * @param {Object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}.
55
52
  */
56
53
  recordCustomEvent(eventType, attributes) {
57
54
  return this.#callMethod(_constants.RECORD_CUSTOM_EVENT, eventType, attributes);
@@ -227,11 +224,21 @@ class ApiBase {
227
224
  * Measures a task that is recorded as a BrowserPerformance event.
228
225
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/measure/}
229
226
  * @param {string} name The name of the task
230
- * @param {object?} options An object used to control the way the measure API operates
227
+ * @param {{start: number, end: number, duration: number, customAttributes: object}} [options] An object used to control the way the measure API operates
231
228
  * @returns {{start: number, end: number, duration: number, customAttributes: object}} Measurement details
232
229
  */
233
230
  measure(name, options) {
234
231
  return this.#callMethod(_constants.MEASURE, name, options);
235
232
  }
233
+
234
+ /**
235
+ * Accepts or rejects consent when the agent is configured to require consent before harvesting.
236
+ * The consent state is stored in session storage inside the NRBA_SESSION object.
237
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/consent/}
238
+ * @param {boolean?} accept Whether to accept or reject consent. Defaults to true (accept) if left undefined.
239
+ */
240
+ consent(accept) {
241
+ return this.#callMethod(_constants.CONSENT, accept);
242
+ }
236
243
  }
237
244
  exports.ApiBase = ApiBase;
@@ -84,6 +84,8 @@
84
84
  * @property {boolean} [spa.enabled] - Turn on/off the single page application feature (on by default). NOTE: the SPA feature is deprecated and under removal procedure.
85
85
  * @property {boolean} [spa.autoStart] - If true, the agent will automatically start the single page application feature. Otherwise, it will be in a deferred state until the `start` API method is called.
86
86
  * @property {boolean} [ssl] - If explicitly false, the agent will use HTTP instead of HTTPS. This setting should NOT be used.
87
+ * @property {Object} [browser_consent_mode]
88
+ * @property {boolean} [browser_consent_mode.enabled] - If true, the agent will use consent mode for whether to allow or disallow data harvest.
87
89
  * @property {Object} [user_actions]
88
90
  * @property {boolean} [user_actions.enabled] - Must be true to allow UserAction events to be captured.
89
91
  * @property {Array<string>} [user_actions.elementAttributes] - List of HTML Element properties to be captured with UserAction events' target elements. This may help to identify the source element being interacted with in the UI.
@@ -62,6 +62,9 @@ const InitModelFn = () => {
62
62
  },
63
63
  duplicate_registered_data: false
64
64
  },
65
+ browser_consent_mode: {
66
+ enabled: false
67
+ },
65
68
  distributed_tracing: {
66
69
  enabled: undefined,
67
70
  exclude_newrelic_header: undefined,
@@ -17,9 +17,18 @@ const ReadOnly = {
17
17
  version: VERSION,
18
18
  originTime
19
19
  };
20
+ const hiddenState = {
21
+ consented: false
22
+ };
20
23
  const RuntimeModel = {
21
24
  /** Agent-specific metadata found in the RUM call response. ex. entityGuid */
22
25
  appMetadata: {},
26
+ get consented() {
27
+ return this.session?.state?.consent || hiddenState.consented;
28
+ },
29
+ set consented(value) {
30
+ hiddenState.consented = value;
31
+ },
23
32
  customTransaction: undefined,
24
33
  denyList: undefined,
25
34
  disabled: false,
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.302.0";
14
+ export const VERSION = "1.303.0-rc.1";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.302.0";
14
+ export const VERSION = "1.303.0-rc.1";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -17,8 +17,10 @@ import { stringify } from '../util/stringify';
17
17
  import { getSubmitMethod, xhr as xhrMethod, xhrFetch as fetchMethod } from '../util/submit-data';
18
18
  import { activatedFeatures } from '../util/feature-flags';
19
19
  import { dispatchGlobalEvent } from '../dispatch/global-event';
20
- const RETRY_FAILED = 'Harvester/Retry/Failed/';
21
- const RETRY_SUCCEEDED = 'Harvester/Retry/Succeeded/';
20
+ const RETRY = 'Harvester/Retry/';
21
+ const RETRY_ATTEMPTED = RETRY + 'Attempted/';
22
+ const RETRY_FAILED = RETRY + 'Failed/';
23
+ const RETRY_SUCCEEDED = RETRY + 'Succeeded/';
22
24
  export class Harvester {
23
25
  #started = false;
24
26
  initializedAggregates = [];
@@ -59,11 +61,11 @@ export class Harvester {
59
61
  endpointVersion: aggregateInst.harvestEndpointVersion || 1
60
62
  };
61
63
  if (aggregateInst.blocked) return output;
64
+ if (this.agentRef.init?.browser_consent_mode?.enabled && !this.agentRef.runtime.consented) return output;
62
65
  const submitMethod = getSubmitMethod(localOpts);
63
66
  if (!submitMethod) return output;
64
67
  const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === xhrMethod; // always retry all features harvests except for final
65
- output.payload = !localOpts.directSend ? aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts) : localOpts.directSend?.payload; // features like PVE can define the payload directly, bypassing the makeHarvestPayload logic
66
-
68
+ output.payload = aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts);
67
69
  if (!output.payload) return output;
68
70
  send(this.agentRef, {
69
71
  endpoint: FEATURE_TO_ENDPOINT[aggregateInst.featureName],
@@ -85,7 +87,9 @@ export class Harvester {
85
87
  function cbFinished(result) {
86
88
  if (aggregateInst.harvestOpts.prevAttemptCode) {
87
89
  // this means we just retried a harvest that last failed
88
- handle(SUPPORTABILITY_METRIC_CHANNEL, [(result.retry ? RETRY_FAILED : RETRY_SUCCEEDED) + aggregateInst.harvestOpts.prevAttemptCode], undefined, FEATURE_NAMES.metrics, aggregateInst.ee);
90
+ const reportSM = message => handle(SUPPORTABILITY_METRIC_CHANNEL, [message], undefined, FEATURE_NAMES.metrics, aggregateInst.ee);
91
+ reportSM(RETRY_ATTEMPTED + aggregateInst.featureName);
92
+ reportSM((result.retry ? RETRY_FAILED : RETRY_SUCCEEDED) + aggregateInst.harvestOpts.prevAttemptCode);
89
93
  delete aggregateInst.harvestOpts.prevAttemptCode; // always reset last observation so we don't falsely report again next harvest
90
94
  // In case this re-attempt failed again, that'll be handled (re-marked again) next.
91
95
  }
@@ -175,9 +179,9 @@ export function send(agentRef, {
175
179
  status: this.status,
176
180
  retry: shouldRetry(this.status),
177
181
  fullUrl,
178
- xhr: this
182
+ xhr: this,
183
+ responseText: this.responseText
179
184
  };
180
- if (localOpts.needResponse) cbResult.responseText = this.responseText;
181
185
  cbFinished(cbResult);
182
186
 
183
187
  /** temporary audit of consistency of harvest metadata flags */
@@ -191,9 +195,9 @@ export function send(agentRef, {
191
195
  status,
192
196
  retry: shouldRetry(status),
193
197
  fullUrl,
194
- fetchResponse: response
198
+ fetchResponse: response,
199
+ responseText: await response.text()
195
200
  };
196
- if (localOpts.needResponse) cbResult.responseText = await response.text();
197
201
  cbFinished(cbResult);
198
202
  /** temporary audit of consistency of harvest metadata flags */
199
203
  if (!shouldRetry(status)) trackHarvestMetadata();
@@ -24,7 +24,6 @@
24
24
  * @property {HarvestEndpointIdentifier} endpoint The endpoint to use (jserrors, events, resources etc.)
25
25
  * @property {HarvestPayload} payload Object representing payload.
26
26
  * @property {object} localOpts Additional options for sending data
27
- * @property {boolean} localOpts.needResponse Specify whether the caller expects a response data.
28
27
  * @property {boolean} localOpts.isFinalHarvest Specify whether the call is a final harvest during page unload.
29
28
  * @property {boolean} localOpts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
30
29
  * @property {boolean} localOpts.forceNoRetry Don't save the buffered data in the case of a need to retry the transmission.
@@ -33,7 +33,8 @@ const model = {
33
33
  serverTimeDiff: null,
34
34
  // set by TimeKeeper; "undefined" value will not be stringified and stored but "null" will
35
35
  custom: {},
36
- numOfResets: 0
36
+ numOfResets: 0,
37
+ consent: false // set by consent() API call
37
38
  };
38
39
  export class SessionEntity {
39
40
  /**
@@ -84,7 +85,8 @@ export class SessionEntity {
84
85
  }) {
85
86
  /** Ensure that certain properties are preserved across a reset if already set */
86
87
  const persistentAttributes = {
87
- serverTimeDiff: this.state.serverTimeDiff || model.serverTimeDiff
88
+ serverTimeDiff: this.state.serverTimeDiff || model.serverTimeDiff,
89
+ consent: this.state.consent || model.consent
88
90
  };
89
91
  this.state = {};
90
92
  this.sync({
@@ -10,9 +10,14 @@
10
10
  export function isValidMFETarget(target = {}) {
11
11
  return !!(target.id && target.name);
12
12
  }
13
+ export function hasValidValue(val) {
14
+ return typeof val === 'string' && val.trim().length < 501 || typeof val === 'number';
15
+ }
13
16
 
14
17
  /**
15
18
  * When given a valid target, returns an object with the MFE payload attributes. Returns an empty object otherwise.
19
+ * @note Field names may change as the schema is finalized
20
+ *
16
21
  * @param {Object} [target] the registered target
17
22
  * @param {AggregateInstance} [aggregateInstance] the aggregate instance calling the method
18
23
  * @returns {{'mfe.id': *, 'mfe.name': String}|{}} returns an empty object if args are not supplied or the aggregate instance is not supporting version 2
@@ -28,11 +33,8 @@ export function getVersion2Attributes(target, aggregateInstance) {
28
33
  }
29
34
  return {
30
35
  'mfe.id': target.id,
31
- // these field names may change as the schema is finalized
32
36
  'mfe.name': target.name,
33
- // these field names may change as the schema is finalized
34
- eventSource: 'MicroFrontendBrowserAgent',
35
- // these field names may change as the schema is finalized
36
- 'parent.id': containerAgentEntityGuid
37
+ eventSource: target.eventSource,
38
+ 'parent.id': target.parent?.id || containerAgentEntityGuid
37
39
  };
38
40
  }
@@ -129,12 +129,17 @@ export function wrapPromise(sharedEE) {
129
129
  });
130
130
  promiseEE.on('propagate', function (val, overwrite, trigger) {
131
131
  if (!this.getCtx || overwrite) {
132
- this.getCtx = function () {
133
- // eslint-disable-next-line
134
- if (val instanceof Promise) {
135
- var store = promiseEE.context(val);
132
+ const selfStore = this;
133
+ const parentStore = val instanceof Promise ? promiseEE.context(val) : null;
134
+ let cachedCtx;
135
+ this.getCtx = function getCtx() {
136
+ if (cachedCtx) return cachedCtx;
137
+ if (parentStore && parentStore !== selfStore) {
138
+ cachedCtx = typeof parentStore.getCtx === 'function' ? parentStore.getCtx() : parentStore;
139
+ } else {
140
+ cachedCtx = selfStore;
136
141
  }
137
- return store && store.getCtx ? store.getCtx() : this;
142
+ return cachedCtx;
138
143
  };
139
144
  }
140
145
  });
@@ -28,13 +28,13 @@ export class Aggregate extends AggregateBase {
28
28
  return;
29
29
  }
30
30
  this.#trackSupportabilityMetrics();
31
- registerHandler('api-recordCustomEvent', (timestamp, eventType, attributes) => {
31
+ registerHandler('api-recordCustomEvent', (timestamp, eventType, attributes, target) => {
32
32
  if (RESERVED_EVENT_TYPES.includes(eventType)) return warn(46);
33
33
  this.addEvent({
34
34
  eventType,
35
35
  timestamp: this.toEpoch(timestamp),
36
36
  ...attributes
37
- });
37
+ }, target);
38
38
  }, this.featureName, this.ee);
39
39
  if (agentRef.init.page_action.enabled) {
40
40
  registerHandler('api-addPageAction', (timestamp, name, attributes, target) => {
@@ -231,7 +231,7 @@ export class Aggregate extends AggregateBase {
231
231
  }
232
232
  }, this.featureName, this.ee);
233
233
  }
234
- registerHandler('api-measure', (args, n) => {
234
+ registerHandler('api-measure', (args, n, target) => {
235
235
  const {
236
236
  start,
237
237
  duration,
@@ -245,7 +245,7 @@ export class Aggregate extends AggregateBase {
245
245
  entryDuration: duration,
246
246
  entryType: 'measure'
247
247
  };
248
- this.addEvent(event);
248
+ this.addEvent(event, target);
249
249
  }, this.featureName, this.ee);
250
250
  this.drain();
251
251
  });
@@ -97,8 +97,7 @@ export class Aggregate extends AggregateBase {
97
97
  common: {
98
98
  /** Attributes in the `common` section are added to `all` logs generated in the payload */
99
99
  attributes: {
100
- ...this.agentRef.info.jsAttributes,
101
- // user-provided custom attributes
100
+ ...applyFnToProps(this.agentRef.info.jsAttributes, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string'),
102
101
  ...(this.harvestEndpointVersion === 1 && {
103
102
  'entity.guid': this.agentRef.runtime.appMetadata.agents[0].entityGuid,
104
103
  appId: this.agentRef.info.applicationID