@newrelic/browser-agent 1.298.0-rc.0 → 1.298.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.298.0-rc.0";
20
+ const VERSION = exports.VERSION = "1.298.0-rc.2";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.298.0-rc.0";
20
+ const VERSION = exports.VERSION = "1.298.0-rc.2";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -153,14 +153,16 @@ function send(agentRef, {
153
153
  }
154
154
  const fullUrl = "".concat(url, "?").concat(baseParams).concat(payloadParams);
155
155
  const gzip = !!qs?.attributes?.includes('gzip');
156
- if (!gzip) {
157
- if (endpoint !== _features.EVENTS) body = (0, _stringify.stringify)(body); // all features going to 'events' endpoint should already be serialized & stringified
158
- // Warn--once per endpoint--if the agent tries to send large payloads
159
- if (body.length > 750000 && (warnings[endpoint] = (warnings[endpoint] || 0) + 1) === 1) (0, _console.warn)(28, endpoint);
160
- }
156
+
157
+ // all gzipped data is already in the correct format and needs no transformation
158
+ // all features going to 'events' endpoint should already be serialized & stringified
159
+ let stringBody = gzip || endpoint === _features.EVENTS ? body : (0, _stringify.stringify)(body);
161
160
 
162
161
  // If body is null, undefined, or an empty object or array after stringifying, send an empty string instead.
163
- if (!body || body.length === 0 || body === '{}' || body === '[]') body = '';
162
+ if (!stringBody || stringBody.length === 0 || stringBody === '{}' || stringBody === '[]') stringBody = '';
163
+
164
+ // Warn--once per endpoint--if the agent tries to send large payloads
165
+ if (endpoint !== _features.BLOBS && stringBody.length > 750000 && (warnings[endpoint] = (warnings[endpoint] || 0) + 1) === 1) (0, _console.warn)(28, endpoint);
164
166
  const headers = [{
165
167
  key: 'content-type',
166
168
  value: 'text/plain'
@@ -172,7 +174,7 @@ function send(agentRef, {
172
174
  Following the removal of img-element method. */
173
175
  let result = submitMethod({
174
176
  url: fullUrl,
175
- body,
177
+ body: stringBody,
176
178
  sync: localOpts.isFinalHarvest && _runtime.isWorkerScope,
177
179
  headers
178
180
  });
@@ -192,6 +194,9 @@ function send(agentRef, {
192
194
  };
193
195
  if (localOpts.needResponse) cbResult.responseText = this.responseText;
194
196
  cbFinished(cbResult);
197
+
198
+ /** temporary audit of consistency of harvest metadata flags */
199
+ if (!shouldRetry(this.status)) trackHarvestMetadata();
195
200
  }, (0, _eventListenerOpts.eventListenerOpts)(false));
196
201
  } else if (submitMethod === _submitData.xhrFetch) {
197
202
  result.then(async function (response) {
@@ -206,8 +211,33 @@ function send(agentRef, {
206
211
  };
207
212
  if (localOpts.needResponse) cbResult.responseText = await response.text();
208
213
  cbFinished(cbResult);
214
+ /** temporary audit of consistency of harvest metadata flags */
215
+ if (!shouldRetry(status)) trackHarvestMetadata();
209
216
  });
210
217
  }
218
+ function trackHarvestMetadata() {
219
+ try {
220
+ if (featureName === _features.FEATURE_NAMES.jserrors && !body?.err) return;
221
+ const hasReplay = baseParams.includes('hr=1');
222
+ const hasTrace = baseParams.includes('ht=1');
223
+ const hasError = qs?.attributes?.includes('hasError=true');
224
+ (0, _handle.handle)('harvest-metadata', [{
225
+ [featureName]: {
226
+ ...(hasReplay && {
227
+ hasReplay
228
+ }),
229
+ ...(hasTrace && {
230
+ hasTrace
231
+ }),
232
+ ...(hasError && {
233
+ hasError
234
+ })
235
+ }
236
+ }], undefined, _features.FEATURE_NAMES.metrics, agentRef.ee);
237
+ } catch (err) {
238
+ // do nothing
239
+ }
240
+ }
211
241
  }
212
242
  (0, _globalEvent.dispatchGlobalEvent)({
213
243
  agentIdentifier: agentRef.agentIdentifier,
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.evaluateHarvestMetadata = evaluateHarvestMetadata;
7
+ /**
8
+ * Copyright 2020-2025 New Relic, Inc. All rights reserved.
9
+ * SPDX-License-Identifier: Apache-2.0
10
+ */
11
+
12
+ function evaluateHarvestMetadata(pageMetadata) {
13
+ try {
14
+ const supportabilityTags = [];
15
+
16
+ // Report SM like... audit/<feature_name>/<hasReplay|hasTrace|hasError>/<true|false>/<negative|positive>
17
+ const formTag = (...strings) => strings.join('/');
18
+
19
+ // Track if replay/trace/error harvests actually occurred (key only exists when harvested)
20
+ function evaluateTag(feature, flag, hasFlag, hasHarvest) {
21
+ const AUDIT = 'audit';
22
+ if (hasFlag) {
23
+ // False positive: flag true, but no harvest
24
+ if (!hasHarvest) supportabilityTags.push(formTag(AUDIT, feature, flag, 'false', 'positive'));
25
+ // True positive (correct)
26
+ else supportabilityTags.push(formTag(AUDIT, feature, flag, 'true', 'positive'));
27
+ } else {
28
+ // False negative: flag false, but harvest occurred
29
+ if (hasHarvest) supportabilityTags.push(formTag(AUDIT, feature, flag, 'false', 'negative'));
30
+ // True negative (correct)
31
+ else supportabilityTags.push(formTag(AUDIT, feature, flag, 'true', 'negative'));
32
+ }
33
+ }
34
+ if (pageMetadata.page_view_event) {
35
+ evaluateTag('page_view', 'hasReplay', pageMetadata.page_view_event.hasReplay, !!pageMetadata.session_replay);
36
+ evaluateTag('page_view', 'hasTrace', pageMetadata.page_view_event.hasTrace, !!pageMetadata.session_trace);
37
+ }
38
+ if (pageMetadata.session_replay) {
39
+ evaluateTag('session_replay', 'hasError', pageMetadata.session_replay.hasError, !!pageMetadata.jserrors);
40
+ }
41
+ return supportabilityTags;
42
+ } catch (err) {
43
+ return [];
44
+ }
45
+ }
@@ -13,6 +13,7 @@ var _eventListenerOpts = require("../../../common/event-listener/event-listener-
13
13
  var _runtime = require("../../../common/constants/runtime");
14
14
  var _aggregateBase = require("../../utils/aggregate-base");
15
15
  var _iframe = require("../../../common/dom/iframe");
16
+ var _harvestMetadata = require("./harvest-metadata");
16
17
  /**
17
18
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
18
19
  * SPDX-License-Identifier: Apache-2.0
@@ -26,6 +27,15 @@ class Aggregate extends _aggregateBase.AggregateBase {
26
27
  constructor(agentRef) {
27
28
  super(agentRef, _constants.FEATURE_NAME);
28
29
  this.harvestOpts.aggregatorTypes = ['cm', 'sm']; // the types in EventAggregator this feature cares about
30
+
31
+ /** all the harvest metadata metrics need to be evaluated simulataneously at unload time so just temporarily buffer them and dont make SMs immediately from the data */
32
+ this.harvestMetadata = {};
33
+ this.harvestOpts.beforeUnload = () => {
34
+ (0, _harvestMetadata.evaluateHarvestMetadata)(this.harvestMetadata).forEach(smTag => {
35
+ this.storeSupportabilityMetrics(smTag);
36
+ });
37
+ };
38
+
29
39
  // This feature only harvests once per potential EoL of the page, which is handled by the central harvester.
30
40
 
31
41
  // this must be read/stored synchronously, as the currentScript is removed from the DOM after this script is executed and this lookup will be void
@@ -145,6 +155,17 @@ class Aggregate extends _aggregateBase.AggregateBase {
145
155
  // handleWebsocketEvents(this.storeSupportabilityMetrics.bind(this), tag, ...args)
146
156
  // }, this.featureName, this.ee)
147
157
  // })
158
+
159
+ /** all the harvest metadata metrics need to be evaluated simulataneously at unload time so just temporarily buffer them and dont make SMs immediately from the data */
160
+ (0, _registerHandler.registerHandler)('harvest-metadata', (harvestMetadataObject = {}) => {
161
+ try {
162
+ Object.keys(harvestMetadataObject).forEach(key => {
163
+ Object.assign(this.harvestMetadata[key] ??= {}, harvestMetadataObject[key]);
164
+ });
165
+ } catch (e) {
166
+ // failed to merge harvest metadata... ignore
167
+ }
168
+ }, this.featureName, this.ee);
148
169
  }
149
170
  eachSessionChecks() {
150
171
  if (!_runtime.isBrowserScope) return;
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.298.0-rc.0";
14
+ export const VERSION = "1.298.0-rc.2";
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.298.0-rc.0";
14
+ export const VERSION = "1.298.0-rc.2";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -145,14 +145,16 @@ export function send(agentRef, {
145
145
  }
146
146
  const fullUrl = "".concat(url, "?").concat(baseParams).concat(payloadParams);
147
147
  const gzip = !!qs?.attributes?.includes('gzip');
148
- if (!gzip) {
149
- if (endpoint !== EVENTS) body = stringify(body); // all features going to 'events' endpoint should already be serialized & stringified
150
- // Warn--once per endpoint--if the agent tries to send large payloads
151
- if (body.length > 750000 && (warnings[endpoint] = (warnings[endpoint] || 0) + 1) === 1) warn(28, endpoint);
152
- }
148
+
149
+ // all gzipped data is already in the correct format and needs no transformation
150
+ // all features going to 'events' endpoint should already be serialized & stringified
151
+ let stringBody = gzip || endpoint === EVENTS ? body : stringify(body);
153
152
 
154
153
  // If body is null, undefined, or an empty object or array after stringifying, send an empty string instead.
155
- if (!body || body.length === 0 || body === '{}' || body === '[]') body = '';
154
+ if (!stringBody || stringBody.length === 0 || stringBody === '{}' || stringBody === '[]') stringBody = '';
155
+
156
+ // Warn--once per endpoint--if the agent tries to send large payloads
157
+ if (endpoint !== BLOBS && stringBody.length > 750000 && (warnings[endpoint] = (warnings[endpoint] || 0) + 1) === 1) warn(28, endpoint);
156
158
  const headers = [{
157
159
  key: 'content-type',
158
160
  value: 'text/plain'
@@ -164,7 +166,7 @@ export function send(agentRef, {
164
166
  Following the removal of img-element method. */
165
167
  let result = submitMethod({
166
168
  url: fullUrl,
167
- body,
169
+ body: stringBody,
168
170
  sync: localOpts.isFinalHarvest && isWorkerScope,
169
171
  headers
170
172
  });
@@ -184,6 +186,9 @@ export function send(agentRef, {
184
186
  };
185
187
  if (localOpts.needResponse) cbResult.responseText = this.responseText;
186
188
  cbFinished(cbResult);
189
+
190
+ /** temporary audit of consistency of harvest metadata flags */
191
+ if (!shouldRetry(this.status)) trackHarvestMetadata();
187
192
  }, eventListenerOpts(false));
188
193
  } else if (submitMethod === fetchMethod) {
189
194
  result.then(async function (response) {
@@ -198,8 +203,33 @@ export function send(agentRef, {
198
203
  };
199
204
  if (localOpts.needResponse) cbResult.responseText = await response.text();
200
205
  cbFinished(cbResult);
206
+ /** temporary audit of consistency of harvest metadata flags */
207
+ if (!shouldRetry(status)) trackHarvestMetadata();
201
208
  });
202
209
  }
210
+ function trackHarvestMetadata() {
211
+ try {
212
+ if (featureName === FEATURE_NAMES.jserrors && !body?.err) return;
213
+ const hasReplay = baseParams.includes('hr=1');
214
+ const hasTrace = baseParams.includes('ht=1');
215
+ const hasError = qs?.attributes?.includes('hasError=true');
216
+ handle('harvest-metadata', [{
217
+ [featureName]: {
218
+ ...(hasReplay && {
219
+ hasReplay
220
+ }),
221
+ ...(hasTrace && {
222
+ hasTrace
223
+ }),
224
+ ...(hasError && {
225
+ hasError
226
+ })
227
+ }
228
+ }], undefined, FEATURE_NAMES.metrics, agentRef.ee);
229
+ } catch (err) {
230
+ // do nothing
231
+ }
232
+ }
203
233
  }
204
234
  dispatchGlobalEvent({
205
235
  agentIdentifier: agentRef.agentIdentifier,
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright 2020-2025 New Relic, Inc. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ export function evaluateHarvestMetadata(pageMetadata) {
7
+ try {
8
+ const supportabilityTags = [];
9
+
10
+ // Report SM like... audit/<feature_name>/<hasReplay|hasTrace|hasError>/<true|false>/<negative|positive>
11
+ const formTag = (...strings) => strings.join('/');
12
+
13
+ // Track if replay/trace/error harvests actually occurred (key only exists when harvested)
14
+ function evaluateTag(feature, flag, hasFlag, hasHarvest) {
15
+ const AUDIT = 'audit';
16
+ if (hasFlag) {
17
+ // False positive: flag true, but no harvest
18
+ if (!hasHarvest) supportabilityTags.push(formTag(AUDIT, feature, flag, 'false', 'positive'));
19
+ // True positive (correct)
20
+ else supportabilityTags.push(formTag(AUDIT, feature, flag, 'true', 'positive'));
21
+ } else {
22
+ // False negative: flag false, but harvest occurred
23
+ if (hasHarvest) supportabilityTags.push(formTag(AUDIT, feature, flag, 'false', 'negative'));
24
+ // True negative (correct)
25
+ else supportabilityTags.push(formTag(AUDIT, feature, flag, 'true', 'negative'));
26
+ }
27
+ }
28
+ if (pageMetadata.page_view_event) {
29
+ evaluateTag('page_view', 'hasReplay', pageMetadata.page_view_event.hasReplay, !!pageMetadata.session_replay);
30
+ evaluateTag('page_view', 'hasTrace', pageMetadata.page_view_event.hasTrace, !!pageMetadata.session_trace);
31
+ }
32
+ if (pageMetadata.session_replay) {
33
+ evaluateTag('session_replay', 'hasError', pageMetadata.session_replay.hasError, !!pageMetadata.jserrors);
34
+ }
35
+ return supportabilityTags;
36
+ } catch (err) {
37
+ return [];
38
+ }
39
+ }
@@ -11,6 +11,7 @@ import { windowAddEventListener } from '../../../common/event-listener/event-lis
11
11
  import { isBrowserScope, isWorkerScope } from '../../../common/constants/runtime';
12
12
  import { AggregateBase } from '../../utils/aggregate-base';
13
13
  import { isIFrameWindow } from '../../../common/dom/iframe';
14
+ import { evaluateHarvestMetadata } from './harvest-metadata';
14
15
  // import { WEBSOCKET_TAG } from '../../../common/wrap/wrap-websocket'
15
16
  // import { handleWebsocketEvents } from './websocket-detection'
16
17
 
@@ -19,6 +20,15 @@ export class Aggregate extends AggregateBase {
19
20
  constructor(agentRef) {
20
21
  super(agentRef, FEATURE_NAME);
21
22
  this.harvestOpts.aggregatorTypes = ['cm', 'sm']; // the types in EventAggregator this feature cares about
23
+
24
+ /** all the harvest metadata metrics need to be evaluated simulataneously at unload time so just temporarily buffer them and dont make SMs immediately from the data */
25
+ this.harvestMetadata = {};
26
+ this.harvestOpts.beforeUnload = () => {
27
+ evaluateHarvestMetadata(this.harvestMetadata).forEach(smTag => {
28
+ this.storeSupportabilityMetrics(smTag);
29
+ });
30
+ };
31
+
22
32
  // This feature only harvests once per potential EoL of the page, which is handled by the central harvester.
23
33
 
24
34
  // this must be read/stored synchronously, as the currentScript is removed from the DOM after this script is executed and this lookup will be void
@@ -138,6 +148,17 @@ export class Aggregate extends AggregateBase {
138
148
  // handleWebsocketEvents(this.storeSupportabilityMetrics.bind(this), tag, ...args)
139
149
  // }, this.featureName, this.ee)
140
150
  // })
151
+
152
+ /** all the harvest metadata metrics need to be evaluated simulataneously at unload time so just temporarily buffer them and dont make SMs immediately from the data */
153
+ registerHandler('harvest-metadata', (harvestMetadataObject = {}) => {
154
+ try {
155
+ Object.keys(harvestMetadataObject).forEach(key => {
156
+ Object.assign(this.harvestMetadata[key] ??= {}, harvestMetadataObject[key]);
157
+ });
158
+ } catch (e) {
159
+ // failed to merge harvest metadata... ignore
160
+ }
161
+ }, this.featureName, this.ee);
141
162
  }
142
163
  eachSessionChecks() {
143
164
  if (!isBrowserScope) return;
@@ -1 +1 @@
1
- {"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init-types.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/attribute-size.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/event-origin.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/monkey-patched.js","../src/common/util/obfuscate.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/target.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-jsonp.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-mutation.js","../src/common/wrap/wrap-promise.js","../src/common/wrap/wrap-timer.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/cause-string.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/aggregate/websocket-detection.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/aggregate/trace/utils.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/spa/constants.js","../src/features/spa/index.js","../src/features/spa/aggregate/index.js","../src/features/spa/aggregate/interaction-node.js","../src/features/spa/aggregate/interaction.js","../src/features/spa/aggregate/serializer.js","../src/features/spa/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/entity-manager.js","../src/features/utils/event-buffer.js","../src/features/utils/event-store-manager.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/features/utils/nr1-debugger.js","../src/interfaces/registered-entity.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/api-base.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/addPageAction.js","../src/loaders/api/addRelease.js","../src/loaders/api/addToTrace.js","../src/loaders/api/constants.js","../src/loaders/api/finished.js","../src/loaders/api/interaction-types.js","../src/loaders/api/interaction.js","../src/loaders/api/log.js","../src/loaders/api/measure.js","../src/loaders/api/noticeError.js","../src/loaders/api/pauseReplay.js","../src/loaders/api/recordCustomEvent.js","../src/loaders/api/recordReplay.js","../src/loaders/api/register-api-types.js","../src/loaders/api/register-api.js","../src/loaders/api/register.js","../src/loaders/api/setApplicationVersion.js","../src/loaders/api/setCustomAttribute.js","../src/loaders/api/setErrorHandler.js","../src/loaders/api/setPageViewName.js","../src/loaders/api/setUserId.js","../src/loaders/api/sharedHandlers.js","../src/loaders/api/start.js","../src/loaders/api/topLevelCallers.js","../src/loaders/api/wrapLogger.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.7.3"}
1
+ {"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init-types.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/attribute-size.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/event-origin.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/monkey-patched.js","../src/common/util/obfuscate.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/target.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-jsonp.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-mutation.js","../src/common/wrap/wrap-promise.js","../src/common/wrap/wrap-timer.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/cause-string.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/harvest-metadata.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/aggregate/websocket-detection.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/aggregate/trace/utils.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/spa/constants.js","../src/features/spa/index.js","../src/features/spa/aggregate/index.js","../src/features/spa/aggregate/interaction-node.js","../src/features/spa/aggregate/interaction.js","../src/features/spa/aggregate/serializer.js","../src/features/spa/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/entity-manager.js","../src/features/utils/event-buffer.js","../src/features/utils/event-store-manager.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/features/utils/nr1-debugger.js","../src/interfaces/registered-entity.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/api-base.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/addPageAction.js","../src/loaders/api/addRelease.js","../src/loaders/api/addToTrace.js","../src/loaders/api/constants.js","../src/loaders/api/finished.js","../src/loaders/api/interaction-types.js","../src/loaders/api/interaction.js","../src/loaders/api/log.js","../src/loaders/api/measure.js","../src/loaders/api/noticeError.js","../src/loaders/api/pauseReplay.js","../src/loaders/api/recordCustomEvent.js","../src/loaders/api/recordReplay.js","../src/loaders/api/register-api-types.js","../src/loaders/api/register-api.js","../src/loaders/api/register.js","../src/loaders/api/setApplicationVersion.js","../src/loaders/api/setCustomAttribute.js","../src/loaders/api/setErrorHandler.js","../src/loaders/api/setPageViewName.js","../src/loaders/api/setUserId.js","../src/loaders/api/sharedHandlers.js","../src/loaders/api/start.js","../src/loaders/api/topLevelCallers.js","../src/loaders/api/wrapLogger.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.7.3"}
@@ -1 +1 @@
1
- {"version":3,"file":"harvester.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/harvester.js"],"names":[],"mappings":"AA6GA;;;;IAII;AACJ;;;;;;;;;IAFc,OAAO,CA+FpB;AAxLD;IAIE,2BAUC;IAZD,6BAA0B;IAGxB,cAAwB;IAW1B,wCASC;IAED;;;;;OAKG;IACH,iCAJW,MAAM,cACN,MAAM,GACJ,OAAO,CA+CnB;;CACF;8BAGY,OAAO,YAAY,EAAE,eAAe"}
1
+ {"version":3,"file":"harvester.d.ts","sourceRoot":"","sources":["../../../../src/common/harvest/harvester.js"],"names":[],"mappings":"AA6GA;;;;IAII;AACJ;;;;;;;;;IAFc,OAAO,CA0HpB;AAnND;IAIE,2BAUC;IAZD,6BAA0B;IAGxB,cAAwB;IAW1B,wCASC;IAED;;;;;OAKG;IACH,iCAJW,MAAM,cACN,MAAM,GACJ,OAAO,CA+CnB;;CACF;8BAGY,OAAO,YAAY,EAAE,eAAe"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright 2020-2025 New Relic, Inc. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ export function evaluateHarvestMetadata(pageMetadata: any): any[];
6
+ //# sourceMappingURL=harvest-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harvest-metadata.d.ts","sourceRoot":"","sources":["../../../../../src/features/metrics/aggregate/harvest-metadata.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kEAoCC"}
@@ -1,6 +1,8 @@
1
1
  export class Aggregate extends AggregateBase {
2
2
  static featureName: string;
3
3
  constructor(agentRef: any);
4
+ /** all the harvest metadata metrics need to be evaluated simulataneously at unload time so just temporarily buffer them and dont make SMs immediately from the data */
5
+ harvestMetadata: {};
4
6
  agentNonce: string | false | undefined;
5
7
  preHarvestChecks(opts: any): any;
6
8
  storeSupportabilityMetrics(name: any, value: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/metrics/aggregate/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAAiC;IACjC,2BAuBC;IAhBC,uCAAiE;IAkBnE,iCAAsE;IAEtE,wDAKC;IAED,iDAKC;IAED,qBAqEC;IAED,0BAOC;CACF;8BA/H6B,4BAA4B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/metrics/aggregate/index.js"],"names":[],"mappings":"AAiBA;IACE,2BAAiC;IACjC,2BAgCC;IA5BC,uKAAuK;IACvK,oBAAyB;IAWzB,uCAAiE;IAkBnE,iCAAsE;IAEtE,wDAKC;IAED,iDAKC;IAED,qBAgFC;IAED,0BAOC;CACF;8BApJ6B,4BAA4B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.298.0-rc.0",
3
+ "version": "1.298.0-rc.2",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -135,14 +135,16 @@ export function send (agentRef, { endpoint, targetApp, payload, localOpts = {},
135
135
 
136
136
  const fullUrl = `${url}?${baseParams}${payloadParams}`
137
137
  const gzip = !!qs?.attributes?.includes('gzip')
138
- if (!gzip) {
139
- if (endpoint !== EVENTS) body = stringify(body) // all features going to 'events' endpoint should already be serialized & stringified
140
- // Warn--once per endpoint--if the agent tries to send large payloads
141
- if (body.length > 750000 && (warnings[endpoint] = (warnings[endpoint] || 0) + 1) === 1) warn(28, endpoint)
142
- }
138
+
139
+ // all gzipped data is already in the correct format and needs no transformation
140
+ // all features going to 'events' endpoint should already be serialized & stringified
141
+ let stringBody = gzip || endpoint === EVENTS ? body : stringify(body)
143
142
 
144
143
  // If body is null, undefined, or an empty object or array after stringifying, send an empty string instead.
145
- if (!body || body.length === 0 || body === '{}' || body === '[]') body = ''
144
+ if (!stringBody || stringBody.length === 0 || stringBody === '{}' || stringBody === '[]') stringBody = ''
145
+
146
+ // Warn--once per endpoint--if the agent tries to send large payloads
147
+ if (endpoint !== BLOBS && stringBody.length > 750000 && (warnings[endpoint] = (warnings[endpoint] || 0) + 1) === 1) warn(28, endpoint)
146
148
 
147
149
  const headers = [{ key: 'content-type', value: 'text/plain' }]
148
150
 
@@ -150,7 +152,7 @@ export function send (agentRef, { endpoint, targetApp, payload, localOpts = {},
150
152
  Because they still do permit synch XHR, the idea is that at final harvest time (worker is closing),
151
153
  we just make a BLOCKING request--trivial impact--with the remaining data as a temp fill-in for sendBeacon.
152
154
  Following the removal of img-element method. */
153
- let result = submitMethod({ url: fullUrl, body, sync: localOpts.isFinalHarvest && isWorkerScope, headers })
155
+ let result = submitMethod({ url: fullUrl, body: stringBody, sync: localOpts.isFinalHarvest && isWorkerScope, headers })
154
156
 
155
157
  if (!localOpts.isFinalHarvest && cbFinished) { // final harvests don't hold onto buffer data (shouldRetryOnFail is false), so cleanup isn't needed
156
158
  if (submitMethod === xhrMethod) {
@@ -160,6 +162,9 @@ export function send (agentRef, { endpoint, targetApp, payload, localOpts = {},
160
162
  const cbResult = { sent: this.status !== 0, status: this.status, retry: shouldRetry(this.status), fullUrl, xhr: this, targetApp }
161
163
  if (localOpts.needResponse) cbResult.responseText = this.responseText
162
164
  cbFinished(cbResult)
165
+
166
+ /** temporary audit of consistency of harvest metadata flags */
167
+ if (!shouldRetry(this.status)) trackHarvestMetadata()
163
168
  }, eventListenerOpts(false))
164
169
  } else if (submitMethod === fetchMethod) {
165
170
  result.then(async function (response) {
@@ -167,8 +172,30 @@ export function send (agentRef, { endpoint, targetApp, payload, localOpts = {},
167
172
  const cbResult = { sent: true, status, retry: shouldRetry(status), fullUrl, fetchResponse: response, targetApp }
168
173
  if (localOpts.needResponse) cbResult.responseText = await response.text()
169
174
  cbFinished(cbResult)
175
+ /** temporary audit of consistency of harvest metadata flags */
176
+ if (!shouldRetry(status)) trackHarvestMetadata()
170
177
  })
171
178
  }
179
+
180
+ function trackHarvestMetadata () {
181
+ try {
182
+ if (featureName === FEATURE_NAMES.jserrors && !body?.err) return
183
+
184
+ const hasReplay = baseParams.includes('hr=1')
185
+ const hasTrace = baseParams.includes('ht=1')
186
+ const hasError = qs?.attributes?.includes('hasError=true')
187
+
188
+ handle('harvest-metadata', [{
189
+ [featureName]: {
190
+ ...(hasReplay && { hasReplay }),
191
+ ...(hasTrace && { hasTrace }),
192
+ ...(hasError && { hasError })
193
+ }
194
+ }], undefined, FEATURE_NAMES.metrics, agentRef.ee)
195
+ } catch (err) {
196
+ // do nothing
197
+ }
198
+ }
172
199
  }
173
200
 
174
201
  dispatchGlobalEvent({
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright 2020-2025 New Relic, Inc. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ export function evaluateHarvestMetadata (pageMetadata) {
7
+ try {
8
+ const supportabilityTags = []
9
+
10
+ // Report SM like... audit/<feature_name>/<hasReplay|hasTrace|hasError>/<true|false>/<negative|positive>
11
+ const formTag = (...strings) => strings.join('/')
12
+
13
+ // Track if replay/trace/error harvests actually occurred (key only exists when harvested)
14
+ function evaluateTag (feature, flag, hasFlag, hasHarvest) {
15
+ const AUDIT = 'audit'
16
+ if (hasFlag) {
17
+ // False positive: flag true, but no harvest
18
+ if (!hasHarvest) supportabilityTags.push(formTag(AUDIT, feature, flag, 'false', 'positive'))
19
+ // True positive (correct)
20
+ else supportabilityTags.push(formTag(AUDIT, feature, flag, 'true', 'positive'))
21
+ } else {
22
+ // False negative: flag false, but harvest occurred
23
+ if (hasHarvest) supportabilityTags.push(formTag(AUDIT, feature, flag, 'false', 'negative'))
24
+ // True negative (correct)
25
+ else supportabilityTags.push(formTag(AUDIT, feature, flag, 'true', 'negative'))
26
+ }
27
+ }
28
+
29
+ if (pageMetadata.page_view_event) {
30
+ evaluateTag('page_view', 'hasReplay', pageMetadata.page_view_event.hasReplay, !!pageMetadata.session_replay)
31
+ evaluateTag('page_view', 'hasTrace', pageMetadata.page_view_event.hasTrace, !!pageMetadata.session_trace)
32
+ }
33
+
34
+ if (pageMetadata.session_replay) {
35
+ evaluateTag('session_replay', 'hasError', pageMetadata.session_replay.hasError, !!pageMetadata.jserrors)
36
+ }
37
+
38
+ return supportabilityTags
39
+ } catch (err) {
40
+ return []
41
+ }
42
+ }
@@ -11,6 +11,7 @@ import { windowAddEventListener } from '../../../common/event-listener/event-lis
11
11
  import { isBrowserScope, isWorkerScope } from '../../../common/constants/runtime'
12
12
  import { AggregateBase } from '../../utils/aggregate-base'
13
13
  import { isIFrameWindow } from '../../../common/dom/iframe'
14
+ import { evaluateHarvestMetadata } from './harvest-metadata'
14
15
  // import { WEBSOCKET_TAG } from '../../../common/wrap/wrap-websocket'
15
16
  // import { handleWebsocketEvents } from './websocket-detection'
16
17
 
@@ -19,6 +20,15 @@ export class Aggregate extends AggregateBase {
19
20
  constructor (agentRef) {
20
21
  super(agentRef, FEATURE_NAME)
21
22
  this.harvestOpts.aggregatorTypes = ['cm', 'sm'] // the types in EventAggregator this feature cares about
23
+
24
+ /** all the harvest metadata metrics need to be evaluated simulataneously at unload time so just temporarily buffer them and dont make SMs immediately from the data */
25
+ this.harvestMetadata = {}
26
+ this.harvestOpts.beforeUnload = () => {
27
+ evaluateHarvestMetadata(this.harvestMetadata).forEach(smTag => {
28
+ this.storeSupportabilityMetrics(smTag)
29
+ })
30
+ }
31
+
22
32
  // This feature only harvests once per potential EoL of the page, which is handled by the central harvester.
23
33
 
24
34
  // this must be read/stored synchronously, as the currentScript is removed from the DOM after this script is executed and this lookup will be void
@@ -126,6 +136,17 @@ export class Aggregate extends AggregateBase {
126
136
  // handleWebsocketEvents(this.storeSupportabilityMetrics.bind(this), tag, ...args)
127
137
  // }, this.featureName, this.ee)
128
138
  // })
139
+
140
+ /** all the harvest metadata metrics need to be evaluated simulataneously at unload time so just temporarily buffer them and dont make SMs immediately from the data */
141
+ registerHandler('harvest-metadata', (harvestMetadataObject = {}) => {
142
+ try {
143
+ Object.keys(harvestMetadataObject).forEach(key => {
144
+ Object.assign(this.harvestMetadata[key] ??= {}, harvestMetadataObject[key])
145
+ })
146
+ } catch (e) {
147
+ // failed to merge harvest metadata... ignore
148
+ }
149
+ }, this.featureName, this.ee)
129
150
  }
130
151
 
131
152
  eachSessionChecks () {