@newrelic/browser-agent 1.313.1 → 1.314.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/cjs/common/constants/agent-constants.js +2 -1
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/dom/selector-path.js +12 -3
- package/dist/cjs/common/timing/time-keeper.js +18 -6
- package/dist/cjs/common/vitals/cumulative-layout-shift.js +3 -2
- package/dist/cjs/common/vitals/interaction-to-next-paint.js +3 -2
- package/dist/cjs/common/vitals/largest-contentful-paint.js +2 -1
- package/dist/cjs/common/vitals/load-time.js +5 -2
- package/dist/cjs/common/vitals/vital-metric.js +7 -4
- package/dist/cjs/features/ajax/aggregate/index.js +6 -2
- package/dist/cjs/features/ajax/constants.js +4 -3
- package/dist/cjs/features/generic_events/aggregate/index.js +60 -53
- package/dist/cjs/features/generic_events/aggregate/user-actions/aggregated-user-action.js +2 -1
- package/dist/cjs/features/generic_events/aggregate/user-actions/user-actions-aggregator.js +4 -3
- package/dist/cjs/features/page_view_timing/aggregate/index.js +27 -6
- package/dist/cjs/features/session_replay/aggregate/index.js +15 -6
- package/dist/cjs/features/session_replay/constants.js +1 -1
- package/dist/cjs/features/session_replay/shared/recorder.js +3 -1
- package/dist/cjs/features/soft_navigations/aggregate/ajax-node.js +7 -3
- package/dist/esm/common/constants/agent-constants.js +2 -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/dom/selector-path.js +13 -3
- package/dist/esm/common/timing/time-keeper.js +18 -6
- package/dist/esm/common/vitals/cumulative-layout-shift.js +3 -2
- package/dist/esm/common/vitals/interaction-to-next-paint.js +3 -2
- package/dist/esm/common/vitals/largest-contentful-paint.js +2 -1
- package/dist/esm/common/vitals/load-time.js +5 -2
- package/dist/esm/common/vitals/vital-metric.js +7 -4
- package/dist/esm/features/ajax/aggregate/index.js +7 -3
- package/dist/esm/features/ajax/constants.js +3 -2
- package/dist/esm/features/generic_events/aggregate/index.js +61 -54
- package/dist/esm/features/generic_events/aggregate/user-actions/aggregated-user-action.js +2 -1
- package/dist/esm/features/generic_events/aggregate/user-actions/user-actions-aggregator.js +4 -3
- package/dist/esm/features/page_view_timing/aggregate/index.js +27 -6
- package/dist/esm/features/session_replay/aggregate/index.js +15 -6
- package/dist/esm/features/session_replay/constants.js +1 -1
- package/dist/esm/features/session_replay/shared/recorder.js +3 -1
- package/dist/esm/features/soft_navigations/aggregate/ajax-node.js +5 -1
- package/dist/types/common/constants/agent-constants.d.ts +1 -0
- package/dist/types/common/constants/agent-constants.d.ts.map +1 -1
- package/dist/types/common/dom/selector-path.d.ts +2 -1
- package/dist/types/common/dom/selector-path.d.ts.map +1 -1
- package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
- package/dist/types/common/vitals/vital-metric.d.ts +3 -2
- package/dist/types/common/vitals/vital-metric.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 +1 -0
- package/dist/types/features/ajax/constants.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/user-actions/aggregated-user-action.d.ts +1 -0
- package/dist/types/features/generic_events/aggregate/user-actions/aggregated-user-action.d.ts.map +1 -1
- package/dist/types/features/generic_events/aggregate/user-actions/user-actions-aggregator.d.ts +2 -0
- package/dist/types/features/generic_events/aggregate/user-actions/user-actions-aggregator.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +1 -11
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts +2 -0
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts +1 -0
- package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/common/constants/agent-constants.js +2 -1
- package/src/common/dom/selector-path.js +13 -4
- package/src/common/timing/time-keeper.js +17 -6
- package/src/common/vitals/cumulative-layout-shift.js +2 -2
- package/src/common/vitals/interaction-to-next-paint.js +2 -2
- package/src/common/vitals/largest-contentful-paint.js +1 -1
- package/src/common/vitals/load-time.js +5 -2
- package/src/common/vitals/vital-metric.js +6 -4
- package/src/features/ajax/aggregate/index.js +6 -3
- package/src/features/ajax/constants.js +3 -1
- package/src/features/generic_events/aggregate/index.js +42 -39
- package/src/features/generic_events/aggregate/user-actions/aggregated-user-action.js +2 -1
- package/src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js +4 -3
- package/src/features/page_view_timing/aggregate/index.js +14 -6
- package/src/features/session_replay/aggregate/index.js +16 -5
- package/src/features/session_replay/constants.js +1 -1
- package/src/features/session_replay/shared/recorder.js +3 -1
- package/src/features/soft_navigations/aggregate/ajax-node.js +4 -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
|
import { record as recorder } from '@newrelic/rrweb';
|
|
@@ -40,6 +40,8 @@ export class Recorder {
|
|
|
40
40
|
this.events = new RecorderEvents(this.shouldFix);
|
|
41
41
|
/** Backlog used for a 2-part sliding window to guarantee a 15-30s buffer window */
|
|
42
42
|
this.backloggedEvents = new RecorderEvents(this.shouldFix);
|
|
43
|
+
/** Used to hold the harvest contents to facilitate retrying */
|
|
44
|
+
this.retryPayload = undefined;
|
|
43
45
|
/** Only set to true once a snapshot node has been processed. Used to block harvests from sending before we know we have a snapshot */
|
|
44
46
|
this.hasSeenSnapshot = false;
|
|
45
47
|
this.hasSeenMeta = false;
|
|
@@ -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 { AJAX_ID } from '../../ajax/constants';
|
|
6
7
|
import { NODE_TYPE } from '../constants';
|
|
7
8
|
import { BelNode } from './bel-node';
|
|
8
9
|
export class AjaxNode extends BelNode {
|
|
@@ -21,6 +22,8 @@ export class AjaxNode extends BelNode {
|
|
|
21
22
|
this.spanTimestamp = ajaxEvent.spanTimestamp;
|
|
22
23
|
this.gql = ajaxEvent.gql;
|
|
23
24
|
this.targetAttributes = ajaxEvent.targetAttributes;
|
|
25
|
+
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
|
+
|
|
24
27
|
this.start = ajaxEvent.startTime;
|
|
25
28
|
this.end = ajaxEvent.endTime;
|
|
26
29
|
if (ajaxContext?.latestLongtaskEnd) {
|
|
@@ -46,7 +49,8 @@ export class AjaxNode extends BelNode {
|
|
|
46
49
|
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)];
|
|
47
50
|
let allAttachedNodes = addCustomAttributes({
|
|
48
51
|
...(this.gql || {}),
|
|
49
|
-
...(this.targetAttributes || {})
|
|
52
|
+
...(this.targetAttributes || {}),
|
|
53
|
+
[AJAX_ID]: this[AJAX_ID]
|
|
50
54
|
}, addString);
|
|
51
55
|
this.children.forEach(node => allAttachedNodes.push(node.serialize())); // no children is expected under ajax nodes at this time
|
|
52
56
|
|
|
@@ -7,6 +7,7 @@ export const SUPPORTS_REGISTERED_ENTITIES: {
|
|
|
7
7
|
[FEATURE_NAMES.genericEvents]: boolean;
|
|
8
8
|
[FEATURE_NAMES.jserrors]: boolean;
|
|
9
9
|
[FEATURE_NAMES.ajax]: boolean;
|
|
10
|
+
[FEATURE_NAMES.pageViewTiming]: boolean;
|
|
10
11
|
};
|
|
11
12
|
import { FEATURE_NAMES } from '../../loaders/features/features';
|
|
12
13
|
//# sourceMappingURL=agent-constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-constants.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/agent-constants.js"],"names":[],"mappings":"AAMA,iCAAkC,KAAK,CAAA;AACvC,+BAAgC,OAAO,CAAA;AACvC,0BAA2B,oBAAoB,CAAA;AAC/C,4BAA6B,eAAe,CAAA;AAE5C;IACE,CAAC,aAAa,CAAC,OAAO,CAAC,UAAM;IAC7B,CAAC,aAAa,CAAC,aAAa,CAAC,UAAM;IACnC,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAM;IAC9B,CAAC,aAAa,CAAC,IAAI,CAAC,UAAM;
|
|
1
|
+
{"version":3,"file":"agent-constants.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/agent-constants.js"],"names":[],"mappings":"AAMA,iCAAkC,KAAK,CAAA;AACvC,+BAAgC,OAAO,CAAA;AACvC,0BAA2B,oBAAoB,CAAA;AAC/C,4BAA6B,eAAe,CAAA;AAE5C;IACE,CAAC,aAAa,CAAC,OAAO,CAAC,UAAM;IAC7B,CAAC,aAAa,CAAC,aAAa,CAAC,UAAM;IACnC,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAM;IAC9B,CAAC,aAAa,CAAC,IAAI,CAAC,UAAM;IAC1B,CAAC,aAAa,CAAC,cAAc,CAAC,UAAM;EACrC;8BAb6B,iCAAiC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export function analyzeElemPath(elem: HTMLElement, targetFields?: Array<string
|
|
1
|
+
export function analyzeElemPath(elem: HTMLElement, targetFields?: Array<string>, agentRef: any): {
|
|
2
2
|
path: (undefined | string);
|
|
3
3
|
nearestFields: {};
|
|
4
|
+
targets: any[];
|
|
4
5
|
hasButton: boolean;
|
|
5
6
|
hasLink: boolean;
|
|
6
7
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selector-path.d.ts","sourceRoot":"","sources":["../../../../src/common/dom/selector-path.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"selector-path.d.ts","sourceRoot":"","sources":["../../../../src/common/dom/selector-path.js"],"names":[],"mappings":"AAkBO,sCAJI,WAAW,iBACX,KAAK,CAAC,MAAM,CAAC,kBACX;IAAC,IAAI,EAAE,CAAC,SAAS,GAAC,MAAM,CAAC,CAAC;IAAC,aAAa,EAAE,EAAE,CAAC;IAAC,OAAO,QAAQ;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAkC/G"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"AAUA;;;;GAIG;AACH;
|
|
1
|
+
{"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"AAUA;;;;GAIG;AACH;IAkCE,6BAIC;IA0BD,qBAEC;IAED,kCAEC;IAED,4BAEC;IAED;;;;;;OAMG;IACH,8BALsB,cAAc,aACf,MAAM,WACR,MAAM,gBACD,MAAM,QAqB7B;IAED;;;;;OAKG;IACH,uCAHwB,MAAM,GACjB,MAAM,CAMlB;IAED;;;;;OAKG;IACH,0CAFa,MAAM,CAMlB;IAED;;;;OAIG;IACH,oCAHqB,MAAM,GACf,MAAM,CAKjB;IAED;;;;OAIG;IACH,uCAHW,mBAAmB,GACjB,MAAM,CAKlB;IAED,+FAA+F;IAC/F,0BASC;;CACF"}
|
|
@@ -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
|
export class VitalMetric {
|
|
@@ -8,9 +8,10 @@ export class VitalMetric {
|
|
|
8
8
|
name: any;
|
|
9
9
|
attrs: {};
|
|
10
10
|
roundingMethod: any;
|
|
11
|
-
update({ value, attrs }: {
|
|
11
|
+
update({ value, attrs, element }: {
|
|
12
12
|
value: any;
|
|
13
13
|
attrs?: {} | undefined;
|
|
14
|
+
element: any;
|
|
14
15
|
}): void;
|
|
15
16
|
get current(): any;
|
|
16
17
|
get isValid(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vital-metric.d.ts","sourceRoot":"","sources":["../../../../src/common/vitals/vital-metric.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH;IAIE,4CAIC;IAND,eAAY;IAGV,UAAgB;IAChB,UAAe;IACf,oBAAwF;IAG1F
|
|
1
|
+
{"version":3,"file":"vital-metric.d.ts","sourceRoot":"","sources":["../../../../src/common/vitals/vital-metric.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH;IAIE,4CAIC;IAND,eAAY;IAGV,UAAgB;IAChB,UAAe;IACf,oBAAwF;IAG1F;;;;aAiBC;IAED,mBAOC;IAED,uBAEC;IAED,uEAMC;;CACF"}
|
|
@@ -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":"AAiBA;IACE,2BAAiC;IAEjC,2BA0BC;IAED,0GAwEC;IAED,+CAOC;IAED,iDAyDC;CACF;8BAnL6B,4BAA4B"}
|
|
@@ -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;AAE9C,sBAAuB,gBAAgB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/generic_events/aggregate/index.js"],"names":[],"mappings":"AAkBA;IACE,2BAAiC;IAGjC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/generic_events/aggregate/index.js"],"names":[],"mappings":"AAkBA;IACE,2BAAiC;IAGjC,2BAyQC;IAvQC,gCAAkG;IA0QpG;;;;;;;;;;;;OAYG;IACH,eAJW,MAAM,YAAC,WACP,MAAM,YAAC,QAkCjB;IAED,qCAEC;IAED;;;MAEC;;CAsBF;8BApW6B,4BAA4B"}
|
package/dist/types/features/generic_events/aggregate/user-actions/aggregated-user-action.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export class AggregatedUserAction {
|
|
|
10
10
|
currentUrl: string;
|
|
11
11
|
deadClick: boolean;
|
|
12
12
|
errorClick: boolean;
|
|
13
|
+
targets: any;
|
|
13
14
|
/**
|
|
14
15
|
* Aggregates the count and maintains the relative MS array for matching events
|
|
15
16
|
* Will determine if a rage click was observed as part of the aggregation
|
package/dist/types/features/generic_events/aggregate/user-actions/aggregated-user-action.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregated-user-action.d.ts","sourceRoot":"","sources":["../../../../../../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js"],"names":[],"mappings":"AAOA;IACE,
|
|
1
|
+
{"version":3,"file":"aggregated-user-action.d.ts","sourceRoot":"","sources":["../../../../../../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js"],"names":[],"mappings":"AAOA;IACE,yCAYC;IAXC,WAAgB;IAChB,cAAc;IACd,iBAAyC;IACzC,qBAAqB;IACrB,kBAAqC;IACrC,+BAA0B;IAC1B,yBAAqD;IACrD,mBAAyC;IACzC,mBAAsB;IACtB,oBAAuB;IACvB,aAAmC;IAGrC;;;;;OAKG;IACH,eAHW,KAAK,GACH,IAAI,CAMhB;IAED;;;OAGG;IACH,eAFa,OAAO,CAKnB;CACF"}
|
package/dist/types/features/generic_events/aggregate/user-actions/user-actions-aggregator.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export class UserActionsAggregator {
|
|
2
|
+
constructor(agentRef: any);
|
|
3
|
+
agentRef: any;
|
|
2
4
|
get aggregationEvent(): AggregatedUserAction | undefined;
|
|
3
5
|
/**
|
|
4
6
|
* Process the event and determine if a new aggregation set should be made or if it should increment the current aggregation
|
package/dist/types/features/generic_events/aggregate/user-actions/user-actions-aggregator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-actions-aggregator.d.ts","sourceRoot":"","sources":["../../../../../../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js"],"names":[],"mappings":"AAUA;
|
|
1
|
+
{"version":3,"file":"user-actions-aggregator.d.ts","sourceRoot":"","sources":["../../../../../../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js"],"names":[],"mappings":"AAUA;IAQE,2BAKC;IAJC,cAAwB;IAM1B,yDAQC;IAED;;;;OAIG;IACH,aAHW,KAAK,sBACH,oBAAoB,GAAC,SAAS,CA2B1C;IAED,yBAKC;IA0CD,oBAEC;;CACF;qCA/GoC,0BAA0B"}
|
|
@@ -8,7 +8,7 @@ export class Aggregate extends AggregateBase {
|
|
|
8
8
|
* @param {number} timestamp
|
|
9
9
|
*/
|
|
10
10
|
endCurrentSession(timestamp: number): void;
|
|
11
|
-
addTiming(name: any, value: any, attrs: any): {
|
|
11
|
+
addTiming(name: any, value: any, attrs: any, element: any): {
|
|
12
12
|
name: any;
|
|
13
13
|
value: any;
|
|
14
14
|
attrs: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_timing/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_timing/aggregate/index.js"],"names":[],"mappings":"AA0BA;IACE,2BAAiC;IAMjC,2BA4BC;IA1BC,4BAA+B;IAC/B,0BAA6B;IA2B/B;;;OAGG;IACH,6BAFW,MAAM,QAOhB;IAED;;;;MAqCC;IAED;;;OAGG;IACH,4BAFa,IAAI,CAahB;IAED,gDAWC;IAED,4BAGC;IAGD,qCAwBC;;CACF;8BApK6B,4BAA4B"}
|
|
@@ -35,17 +35,7 @@ export class Aggregate extends AggregateBase {
|
|
|
35
35
|
PRELOAD: string;
|
|
36
36
|
}): void;
|
|
37
37
|
prepUtils(): Promise<void>;
|
|
38
|
-
makeHarvestPayload():
|
|
39
|
-
qs: {
|
|
40
|
-
browser_monitoring_key: any;
|
|
41
|
-
type: string;
|
|
42
|
-
app_id: any;
|
|
43
|
-
protocol_version: string;
|
|
44
|
-
timestamp: any;
|
|
45
|
-
attributes: string;
|
|
46
|
-
};
|
|
47
|
-
body: any;
|
|
48
|
-
} | undefined;
|
|
38
|
+
makeHarvestPayload(): any;
|
|
49
39
|
/**
|
|
50
40
|
* returns the timestamps for the earliest and latest nodes in the provided array, even if out of order
|
|
51
41
|
* @param {Object[]} [nodes] - the nodes to evaluate
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AAyBA;IACE,2BAAiC;IAIjC,sCAyFC;IA5FD,aAAe;IAKb,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IACnB,+DAA+D;IAC/D,wBAA0B;IAE1B,0BAA0B;IAC1B,kBAAqB;IACrB,6CAA6C;IAC7C,gBAA2B;IAE3B,qBAA2B;IAE3B,cAA8C;IAI9C,kCAAqG;IAmEvG,0BAEC;IAED,0BAMC;IAED,qBAUC;IAED;;;;;;OAMG;IACH,4BALW,OAAO,iBACP,OAAO;;;;;;QAEL,IAAI,CA8ChB;IAED,2BAUC;IAED
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AAyBA;IACE,2BAAiC;IAIjC,sCAyFC;IA5FD,aAAe;IAKb,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IACnB,+DAA+D;IAC/D,wBAA0B;IAE1B,0BAA0B;IAC1B,kBAAqB;IACrB,6CAA6C;IAC7C,gBAA2B;IAE3B,qBAA2B;IAE3B,cAA8C;IAI9C,kCAAqG;IAmEvG,0BAEC;IAED,0BAMC;IAED,qBAUC;IAED;;;;;;OAMG;IACH,4BALW,OAAO,iBACP,OAAO;;;;;;QAEL,IAAI,CA8ChB;IAED,2BAUC;IAED,0BA0CC;IAED;;;;OAIG;IACH,6BAHW,MAAM,EAAE,GACN;QAAE,UAAU,EAAE,MAAM,GAAC,SAAS,CAAC;QAAC,SAAS,EAAE,MAAM,GAAC,SAAS,CAAA;KAAE,CAUzE;IAED;;;;;;;;;;MAsEC;IAED,sCAcC;IAED;;;;OAIG;IACH,mCAKC;IAED,yDAAyD;IACzD,+CASC;IAED,yCAIC;CACF;8BAxX6B,4BAA4B"}
|
|
@@ -13,6 +13,8 @@ export class Recorder {
|
|
|
13
13
|
events: RecorderEvents;
|
|
14
14
|
/** Backlog used for a 2-part sliding window to guarantee a 15-30s buffer window */
|
|
15
15
|
backloggedEvents: RecorderEvents;
|
|
16
|
+
/** Used to hold the harvest contents to facilitate retrying */
|
|
17
|
+
retryPayload: any;
|
|
16
18
|
/** Only set to true once a snapshot node has been processed. Used to block harvests from sending before we know we have a snapshot */
|
|
17
19
|
hasSeenSnapshot: boolean;
|
|
18
20
|
hasSeenMeta: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"AAqBA;IAUE,+
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/shared/recorder.js"],"names":[],"mappings":"AAqBA;IAUE,+BAoCC;IAtCD,sBAAmB;IAGjB,iDAAiD;IACjD,kBAAgC;IAEhC,QAAyB;IACzB,mBAA6C;IAC7C,cAAqC;IAErC,qBAAwB;IACxB,0FAA0F;IAC1F,eAAkE;IAElE,iHAAiH;IACjH,uBAAgD;IAChD,mFAAmF;IACnF,iCAA0D;IAC1D,+DAA+D;IAC/D,kBAA6B;IAC7B,uIAAuI;IACvI,yBAA4B;IAC5B,qBAAwB;IACxB,kIAAkI;IAClI,kBAAqB;IACrB,uIAAuI;IACvI,0BAAwE;IAc1E,mBAEC;IAED;;;;;;;;;MAWC;IAED,kFAAkF;IAClF,oBAGC;IAED,qDAAqD;IACrD,8CA0CC;IAED;;;;;OAKG;IACH,aAHW,GAAC,cACD,GAAC,QAiCX;IAED,yHAAyH;IACzH,yCAiCC;IAED,0HAA0H;IAC1H,yBAOC;IAED,wBAEC;IAED,gCAAgC;IAChC,uCAGC;IAED;;;SAGK;IACL,oCAGC;;CACF;+BAzO8B,mBAAmB"}
|
|
@@ -15,6 +15,7 @@ export class AjaxNode extends BelNode {
|
|
|
15
15
|
targetAttributes: any;
|
|
16
16
|
callbackEnd: any;
|
|
17
17
|
serialize(parentStartTimestamp: any, agentRef: any): string;
|
|
18
|
+
"ajaxRequest.id": any;
|
|
18
19
|
}
|
|
19
20
|
import { BelNode } from './bel-node';
|
|
20
21
|
//# sourceMappingURL=ajax-node.d.ts.map
|
|
@@ -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":"AASA;IACE,8CAuBC;IArBC,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;IAMhD,iBAAoE;IAKxE,4DAkCC;IA5CC,sBAAkC;CA6CrC;wBA/DuB,YAAY"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/browser-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.314.0-rc.1",
|
|
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
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
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
|
|
|
6
|
+
import { getRegisteredTargetsFromId } from '../v2/utils'
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* Generates a CSS selector path for the given element, if possible.
|
|
8
10
|
* Also gather metadata about the element's nearest fields, and whether there are any links or buttons in the path.
|
|
@@ -12,10 +14,11 @@
|
|
|
12
14
|
*
|
|
13
15
|
* @param {HTMLElement} elem
|
|
14
16
|
* @param {Array<string>} [targetFields=[]] specifies which fields to gather from the nearest element in the path
|
|
15
|
-
* @returns {{path: (undefined|string), nearestFields: {}, hasButton: boolean, hasLink: boolean}}
|
|
17
|
+
* @returns {{path: (undefined|string), nearestFields: {}, targets: Array, hasButton: boolean, hasLink: boolean}}
|
|
16
18
|
*/
|
|
17
|
-
export const analyzeElemPath = (elem, targetFields = []) => {
|
|
18
|
-
const
|
|
19
|
+
export const analyzeElemPath = (elem, targetFields = [], agentRef) => {
|
|
20
|
+
const targets = []
|
|
21
|
+
const result = { path: undefined, nearestFields: {}, get targets () { return targets.length ? targets : [undefined] }, hasButton: false, hasLink: false }
|
|
19
22
|
if (!elem) return result
|
|
20
23
|
if (elem === window) { result.path = 'window'; return result }
|
|
21
24
|
if (elem === document) { result.path = 'document'; return result }
|
|
@@ -30,6 +33,12 @@ export const analyzeElemPath = (elem, targetFields = []) => {
|
|
|
30
33
|
result.hasButton ||= tagName === 'button' || (tagName === 'input' && elem.type.toLowerCase() === 'button')
|
|
31
34
|
|
|
32
35
|
targetFields.forEach(field => { result.nearestFields[nearestAttrName(field)] ||= (elem[field]?.baseVal || elem[field]) })
|
|
36
|
+
|
|
37
|
+
const dataAttrs = elem?.dataset
|
|
38
|
+
if (dataAttrs.nrMfeId) {
|
|
39
|
+
targets.push(...getRegisteredTargetsFromId(dataAttrs.nrMfeId, agentRef))
|
|
40
|
+
}
|
|
41
|
+
|
|
33
42
|
pathSelector = buildPathSelector(elem, pathSelector)
|
|
34
43
|
elem = elem.parentNode
|
|
35
44
|
}
|
|
@@ -40,7 +40,12 @@ export class TimeKeeper {
|
|
|
40
40
|
*/
|
|
41
41
|
#ready = false
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
/**
|
|
44
|
+
* The total measured drift in milliseconds. Represents how much performance.now()
|
|
45
|
+
* has fallen behind Date.now(), which is used to correct timestamp conversions.
|
|
46
|
+
* @type {number}
|
|
47
|
+
*/
|
|
48
|
+
#measuredDrift = 0
|
|
44
49
|
|
|
45
50
|
constructor (sessionObj) {
|
|
46
51
|
this.#session = sessionObj
|
|
@@ -49,7 +54,6 @@ export class TimeKeeper {
|
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
#detectDrift () {
|
|
52
|
-
if (this.#reportedDrift) return
|
|
53
57
|
try {
|
|
54
58
|
// Drift detection: measures if performance.now() and Date.now() have become desynchronized
|
|
55
59
|
// This can happen when a machine sleeps and the performance timer freezes while Date continues
|
|
@@ -60,8 +64,13 @@ export class TimeKeeper {
|
|
|
60
64
|
// Note: localTimeDiff (server time offset) is NOT part of drift - that's a legitimate offset
|
|
61
65
|
const drift = (Date.now() - originTime) - performance.now()
|
|
62
66
|
if (drift > 1000) {
|
|
63
|
-
this
|
|
64
|
-
|
|
67
|
+
// Check if this is new drift (increase of >1000ms from last measurement)
|
|
68
|
+
const newDrift = drift - this.#measuredDrift
|
|
69
|
+
if (newDrift > 1000) {
|
|
70
|
+
// Update measured drift and report it
|
|
71
|
+
this.#measuredDrift = drift
|
|
72
|
+
if (this.#session) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/TimeKeeper/ClockDrift/Detected', drift], undefined, FEATURE_NAMES.metrics, this.#session.agentRef.ee)
|
|
73
|
+
}
|
|
65
74
|
}
|
|
66
75
|
} catch (err) {
|
|
67
76
|
// Silently ignore drift detection errors to avoid breaking normal operation
|
|
@@ -116,7 +125,8 @@ export class TimeKeeper {
|
|
|
116
125
|
*/
|
|
117
126
|
convertRelativeTimestamp (relativeTime) {
|
|
118
127
|
this.#detectDrift()
|
|
119
|
-
|
|
128
|
+
// Add measured drift to compensate for performance.now() falling behind
|
|
129
|
+
return originTime + relativeTime + this.#measuredDrift
|
|
120
130
|
}
|
|
121
131
|
|
|
122
132
|
/**
|
|
@@ -127,7 +137,8 @@ export class TimeKeeper {
|
|
|
127
137
|
*/
|
|
128
138
|
convertAbsoluteTimestamp (timestamp) {
|
|
129
139
|
this.#detectDrift()
|
|
130
|
-
|
|
140
|
+
// Subtract measured drift since we're converting from absolute to relative
|
|
141
|
+
return timestamp - originTime - this.#measuredDrift
|
|
131
142
|
}
|
|
132
143
|
|
|
133
144
|
/**
|
|
@@ -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 { onCLS } from 'web-vitals/attribution'
|
|
@@ -18,6 +18,6 @@ if (isBrowserScope) {
|
|
|
18
18
|
largestShiftValue: attribution.largestShiftValue,
|
|
19
19
|
loadState: attribution.loadState
|
|
20
20
|
}
|
|
21
|
-
cumulativeLayoutShift.update({ value, attrs })
|
|
21
|
+
cumulativeLayoutShift.update({ value, attrs, element: attribution.largestShiftSource?.node })
|
|
22
22
|
}, { reportAllChanges: true })
|
|
23
23
|
}
|
|
@@ -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 { onINP } from 'web-vitals/attribution'
|
|
@@ -25,6 +25,6 @@ if (isBrowserScope) {
|
|
|
25
25
|
presentationDelay: attribution.presentationDelay,
|
|
26
26
|
loadState: attribution.loadState
|
|
27
27
|
}
|
|
28
|
-
interactionToNextPaint.update({ value, attrs })
|
|
28
|
+
interactionToNextPaint.update({ value, attrs, element: attribution.interactionTargetElement })
|
|
29
29
|
})
|
|
30
30
|
}
|
|
@@ -31,6 +31,6 @@ if (isBrowserScope) {
|
|
|
31
31
|
if (attribution.element) attrs.element = attribution.element
|
|
32
32
|
if (attribution.url) attrs.elUrl = cleanURL(attribution.url)
|
|
33
33
|
|
|
34
|
-
largestContentfulPaint.update({ value, attrs })
|
|
34
|
+
largestContentfulPaint.update({ value, attrs, element: lcpEntry?.element })
|
|
35
35
|
})
|
|
36
36
|
}
|
|
@@ -12,12 +12,15 @@ export const loadTime = new VitalMetric(VITAL_NAMES.LOAD_TIME)
|
|
|
12
12
|
if (isBrowserScope) {
|
|
13
13
|
const perf = globalScope.performance
|
|
14
14
|
const handler = () => {
|
|
15
|
-
|
|
15
|
+
// setTimeout defers the read until after the load event handler returns,
|
|
16
|
+
// ensuring loadEventEnd is populated (non-zero) — matching the web-vitals onTTFB pattern
|
|
17
|
+
setTimeout(() => {
|
|
18
|
+
if (loadTime.isValid || !perf) return
|
|
16
19
|
const navEntry = getNavigationEntry()
|
|
17
20
|
loadTime.update({
|
|
18
21
|
value: navEntry ? navEntry.loadEventEnd : (perf.timing?.loadEventEnd - originTime)
|
|
19
22
|
})
|
|
20
|
-
}
|
|
23
|
+
}, 0)
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
onWindowLoad(handler, true)
|
|
@@ -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
|
export class VitalMetric {
|
|
@@ -12,12 +12,13 @@ export class VitalMetric {
|
|
|
12
12
|
this.roundingMethod = typeof roundingMethod === 'function' ? roundingMethod : Math.floor
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
update ({ value, attrs = {} }) {
|
|
15
|
+
update ({ value, attrs = {}, element }) {
|
|
16
16
|
if (value === undefined || value === null || value < 0) return
|
|
17
17
|
const state = {
|
|
18
18
|
value: this.roundingMethod(value),
|
|
19
19
|
name: this.name,
|
|
20
|
-
attrs
|
|
20
|
+
attrs,
|
|
21
|
+
element
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
this.history.push(state)
|
|
@@ -34,7 +35,8 @@ export class VitalMetric {
|
|
|
34
35
|
return this.history[this.history.length - 1] || {
|
|
35
36
|
value: undefined,
|
|
36
37
|
name: this.name,
|
|
37
|
-
attrs: {}
|
|
38
|
+
attrs: {},
|
|
39
|
+
element: undefined
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
|
|
@@ -6,13 +6,14 @@ import { registerHandler } from '../../../common/event-emitter/register-handler'
|
|
|
6
6
|
import { stringify } from '../../../common/util/stringify'
|
|
7
7
|
import { handle } from '../../../common/event-emitter/handle'
|
|
8
8
|
import { setDenyList, shouldCollectEvent } from '../../../common/deny-list/deny-list'
|
|
9
|
-
import { FEATURE_NAME } from '../constants'
|
|
9
|
+
import { AJAX_ID, FEATURE_NAME } from '../constants'
|
|
10
10
|
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
11
11
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
12
12
|
import { parseGQL } from './gql'
|
|
13
13
|
import { nullable, numeric, getAddStringContext, addCustomAttributes } from '../../../common/serialize/bel-serializer'
|
|
14
14
|
import { gosNREUMOriginals } from '../../../common/window/nreum'
|
|
15
15
|
import { getVersion2Attributes, getVersion2DuplicationAttributes, shouldDuplicate } from '../../../common/v2/utils'
|
|
16
|
+
import { generateUuid } from '../../../common/ids/unique-id'
|
|
16
17
|
|
|
17
18
|
export class Aggregate extends AggregateBase {
|
|
18
19
|
static featureName = FEATURE_NAME
|
|
@@ -91,7 +92,8 @@ export class Aggregate extends AggregateBase {
|
|
|
91
92
|
type,
|
|
92
93
|
startTime,
|
|
93
94
|
endTime,
|
|
94
|
-
callbackDuration: metrics.cbTime
|
|
95
|
+
callbackDuration: metrics.cbTime,
|
|
96
|
+
[AJAX_ID]: generateUuid() // all AjaxRequest events should have a unique identifier to allow for easier grouping and analysis in the UI
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
if (ctx.dt) {
|
|
@@ -168,7 +170,8 @@ export class Aggregate extends AggregateBase {
|
|
|
168
170
|
const attrParts = addCustomAttributes({
|
|
169
171
|
...(jsAttributes || {}),
|
|
170
172
|
...(event.gql || {}),
|
|
171
|
-
...(event.targetAttributes || {}) // used to supply the version 2 attributes, either MFE target or duplication attributes for the main agent app
|
|
173
|
+
...(event.targetAttributes || {}), // used to supply the version 2 attributes, either MFE target or duplication attributes for the main agent app
|
|
174
|
+
[AJAX_ID]: event[AJAX_ID] // all AjaxRequest events should have a unique identifier to allow for easier grouping and analysis in the UI
|
|
172
175
|
}, addString)
|
|
173
176
|
|
|
174
177
|
fields.unshift(numeric(attrParts.length))
|
|
@@ -1,7 +1,9 @@
|
|
|
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 { FEATURE_NAMES } from '../../loaders/features/features'
|
|
6
6
|
|
|
7
7
|
export const FEATURE_NAME = FEATURE_NAMES.ajax
|
|
8
|
+
|
|
9
|
+
export const AJAX_ID = 'ajaxRequest.id'
|
|
@@ -14,7 +14,7 @@ import { applyFnToProps } from '../../../common/util/traverse'
|
|
|
14
14
|
import { UserActionsAggregator } from './user-actions/user-actions-aggregator'
|
|
15
15
|
import { isIFrameWindow } from '../../../common/dom/iframe'
|
|
16
16
|
import { isPureObject } from '../../../common/util/type-check'
|
|
17
|
-
import { getVersion2Attributes } from '../../../common/v2/utils'
|
|
17
|
+
import { getVersion2Attributes, getVersion2DuplicationAttributes, shouldDuplicate } from '../../../common/v2/utils'
|
|
18
18
|
|
|
19
19
|
export class Aggregate extends AggregateBase {
|
|
20
20
|
static featureName = FEATURE_NAME
|
|
@@ -61,7 +61,7 @@ export class Aggregate extends AggregateBase {
|
|
|
61
61
|
|
|
62
62
|
let addUserAction = () => { /** no-op */ }
|
|
63
63
|
if (isBrowserScope && agentRef.init.user_actions.enabled) {
|
|
64
|
-
this.#userActionAggregator = new UserActionsAggregator()
|
|
64
|
+
this.#userActionAggregator = new UserActionsAggregator(this.agentRef)
|
|
65
65
|
this.harvestOpts.beforeUnload = () => addUserAction?.(this.#userActionAggregator.aggregationEvent)
|
|
66
66
|
|
|
67
67
|
addUserAction = (aggregatedUserAction) => {
|
|
@@ -70,50 +70,54 @@ export class Aggregate extends AggregateBase {
|
|
|
70
70
|
* so we still need to validate that an event was given to this method before we try to add */
|
|
71
71
|
if (aggregatedUserAction?.event) {
|
|
72
72
|
const { target, timeStamp, type } = aggregatedUserAction.event
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
|
|
74
|
+
aggregatedUserAction.targets.forEach(mfeTarget => {
|
|
75
|
+
const userActionEvent = {
|
|
76
|
+
eventType: 'UserAction',
|
|
77
|
+
timestamp: this.#toEpoch(timeStamp),
|
|
78
|
+
action: type,
|
|
79
|
+
actionCount: aggregatedUserAction.count,
|
|
80
|
+
actionDuration: aggregatedUserAction.relativeMs[aggregatedUserAction.relativeMs.length - 1],
|
|
81
|
+
actionMs: aggregatedUserAction.relativeMs,
|
|
82
|
+
rageClick: aggregatedUserAction.rageClick,
|
|
83
|
+
target: aggregatedUserAction.selectorPath,
|
|
84
|
+
currentUrl: aggregatedUserAction.currentUrl,
|
|
85
|
+
...(isIFrameWindow(window) && { iframe: true }),
|
|
86
|
+
...(this.agentRef.init.user_actions.elementAttributes.reduce((acc, field) => {
|
|
85
87
|
/** prevent us from capturing an obscenely long value */
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
if (canTrustTargetAttribute(field)) acc[targetAttrName(field)] = String(target[field]).trim().slice(0, 128)
|
|
89
|
+
return acc
|
|
90
|
+
}, {})),
|
|
91
|
+
...aggregatedUserAction.nearestTargetFields,
|
|
92
|
+
...(aggregatedUserAction.deadClick && { deadClick: true }),
|
|
93
|
+
...(aggregatedUserAction.errorClick && { errorClick: true })
|
|
94
|
+
}
|
|
95
|
+
this.addEvent(userActionEvent, mfeTarget)
|
|
96
|
+
|
|
97
|
+
this.#trackUserActionSM(userActionEvent)
|
|
98
|
+
|
|
99
|
+
/**
|
|
97
100
|
* Returns the original target field name with `target` prepended and camelCased
|
|
98
101
|
* @param {string} originalFieldName
|
|
99
102
|
* @returns {string} the target field name
|
|
100
103
|
*/
|
|
101
|
-
|
|
104
|
+
function targetAttrName (originalFieldName) {
|
|
102
105
|
/** preserve original renaming structure for pre-existing field maps */
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
if (originalFieldName === 'tagName') originalFieldName = 'tag'
|
|
107
|
+
if (originalFieldName === 'className') originalFieldName = 'class'
|
|
108
|
+
/** return the original field name, cap'd and prepended with target to match formatting */
|
|
109
|
+
return `target${originalFieldName.charAt(0).toUpperCase() + originalFieldName.slice(1)}`
|
|
110
|
+
}
|
|
108
111
|
|
|
109
|
-
|
|
112
|
+
/**
|
|
110
113
|
* Only trust attributes that exist on HTML element targets, which excludes the window and the document targets
|
|
111
114
|
* @param {string} attribute The attribute to check for on the target element
|
|
112
115
|
* @returns {boolean} Whether the target element has the attribute and can be trusted
|
|
113
116
|
*/
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
+
function canTrustTargetAttribute (attribute) {
|
|
118
|
+
return !!(aggregatedUserAction.selectorPath !== 'window' && aggregatedUserAction.selectorPath !== 'document' && target instanceof HTMLElement && target?.[attribute])
|
|
119
|
+
}
|
|
120
|
+
})
|
|
117
121
|
}
|
|
118
122
|
} catch (e) {
|
|
119
123
|
// do nothing for now
|
|
@@ -314,9 +318,7 @@ export class Aggregate extends AggregateBase {
|
|
|
314
318
|
timestamp: this.#toEpoch(now()),
|
|
315
319
|
/** all generic events require pageUrl(s) */
|
|
316
320
|
pageUrl: cleanURL('' + initialLocation),
|
|
317
|
-
currentUrl: cleanURL('' + location)
|
|
318
|
-
/** Specific attributes only supplied if harvesting to endpoint version 2 */
|
|
319
|
-
...(getVersion2Attributes(target, this))
|
|
321
|
+
currentUrl: cleanURL('' + location)
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
const eventAttributes = {
|
|
@@ -328,7 +330,8 @@ export class Aggregate extends AggregateBase {
|
|
|
328
330
|
...obj
|
|
329
331
|
}
|
|
330
332
|
|
|
331
|
-
this.events.add(eventAttributes)
|
|
333
|
+
this.events.add({ ...eventAttributes, ...getVersion2Attributes(target, this) })
|
|
334
|
+
if (shouldDuplicate(target, this)) this.addEvent({ ...eventAttributes, ...getVersion2DuplicationAttributes(target, this) })
|
|
332
335
|
}
|
|
333
336
|
|
|
334
337
|
serializer (eventBuffer) {
|