@newrelic/browser-agent 1.316.0-rc.6 → 1.317.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.
- package/CHANGELOG.md +15 -0
- package/dist/cjs/common/config/init-types.js +1 -0
- package/dist/cjs/common/config/init.js +6 -4
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/payloads/payloads.js +127 -0
- package/dist/cjs/common/serialize/bel-serializer.js +2 -1
- package/dist/cjs/common/util/data-size.js +2 -2
- package/dist/cjs/common/wrap/wrap-xhr.js +1 -1
- package/dist/cjs/features/ajax/aggregate/gql.js +40 -1
- package/dist/cjs/features/ajax/aggregate/index.js +46 -13
- package/dist/cjs/features/ajax/constants.js +6 -1
- package/dist/cjs/features/ajax/instrument/index.js +105 -17
- package/dist/cjs/features/jserrors/aggregate/format-stack-trace.js +2 -2
- package/dist/cjs/features/jserrors/aggregate/index.js +1 -1
- package/dist/cjs/features/soft_navigations/aggregate/ajax-node.js +35 -4
- package/dist/cjs/features/soft_navigations/aggregate/initial-page-load-interaction.js +1 -1
- package/dist/esm/common/config/init-types.js +1 -0
- package/dist/esm/common/config/init.js +3 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/payloads/payloads.js +118 -0
- package/dist/esm/common/serialize/bel-serializer.js +2 -1
- package/dist/esm/common/util/data-size.js +2 -2
- package/dist/esm/common/wrap/wrap-xhr.js +1 -1
- package/dist/esm/features/ajax/aggregate/gql.js +39 -1
- package/dist/esm/features/ajax/aggregate/index.js +47 -14
- package/dist/esm/features/ajax/constants.js +5 -0
- package/dist/esm/features/ajax/instrument/index.js +106 -18
- package/dist/esm/features/jserrors/aggregate/format-stack-trace.js +2 -2
- package/dist/esm/features/jserrors/aggregate/index.js +1 -1
- package/dist/esm/features/soft_navigations/aggregate/ajax-node.js +35 -4
- package/dist/esm/features/soft_navigations/aggregate/initial-page-load-interaction.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/config/init-types.d.ts +4 -0
- package/dist/types/common/config/init-types.d.ts.map +1 -1
- package/dist/types/common/config/init.d.ts.map +1 -1
- package/dist/types/common/payloads/payloads.d.ts +42 -0
- package/dist/types/common/payloads/payloads.d.ts.map +1 -0
- package/dist/types/common/serialize/bel-serializer.d.ts +1 -1
- package/dist/types/common/serialize/bel-serializer.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/gql.d.ts +8 -0
- package/dist/types/features/ajax/aggregate/gql.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/ajax/constants.d.ts +5 -0
- package/dist/types/features/ajax/constants.d.ts.map +1 -1
- package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts +5 -0
- package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/common/config/init-types.js +1 -0
- package/src/common/config/init.js +2 -1
- package/src/common/payloads/payloads.js +135 -0
- package/src/common/serialize/bel-serializer.js +2 -1
- package/src/common/util/data-size.js +2 -2
- package/src/common/wrap/wrap-xhr.js +1 -1
- package/src/features/ajax/aggregate/gql.js +42 -1
- package/src/features/ajax/aggregate/index.js +38 -13
- package/src/features/ajax/constants.js +5 -1
- package/src/features/ajax/instrument/index.js +114 -18
- package/src/features/jserrors/aggregate/format-stack-trace.js +3 -3
- package/src/features/jserrors/aggregate/index.js +1 -1
- package/src/features/soft_navigations/aggregate/ajax-node.js +25 -4
- package/src/features/soft_navigations/aggregate/initial-page-load-interaction.js +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ export function formatStackTrace(stackLines) {
|
|
|
9
9
|
return truncateStackLines(stackLines).replace(stripNewlinesRegex, '');
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
// takes array of stack lines and returns string with top 50 and
|
|
12
|
+
// takes array of stack lines and returns string with top 50 and bottom 50 lines
|
|
13
13
|
function truncateStackLines(stackLines) {
|
|
14
14
|
var stackString;
|
|
15
15
|
if (stackLines.length > 100) {
|
|
@@ -262,7 +262,7 @@ export class Aggregate extends AggregateBase {
|
|
|
262
262
|
params.stack_trace = truncateSize(stackInfo.stackString);
|
|
263
263
|
this.observedAt[bucketHash] = Math.floor(this.agentRef.runtime.timeKeeper.correctRelativeTimestamp(time));
|
|
264
264
|
} else {
|
|
265
|
-
params.browser_stack_hash = stringHashCode(stackInfo.stackString);
|
|
265
|
+
params.browser_stack_hash = stringHashCode(truncateSize(stackInfo.stackString));
|
|
266
266
|
}
|
|
267
267
|
params.releaseIds = stringify(this.agentRef.runtime.releaseIds);
|
|
268
268
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { addCustomAttributes, getAddStringContext, nullable, numeric } from '../../../common/serialize/bel-serializer';
|
|
6
|
+
import { createStringAdders } from '../../../common/payloads/payloads';
|
|
6
7
|
import { AJAX_ID } from '../../ajax/constants';
|
|
7
8
|
import { NODE_TYPE } from '../constants';
|
|
8
9
|
import { BelNode } from './bel-node';
|
|
@@ -24,6 +25,12 @@ export class AjaxNode extends BelNode {
|
|
|
24
25
|
this.targetAttributes = ajaxEvent.targetAttributes;
|
|
25
26
|
this[AJAX_ID] = ajaxEvent[AJAX_ID]; // all AjaxRequest events should have a unique identifier to allow for easier grouping and analysis in the UI
|
|
26
27
|
|
|
28
|
+
// optional payload metadata attributes
|
|
29
|
+
this.requestBody = ajaxEvent.requestBody;
|
|
30
|
+
this.requestHeaders = ajaxEvent.requestHeaders;
|
|
31
|
+
this.requestQuery = ajaxEvent.requestQuery;
|
|
32
|
+
this.responseBody = ajaxEvent.responseBody;
|
|
33
|
+
this.responseHeaders = ajaxEvent.responseHeaders;
|
|
27
34
|
this.start = ajaxEvent.startTime;
|
|
28
35
|
this.end = ajaxEvent.endTime;
|
|
29
36
|
if (ajaxContext?.latestLongtaskEnd) {
|
|
@@ -32,7 +39,10 @@ export class AjaxNode extends BelNode {
|
|
|
32
39
|
} else this.callbackEnd = this.end; // if no long task was observed, callbackEnd is the same as end
|
|
33
40
|
}
|
|
34
41
|
serialize(parentStartTimestamp, agentRef, ajaxObfuscator) {
|
|
35
|
-
const
|
|
42
|
+
const {
|
|
43
|
+
addString,
|
|
44
|
+
addStringWithTruncation
|
|
45
|
+
} = createStringAdders(getAddStringContext, ajaxObfuscator);
|
|
36
46
|
const nodeList = [];
|
|
37
47
|
|
|
38
48
|
// IMPORTANT: The order in which addString is called matters and correlates to the order in which string shows up in the harvest payload. Do not re-order the following code.
|
|
@@ -47,11 +57,32 @@ export class AjaxNode extends BelNode {
|
|
|
47
57
|
numeric(this.callbackDuration),
|
|
48
58
|
// not relative
|
|
49
59
|
addString(this.method), numeric(this.status), addString(this.domain), addString(this.path), numeric(this.txSize), numeric(this.rxSize), this.requestedWith, addString(this.nodeId), nullable(this.spanId, addString, true) + nullable(this.traceId, addString, true) + nullable(this.spanTimestamp, numeric)];
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
// Regular attributes: obfuscate only
|
|
61
|
+
const regularAttrs = addCustomAttributes({
|
|
62
|
+
[AJAX_ID]: this[AJAX_ID],
|
|
52
63
|
...(this.targetAttributes || {}),
|
|
53
|
-
|
|
64
|
+
...(this.gql || {})
|
|
54
65
|
}, addString);
|
|
66
|
+
|
|
67
|
+
// Payload attributes: obfuscate then truncate
|
|
68
|
+
const payloadAttrs = addCustomAttributes({
|
|
69
|
+
...(this.requestBody ? {
|
|
70
|
+
requestBody: this.requestBody
|
|
71
|
+
} : {}),
|
|
72
|
+
...(this.requestHeaders ? {
|
|
73
|
+
requestHeaders: this.requestHeaders
|
|
74
|
+
} : {}),
|
|
75
|
+
...(this.requestQuery ? {
|
|
76
|
+
requestQuery: this.requestQuery
|
|
77
|
+
} : {}),
|
|
78
|
+
...(this.responseBody ? {
|
|
79
|
+
responseBody: this.responseBody
|
|
80
|
+
} : {}),
|
|
81
|
+
...(this.responseHeaders ? {
|
|
82
|
+
responseHeaders: this.responseHeaders
|
|
83
|
+
} : {})
|
|
84
|
+
}, addStringWithTruncation);
|
|
85
|
+
let allAttachedNodes = [...regularAttrs, ...payloadAttrs];
|
|
55
86
|
this.children.forEach(node => allAttachedNodes.push(node.serialize())); // no children is expected under ajax nodes at this time
|
|
56
87
|
|
|
57
88
|
fields[1] = numeric(allAttachedNodes.length);
|
|
@@ -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/events.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/session/session-key.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/extract-url.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/browser-stack-matchers.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/short-circuit.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/util/webdriver-detection.js","../src/common/v2/script-correlation.js","../src/common/v2/script-tracker.js","../src/common/v2/utils.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/load-time.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-logger.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/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/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/event-buffer.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.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/consent.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.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.9.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/events.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/payloads/payloads.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/session/session-key.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/extract-url.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/browser-stack-matchers.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/short-circuit.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/util/webdriver-detection.js","../src/common/v2/script-correlation.js","../src/common/v2/script-tracker.js","../src/common/v2/utils.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/load-time.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-logger.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/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/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/event-buffer.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.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/consent.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.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.9.3"}
|
|
@@ -18,6 +18,10 @@ export type Init = {
|
|
|
18
18
|
* - If true, the agent will automatically start the ajax feature. Otherwise, it will be in a deferred state until the `start` API method is called.
|
|
19
19
|
*/
|
|
20
20
|
autoStart?: boolean | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* - Controls when AJAX request/response payloads are captured. 'none' = never capture, 'failures' = capture only on errors (4xx, 5xx, network errors, GraphQL errors), 'all' = always capture.
|
|
23
|
+
*/
|
|
24
|
+
capture_payloads?: "none" | "failures" | "all" | undefined;
|
|
21
25
|
} | undefined;
|
|
22
26
|
api?: {
|
|
23
27
|
register?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-types.d.ts","sourceRoot":"","sources":["../../../../src/common/config/init-types.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init-types.d.ts","sourceRoot":"","sources":["../../../../src/common/config/init-types.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAuCsB,MAAM,GAAG,MAAM;qBAAe,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/common/config/init.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/common/config/init.js"],"names":[],"mappings":"AAgJO,0CAEN;mBAtIY,OAAO,cAAc,EAAE,IAAI"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determines whether payload data should be captured based on the capture mode setting,
|
|
3
|
+
* HTTP status code, and GraphQL error status.
|
|
4
|
+
* @param {string} captureMode - The capture mode setting ('none', 'all', or 'failures')
|
|
5
|
+
* @param {number} statusCode - The HTTP status code
|
|
6
|
+
* @param {boolean} hasGQLErrors - Whether the response contains GraphQL errors
|
|
7
|
+
* @returns {boolean} True if payload should be captured
|
|
8
|
+
*/
|
|
9
|
+
export function canCapturePayload(captureMode: string, statusCode: number, hasGQLErrors: boolean): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Parses a query string into an object of key-value pairs.
|
|
12
|
+
* @param {string} search a query string starting with "?" or without (ex. new URL(...).search)
|
|
13
|
+
* @returns {Object|undefined} Parsed query parameters as key-value pairs. Returns undefined if no valid parameters are found.
|
|
14
|
+
*/
|
|
15
|
+
export function parseQueryString(search: string): Object | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Determines if the given content type is likely to be human-readable (text-based).
|
|
18
|
+
* @param {Object} headers - The headers object containing content-type
|
|
19
|
+
* @param {*} data - The data to check
|
|
20
|
+
* @returns {boolean} True if the content type is human-readable (text-based)
|
|
21
|
+
*/
|
|
22
|
+
export function isLikelyHumanReadable(headers: Object, data: any): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Truncates a string to ensure its UTF-8 byte length does not exceed 4092 bytes. If truncation is necessary,
|
|
25
|
+
* the string is cut off at a character boundary to avoid breaking multi-byte characters and " ..." is appended to indicate truncation.
|
|
26
|
+
* If not a string, it is first converted to a string using JSON.stringify.
|
|
27
|
+
* @param {*} data The data to truncate.
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
export function truncateAsString(data: any): string;
|
|
31
|
+
/**
|
|
32
|
+
* Creates string adder functions for BEL serialization with obfuscation and optional truncation.
|
|
33
|
+
* This ensures a single string table is used while providing separate handling for regular vs payload attributes.
|
|
34
|
+
* @param {Function} getAddStringContext - Function that creates a new string table context
|
|
35
|
+
* @param {Object} obfuscator - Optional obfuscator instance for string obfuscation
|
|
36
|
+
* @returns {{addString: Function, addStringWithTruncation: Function}} Object containing both string adder functions
|
|
37
|
+
*/
|
|
38
|
+
export function createStringAdders(getAddStringContext: Function, obfuscator: Object): {
|
|
39
|
+
addString: Function;
|
|
40
|
+
addStringWithTruncation: Function;
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=payloads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payloads.d.ts","sourceRoot":"","sources":["../../../../src/common/payloads/payloads.js"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,+CALW,MAAM,cACN,MAAM,gBACN,OAAO,GACL,OAAO,CAQnB;AAED;;;;GAIG;AACH,yCAHW,MAAM,GACJ,MAAM,GAAC,SAAS,CAgB5B;AAED;;;;;GAKG;AACH,+CAJW,MAAM,QACN,GAAC,GACC,OAAO,CA2BnB;AAED;;;;;;GAMG;AACH,uCAHW,GAAC,GACC,MAAM,CA2BlB;AAED;;;;;;GAMG;AACH,8EAHW,MAAM,GACJ;IAAC,SAAS,WAAW;IAAC,uBAAuB,WAAU;CAAC,CAiBpE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function nullable(val: any, fn: any, comma: any): string;
|
|
2
2
|
export function numeric(n: any, noDefault: any): string;
|
|
3
|
-
export function getAddStringContext(obfuscator: any): (str: any) => string;
|
|
3
|
+
export function getAddStringContext(obfuscator: any, truncator: any): (str: any) => string;
|
|
4
4
|
export function addCustomAttributes(attrs: any, addString: any): any[];
|
|
5
5
|
//# sourceMappingURL=bel-serializer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bel-serializer.d.ts","sourceRoot":"","sources":["../../../../src/common/serialize/bel-serializer.js"],"names":[],"mappings":"AAUA,gEAIC;AAED,wDAKC;AAED,
|
|
1
|
+
{"version":3,"file":"bel-serializer.d.ts","sourceRoot":"","sources":["../../../../src/common/serialize/bel-serializer.js"],"names":[],"mappings":"AAUA,gEAIC;AAED,wDAKC;AAED,2FAiBC;AAED,uEAwCC"}
|
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
* @returns {GQLMetadata | undefined}
|
|
13
13
|
*/
|
|
14
14
|
export function parseGQL({ body, query }?: object | string): GQLMetadata | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Checks if a response body contains GraphQL errors according to the GraphQL spec.
|
|
17
|
+
* A valid GraphQL error response contains an "errors" array with at least one error object.
|
|
18
|
+
* Supports both single and batched GraphQL responses.
|
|
19
|
+
* @param {string|object|array} [responseBody] The response body to check
|
|
20
|
+
* @returns {boolean} True if the response contains GraphQL errors
|
|
21
|
+
*/
|
|
22
|
+
export function hasGQLErrors(responseBody?: string | object | array): boolean;
|
|
15
23
|
export type GQLMetadata = {
|
|
16
24
|
/**
|
|
17
25
|
* Name of the operation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gql.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/aggregate/gql.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,2CAJW,MAAM,GAAC,MAAM,GAEX,WAAW,GAAG,SAAS,CAYnC;;;;;
|
|
1
|
+
{"version":3,"file":"gql.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/aggregate/gql.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,2CAJW,MAAM,GAAC,MAAM,GAEX,WAAW,GAAG,SAAS,CAYnC;AAkFD;;;;;;GAMG;AACH,4CAHW,MAAM,GAAC,MAAM,GAAC,KAAK,GACjB,OAAO,CAsBnB;;;;;mBAnIa,MAAM;;;;mBACN,MAAM;;;;wBACN,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/aggregate/index.js"],"names":[],"mappings":"AAoBA;IACE,2BAAiC;IAEjC,2BA6BC;IAvBC,uBAA4D;IAyB9D,0GAqFC;IAED,+CAOC;IAED,iDAoEC;CACF;8BAjN6B,4BAA4B;2BAK/B,gCAAgC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/ajax/constants.js"],"names":[],"mappings":"AAMA,kCAA8C
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/ajax/constants.js"],"names":[],"mappings":"AAMA,kCAA8C;;;;;;AAM9C,sBAAuB,gBAAgB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/instrument/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/instrument/index.js"],"names":[],"mappings":"AA+BA;IACE,2BAAiC;IACjC,2BAiCC;IA9BC,OAA0B;IAE1B,8DAAkF;CA6BrF;AA6bD,qCAA8B;+BAjfC,6BAA6B;mBAFzC,uBAAuB"}
|
|
@@ -13,6 +13,11 @@ export class AjaxNode extends BelNode {
|
|
|
13
13
|
spanTimestamp: any;
|
|
14
14
|
gql: any;
|
|
15
15
|
targetAttributes: any;
|
|
16
|
+
requestBody: any;
|
|
17
|
+
requestHeaders: any;
|
|
18
|
+
requestQuery: any;
|
|
19
|
+
responseBody: any;
|
|
20
|
+
responseHeaders: any;
|
|
16
21
|
callbackEnd: any;
|
|
17
22
|
serialize(parentStartTimestamp: any, agentRef: any, ajaxObfuscator: any): string;
|
|
18
23
|
"ajaxRequest.id": any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ajax-node.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/ajax-node.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ajax-node.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/ajax-node.js"],"names":[],"mappings":"AAUA;IACE,8CA8BC;IA5BC,gBAA6B;IAC7B,YAA8B;IAC9B,YAA8B;IAC9B,YAA8B;IAC9B,UAA0B;IAC1B,YAAmC;IACnC,YAAoC;IACpC,+BAAwD;IACxD,YAA8B;IAC9B,aAAgC;IAChC,mBAA4C;IAC5C,SAAwB;IACxB,sBAAkD;IAIlD,iBAAwC;IACxC,oBAA8C;IAC9C,kBAA0C;IAC1C,kBAA0C;IAC1C,qBAAgD;IAK9C,iBAAoE;IAKxE,iFA+CC;IAhEC,sBAAkC;CAiErC;wBAnFuB,YAAY"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/browser-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.317.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
|
|
6
6
|
"description": "New Relic Browser Agent",
|
|
@@ -284,4 +284,4 @@
|
|
|
284
284
|
"README.md",
|
|
285
285
|
"CHANGELOG.md"
|
|
286
286
|
]
|
|
287
|
-
}
|
|
287
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @property {boolean} [ajax.block_internal] - If true, agent requests going to harvest endpoint are treated as on deny list. In other words, agent will not self-report AJAX.
|
|
12
12
|
* @property {boolean} [ajax.enabled] - Turn on/off the ajax feature (on by default).
|
|
13
13
|
* @property {boolean} [ajax.autoStart] - If true, the agent will automatically start the ajax feature. Otherwise, it will be in a deferred state until the `start` API method is called.
|
|
14
|
+
* @property {('none'|'failures'|'all')} [ajax.capture_payloads] - Controls when AJAX request/response payloads are captured. 'none' = never capture, 'failures' = capture only on errors (4xx, 5xx, network errors, GraphQL errors), 'all' = always capture.
|
|
14
15
|
* @property {Object} [api]
|
|
15
16
|
* @property {Object} [api.register]
|
|
16
17
|
* @property {boolean} [api.register.enabled] - If true, the agent will allow registered children to be sent to the server.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { FEATURE_FLAGS } from '../../features/generic_events/constants'
|
|
6
|
+
import { CAPTURE_PAYLOAD_SETTINGS } from '../../features/ajax/constants'
|
|
6
7
|
import { isValidSelector } from '../dom/query-selector'
|
|
7
8
|
import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS } from '../session/constants'
|
|
8
9
|
import { warn } from '../util/console'
|
|
@@ -47,7 +48,7 @@ const InitModelFn = () => {
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
return {
|
|
50
|
-
ajax: { deny_list: undefined, block_internal: true, enabled: true, autoStart: true },
|
|
51
|
+
ajax: { deny_list: undefined, block_internal: true, enabled: true, autoStart: true, capture_payloads: CAPTURE_PAYLOAD_SETTINGS.NONE },
|
|
51
52
|
api: {
|
|
52
53
|
register: {
|
|
53
54
|
get enabled () { return hiddenState.feature_flags.includes(FEATURE_FLAGS.REGISTER) || hiddenState.experimental.register },
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { stringify } from '../util/stringify'
|
|
7
|
+
import { CAPTURE_PAYLOAD_SETTINGS } from '../../features/ajax/constants'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Determines whether payload data should be captured based on the capture mode setting,
|
|
11
|
+
* HTTP status code, and GraphQL error status.
|
|
12
|
+
* @param {string} captureMode - The capture mode setting ('none', 'all', or 'failures')
|
|
13
|
+
* @param {number} statusCode - The HTTP status code
|
|
14
|
+
* @param {boolean} hasGQLErrors - Whether the response contains GraphQL errors
|
|
15
|
+
* @returns {boolean} True if payload should be captured
|
|
16
|
+
*/
|
|
17
|
+
export function canCapturePayload (captureMode, statusCode, hasGQLErrors) {
|
|
18
|
+
if (captureMode === CAPTURE_PAYLOAD_SETTINGS.ALL) return true
|
|
19
|
+
if (!captureMode || captureMode === CAPTURE_PAYLOAD_SETTINGS.NONE) return false
|
|
20
|
+
|
|
21
|
+
// Default "failures" mode
|
|
22
|
+
return statusCode === 0 || statusCode >= 400 || hasGQLErrors === true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parses a query string into an object of key-value pairs.
|
|
27
|
+
* @param {string} search a query string starting with "?" or without (ex. new URL(...).search)
|
|
28
|
+
* @returns {Object|undefined} Parsed query parameters as key-value pairs. Returns undefined if no valid parameters are found.
|
|
29
|
+
*/
|
|
30
|
+
export function parseQueryString (search) {
|
|
31
|
+
if (!search || search.length === 0) return
|
|
32
|
+
|
|
33
|
+
const queryParams = {}
|
|
34
|
+
try {
|
|
35
|
+
const searchParams = new URLSearchParams(search)
|
|
36
|
+
searchParams.forEach(function (value, key) {
|
|
37
|
+
queryParams[key] = value
|
|
38
|
+
})
|
|
39
|
+
} catch (e) {
|
|
40
|
+
// Fallback for environments without URLSearchParams
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return queryParams
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Determines if the given content type is likely to be human-readable (text-based).
|
|
48
|
+
* @param {Object} headers - The headers object containing content-type
|
|
49
|
+
* @param {*} data - The data to check
|
|
50
|
+
* @returns {boolean} True if the content type is human-readable (text-based)
|
|
51
|
+
*/
|
|
52
|
+
export function isLikelyHumanReadable (headers, data) {
|
|
53
|
+
if (!headers) return typeof data === 'string'
|
|
54
|
+
var contentType = headers['content-type']
|
|
55
|
+
if (!contentType) return typeof data === 'string'
|
|
56
|
+
// Normalize to lowercase and extract the mime type (ignore charset, etc.)
|
|
57
|
+
var mimeType = contentType.toLowerCase().split(';')[0].trim()
|
|
58
|
+
|
|
59
|
+
// Check for text/* types
|
|
60
|
+
if (mimeType.indexOf('text/') === 0) return true
|
|
61
|
+
|
|
62
|
+
// Check for specific application/* types
|
|
63
|
+
var readableAppTypes = [
|
|
64
|
+
'/json',
|
|
65
|
+
'/xml',
|
|
66
|
+
'/xhtml+xml',
|
|
67
|
+
'/ld+json',
|
|
68
|
+
'/yaml',
|
|
69
|
+
'/x-www-form-urlencoded'
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
for (var i = 0; i < readableAppTypes.length; i++) {
|
|
73
|
+
if (mimeType === 'application' + readableAppTypes[i]) return true
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Truncates a string to ensure its UTF-8 byte length does not exceed 4092 bytes. If truncation is necessary,
|
|
81
|
+
* the string is cut off at a character boundary to avoid breaking multi-byte characters and " ..." is appended to indicate truncation.
|
|
82
|
+
* If not a string, it is first converted to a string using JSON.stringify.
|
|
83
|
+
* @param {*} data The data to truncate.
|
|
84
|
+
* @returns {string}
|
|
85
|
+
*/
|
|
86
|
+
export function truncateAsString (data) {
|
|
87
|
+
if (!data) return data
|
|
88
|
+
try {
|
|
89
|
+
if (typeof data !== 'string') data = stringify(data)
|
|
90
|
+
let bytes = 0
|
|
91
|
+
let i = 0
|
|
92
|
+
let needsEllipsis = false
|
|
93
|
+
|
|
94
|
+
while (i < data.length) {
|
|
95
|
+
const c = data.charCodeAt(i)
|
|
96
|
+
const charBytes = c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0xD800 || c >= 0xE000 ? 3 : 4
|
|
97
|
+
|
|
98
|
+
if (bytes + charBytes > 4092) {
|
|
99
|
+
needsEllipsis = true
|
|
100
|
+
break
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
bytes += charBytes
|
|
104
|
+
i += charBytes === 4 ? 2 : 1
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return data.slice(0, i) + (needsEllipsis ? ' ...' : '')
|
|
108
|
+
} catch (e) {
|
|
109
|
+
return data
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Creates string adder functions for BEL serialization with obfuscation and optional truncation.
|
|
115
|
+
* This ensures a single string table is used while providing separate handling for regular vs payload attributes.
|
|
116
|
+
* @param {Function} getAddStringContext - Function that creates a new string table context
|
|
117
|
+
* @param {Object} obfuscator - Optional obfuscator instance for string obfuscation
|
|
118
|
+
* @returns {{addString: Function, addStringWithTruncation: Function}} Object containing both string adder functions
|
|
119
|
+
*/
|
|
120
|
+
export function createStringAdders (getAddStringContext, obfuscator) {
|
|
121
|
+
const addStringRaw = getAddStringContext()
|
|
122
|
+
|
|
123
|
+
const processString = (str, shouldTruncate) => {
|
|
124
|
+
if (typeof str === 'undefined' || str === '') return addStringRaw(str)
|
|
125
|
+
if (typeof str !== 'string') str = stringify(str)
|
|
126
|
+
const obfuscated = obfuscator?.obfuscateString(str) ?? str
|
|
127
|
+
const processed = shouldTruncate ? truncateAsString(obfuscated) : obfuscated
|
|
128
|
+
return addStringRaw(processed)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
addString: (str) => processString(str, false),
|
|
133
|
+
addStringWithTruncation: (str) => processString(str, true)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -21,7 +21,7 @@ export function numeric (n, noDefault) {
|
|
|
21
21
|
return (n === undefined || n === 0) ? '' : Math.floor(n).toString(36)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export function getAddStringContext (obfuscator) {
|
|
24
|
+
export function getAddStringContext (obfuscator, truncator) {
|
|
25
25
|
let stringTableIdx = 0
|
|
26
26
|
const stringTable = Object.prototype.hasOwnProperty.call(Object, 'create') ? Object.create(null) : {}
|
|
27
27
|
|
|
@@ -30,6 +30,7 @@ export function getAddStringContext (obfuscator) {
|
|
|
30
30
|
function addString (str) {
|
|
31
31
|
if (typeof str === 'undefined' || str === '') return ''
|
|
32
32
|
str = obfuscator?.obfuscateString(String(str)) ?? String(str)
|
|
33
|
+
str = truncator?.(str) ?? str
|
|
33
34
|
if (hasOwnProp.call(stringTable, str)) {
|
|
34
35
|
return numeric(stringTable[str], true)
|
|
35
36
|
} else {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -12,7 +12,7 @@ import { stringify } from './stringify'
|
|
|
12
12
|
* @returns {(number|undefined)} - The size of the data or undefined if size cannot be determined.
|
|
13
13
|
*/
|
|
14
14
|
export function dataSize (data) {
|
|
15
|
-
if (typeof data === 'string'
|
|
15
|
+
if (typeof data === 'string') return data.length
|
|
16
16
|
if (typeof data !== 'object') return undefined
|
|
17
17
|
// eslint-disable-next-line
|
|
18
18
|
if (typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer && data.byteLength) return data.byteLength
|
|
@@ -17,7 +17,7 @@ import { warn } from '../util/console'
|
|
|
17
17
|
import { findTargetsFromStackTrace } from '../v2/utils'
|
|
18
18
|
|
|
19
19
|
const wrapped = {}
|
|
20
|
-
const XHR_PROPS = ['open', 'send'] // these are the specific funcs being wrapped on all XMLHttpRequests(.prototype)
|
|
20
|
+
const XHR_PROPS = ['open', 'send', 'setRequestHeader'] // these are the specific funcs being wrapped on all XMLHttpRequests(.prototype)
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Wraps the native XMLHttpRequest (XHR) object to emit custom events to its readystatechange event and an assortment
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2020-
|
|
2
|
+
* Copyright 2020-2026 New Relic, Inc. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { isPureObject } from '../../../common/util/type-check'
|
|
@@ -97,3 +97,44 @@ function parseGQLQueryString (gqlQueryString) {
|
|
|
97
97
|
function validateGQLObject (obj) {
|
|
98
98
|
return !(typeof obj !== 'object' || !obj.query || typeof obj.query !== 'string')
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Checks if a response object has valid GraphQL errors.
|
|
103
|
+
* @param {object} response - A single GraphQL response object
|
|
104
|
+
* @returns {boolean} True if the response has valid errors
|
|
105
|
+
*/
|
|
106
|
+
function hasValidGQLErrors (response) {
|
|
107
|
+
return Array.isArray(response?.errors) &&
|
|
108
|
+
response.errors.some(err =>
|
|
109
|
+
err && typeof err === 'object' && typeof err.message === 'string'
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Checks if a response body contains GraphQL errors according to the GraphQL spec.
|
|
115
|
+
* A valid GraphQL error response contains an "errors" array with at least one error object.
|
|
116
|
+
* Supports both single and batched GraphQL responses.
|
|
117
|
+
* @param {string|object|array} [responseBody] The response body to check
|
|
118
|
+
* @returns {boolean} True if the response contains GraphQL errors
|
|
119
|
+
*/
|
|
120
|
+
export function hasGQLErrors (responseBody) {
|
|
121
|
+
if (!responseBody) return false
|
|
122
|
+
try {
|
|
123
|
+
let parsed = responseBody
|
|
124
|
+
|
|
125
|
+
// Parse string to object if needed
|
|
126
|
+
if (typeof responseBody === 'string') {
|
|
127
|
+
parsed = JSON.parse(responseBody)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Handle batched GraphQL responses (array of response objects)
|
|
131
|
+
if (Array.isArray(parsed)) {
|
|
132
|
+
return parsed.some(hasValidGQLErrors)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Handle single GraphQL response
|
|
136
|
+
return hasValidGQLErrors(parsed)
|
|
137
|
+
} catch (err) {
|
|
138
|
+
return false
|
|
139
|
+
}
|
|
140
|
+
}
|