@newrelic/browser-agent 1.297.1-rc.4 → 1.297.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cjs/common/constants/env.cdn.js +1 -1
  2. package/dist/cjs/common/constants/env.npm.js +1 -1
  3. package/dist/cjs/common/vitals/largest-contentful-paint.js +1 -4
  4. package/dist/cjs/common/wrap/wrap-function.js +4 -9
  5. package/dist/cjs/features/ajax/aggregate/index.js +2 -10
  6. package/dist/cjs/features/ajax/instrument/index.js +0 -1
  7. package/dist/cjs/features/jserrors/aggregate/index.js +4 -9
  8. package/dist/cjs/features/soft_navigations/aggregate/ajax-node.js +3 -11
  9. package/dist/cjs/features/soft_navigations/aggregate/index.js +14 -38
  10. package/dist/cjs/features/soft_navigations/aggregate/interaction.js +20 -34
  11. package/dist/cjs/features/soft_navigations/constants.js +4 -8
  12. package/dist/cjs/features/soft_navigations/instrument/index.js +6 -9
  13. package/dist/esm/common/constants/env.cdn.js +1 -1
  14. package/dist/esm/common/constants/env.npm.js +1 -1
  15. package/dist/esm/common/vitals/largest-contentful-paint.js +1 -4
  16. package/dist/esm/common/wrap/wrap-function.js +4 -9
  17. package/dist/esm/features/ajax/aggregate/index.js +2 -10
  18. package/dist/esm/features/ajax/instrument/index.js +0 -1
  19. package/dist/esm/features/jserrors/aggregate/index.js +4 -9
  20. package/dist/esm/features/soft_navigations/aggregate/ajax-node.js +3 -11
  21. package/dist/esm/features/soft_navigations/aggregate/index.js +15 -39
  22. package/dist/esm/features/soft_navigations/aggregate/interaction.js +21 -35
  23. package/dist/esm/features/soft_navigations/constants.js +3 -7
  24. package/dist/esm/features/soft_navigations/instrument/index.js +7 -10
  25. package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
  26. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  27. package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
  28. package/dist/types/features/jserrors/aggregate/index.d.ts +1 -1
  29. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  30. package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts +1 -2
  31. package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts.map +1 -1
  32. package/dist/types/features/soft_navigations/aggregate/index.d.ts +1 -1
  33. package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
  34. package/dist/types/features/soft_navigations/aggregate/interaction.d.ts +3 -6
  35. package/dist/types/features/soft_navigations/aggregate/interaction.d.ts.map +1 -1
  36. package/dist/types/features/soft_navigations/constants.d.ts +0 -4
  37. package/dist/types/features/soft_navigations/constants.d.ts.map +1 -1
  38. package/dist/types/features/soft_navigations/instrument/index.d.ts.map +1 -1
  39. package/package.json +2 -2
  40. package/src/common/vitals/largest-contentful-paint.js +1 -2
  41. package/src/common/wrap/wrap-function.js +4 -9
  42. package/src/features/ajax/aggregate/index.js +2 -10
  43. package/src/features/ajax/instrument/index.js +0 -1
  44. package/src/features/jserrors/aggregate/index.js +6 -10
  45. package/src/features/soft_navigations/aggregate/ajax-node.js +4 -8
  46. package/src/features/soft_navigations/aggregate/index.js +15 -39
  47. package/src/features/soft_navigations/aggregate/interaction.js +19 -33
  48. package/src/features/soft_navigations/constants.js +2 -5
  49. package/src/features/soft_navigations/instrument/index.js +8 -9
@@ -39,7 +39,7 @@ export class Aggregate extends AggregateBase {
39
39
  this.ee.on('interactionDone', (interaction, wasSaved) => this.onInteractionDone(interaction, wasSaved));
40
40
  register('err', (...args) => this.storeError(...args), this.featureName, this.ee);
41
41
  register('ierr', (...args) => this.storeError(...args), this.featureName, this.ee);
42
- register('softNavFlush', (interactionId, wasFinished, softNavAttrs, interactionEndTime) => this.onSoftNavNotification(interactionId, wasFinished, softNavAttrs, interactionEndTime), this.featureName, this.ee); // when an ixn is done or cancelled
42
+ register('softNavFlush', (interactionId, wasFinished, softNavAttrs) => this.onSoftNavNotification(interactionId, wasFinished, softNavAttrs), this.featureName, this.ee); // when an ixn is done or cancelled
43
43
 
44
44
  this.harvestOpts.aggregatorTypes = ['err', 'ierr', 'xhr']; // the types in EventAggregator this feature cares about
45
45
 
@@ -266,15 +266,10 @@ export class Aggregate extends AggregateBase {
266
266
  });
267
267
  delete this.bufferedErrorsUnderSpa[interaction.id];
268
268
  }
269
- onSoftNavNotification(interactionId, wasFinished, softNavAttrs, interactionEndTime) {
269
+ onSoftNavNotification(interactionId, wasFinished, softNavAttrs) {
270
270
  if (this.blocked) return;
271
- this.bufferedErrorsUnderSpa[interactionId]?.forEach(jsErrorEvent => {
272
- // this should not modify the re-used softNavAttrs contents
273
- if (!wasFinished) return this.#storeJserrorForHarvest(jsErrorEvent, false, softNavAttrs);
274
- const startTime = jsErrorEvent[3].time; // in storeError fn, the newMetrics obj contains the time passed to & used by SN to seek the ixn
275
- if (startTime > interactionEndTime) return this.#storeJserrorForHarvest(jsErrorEvent, false, softNavAttrs); // disassociate any error that ultimately falls outside the final ixn span
276
- return this.#storeJserrorForHarvest(jsErrorEvent, true, softNavAttrs);
277
- });
271
+ this.bufferedErrorsUnderSpa[interactionId]?.forEach(jsErrorEvent => this.#storeJserrorForHarvest(jsErrorEvent, wasFinished, softNavAttrs) // this should not modify the re-used softNavAttrs contents
272
+ );
278
273
  delete this.bufferedErrorsUnderSpa[interactionId]; // wipe the list of jserrors so they aren't duplicated by another call to the same id
279
274
  }
280
275
  }
@@ -6,7 +6,7 @@ import { addCustomAttributes, getAddStringContext, nullable, numeric } from '../
6
6
  import { NODE_TYPE } from '../constants';
7
7
  import { BelNode } from './bel-node';
8
8
  export class AjaxNode extends BelNode {
9
- constructor(ajaxEvent, ajaxContext) {
9
+ constructor(ajaxEvent) {
10
10
  super();
11
11
  this.belType = NODE_TYPE.AJAX;
12
12
  this.method = ajaxEvent.method;
@@ -20,12 +20,8 @@ export class AjaxNode extends BelNode {
20
20
  this.traceId = ajaxEvent.traceId;
21
21
  this.spanTimestamp = ajaxEvent.spanTimestamp;
22
22
  this.gql = ajaxEvent.gql;
23
- this.start = ajaxEvent.startTime;
23
+ this.start = ajaxEvent.startTime; // 5000 --- 5500 --> 10500
24
24
  this.end = ajaxEvent.endTime;
25
- if (ajaxContext?.latestLongtaskEnd) {
26
- this.callbackEnd = Math.max(ajaxContext.latestLongtaskEnd, this.end); // typically lt end if non-zero, but added clamping to end just in case
27
- this.callbackDuration = this.callbackEnd - this.end; // callbackDuration is the time from ajax loaded to last long task observed from it
28
- } else this.callbackEnd = this.end; // if no long task was observed, callbackEnd is the same as end
29
25
  }
30
26
  serialize(parentStartTimestamp, agentRef) {
31
27
  const addString = getAddStringContext(agentRef.runtime.obfuscator);
@@ -38,11 +34,7 @@ export class AjaxNode extends BelNode {
38
34
  // start relative to parent start (if part of first node in payload) or first parent start
39
35
  numeric(this.end - this.start),
40
36
  // end is relative to start
41
- numeric(this.callbackEnd - this.end),
42
- // callbackEnd is relative to end
43
- numeric(this.callbackDuration),
44
- // not relative
45
- 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)];
37
+ numeric(this.callbackEnd), numeric(this.callbackDuration), 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)];
46
38
  let allAttachedNodes = [];
47
39
  if (typeof this.gql === 'object') allAttachedNodes = addCustomAttributes(this.gql, addString);
48
40
  this.children.forEach(node => allAttachedNodes.push(node.serialize())); // no children is expected under ajax nodes at this time
@@ -8,7 +8,7 @@ import { single } from '../../../common/util/invoke';
8
8
  import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte';
9
9
  import { FEATURE_NAMES } from '../../../loaders/features/features';
10
10
  import { AggregateBase } from '../../utils/aggregate-base';
11
- import { API_TRIGGER_NAME, FEATURE_NAME, INTERACTION_STATUS, INTERACTION_TRIGGERS, IPL_TRIGGER_NAME, NO_LONG_TASK_WINDOW, POPSTATE_MERGE_WINDOW, POPSTATE_TRIGGER } from '../constants';
11
+ import { API_TRIGGER_NAME, FEATURE_NAME, INTERACTION_STATUS, INTERACTION_TRIGGERS, IPL_TRIGGER_NAME } from '../constants';
12
12
  import { AjaxNode } from './ajax-node';
13
13
  import { InitialPageLoadInteraction } from './initial-page-load-interaction';
14
14
  import { Interaction } from './interaction';
@@ -40,7 +40,7 @@ export class Aggregate extends AggregateBase {
40
40
  });
41
41
  this.latestRouteSetByApi = null;
42
42
  this.interactionInProgress = null; // aside from the "page load" interaction, there can only ever be 1 ongoing at a time
43
- this.latestHistoryUrl = window.location.href; // the initial url is needed to get a correct oldURL in the case that the first nav is triggered by 'popstate'
43
+ this.latestHistoryUrl = null;
44
44
  this.harvestOpts.beforeUnload = () => this.interactionInProgress?.done(); // return any withheld ajax or jserr events so they can be sent with EoL harvest
45
45
 
46
46
  this.waitForFlags(['spa']).then(([spaOn]) => {
@@ -56,25 +56,14 @@ export class Aggregate extends AggregateBase {
56
56
  // By default, a complete UI driven interaction requires event -> URL change -> DOM mod in that exact order.
57
57
  registerHandler('newUIEvent', event => this.startUIInteraction(event.type, Math.floor(event.timeStamp), event.target), this.featureName, this.ee);
58
58
  registerHandler('newURL', (timestamp, url) => {
59
- // The newURL always need to be tracked such that it becomes the oldURL of the next potential popstate ixn.
60
- // Because for 'popstate' triggered newUIEVent, by the time the event fires, the page URL has already changed so the previous URL is lost if not recorded.
59
+ // In the case of 'popstate' trigger, by the time the event fires, the URL has already changed, so we need to store what-will-be the *previous* URL for oldURL of next popstate ixn.
61
60
  this.latestHistoryUrl = url;
62
61
  this.interactionInProgress?.updateHistory(timestamp, url);
63
62
  }, this.featureName, this.ee);
64
63
  registerHandler('newDom', timestamp => {
65
64
  this.interactionInProgress?.updateDom(timestamp);
66
- this.interactionInProgress?.checkHistoryAndDomChange();
65
+ if (this.interactionInProgress?.seenHistoryAndDomChange()) this.interactionInProgress.done();
67
66
  }, this.featureName, this.ee);
68
- this.ee.on('long-task', task => {
69
- if (!this.interactionInProgress?.watchLongtaskTimer) return; // no ixn in progress or it's not yet in a pending-finish state, as indicated by the lack of a watchLongtask timeout
70
- clearTimeout(this.interactionInProgress.watchLongtaskTimer);
71
- // Provided there isn't another long task, the ixn span will be extended to include this long task that would finish the interaction.
72
- this.interactionInProgress.customEnd = task.end;
73
- this.interactionInProgress.watchLongtaskTimer = setTimeout(() => this.interactionInProgress.done(), NO_LONG_TASK_WINDOW);
74
-
75
- // Report metric on frequency of ixn extension due to long task
76
- this.reportSupportabilityMetric('SoftNav/Interaction/Extended');
77
- });
78
67
  this.#registerApiHandlers();
79
68
  registerHandler('ajax', this.#handleAjaxEvent.bind(this), this.featureName, this.ee);
80
69
  registerHandler('jserror', this.#handleJserror.bind(this), this.featureName, this.ee);
@@ -93,11 +82,9 @@ export class Aggregate extends AggregateBase {
93
82
  startUIInteraction(eventName, startedAt, sourceElem) {
94
83
  // this is throttled by instrumentation so that it isn't excessively called
95
84
  if (this.interactionInProgress?.createdByApi) return; // api-started interactions cannot be disrupted aka cancelled by UI events (and the vice versa applies as well)
96
- // Navs from interacting with the document will emit the UI event like click, followed by a popstate which should be squashed given some margin of time. This prevents it from cancelling the first UI ixn.
97
- if (eventName === POPSTATE_TRIGGER && this.interactionInProgress?.trigger !== POPSTATE_TRIGGER && startedAt - this.interactionInProgress?.start <= POPSTATE_MERGE_WINDOW) return;
98
- if (this.interactionInProgress?.done() === false) return; // current in-progress is blocked from closing if true, e.g. by 'waitForEnd' api option; notice this cancels/finishes existing in-progress ixn
85
+ if (this.interactionInProgress?.done() === false) return; // current in-progress is blocked from closing, e.g. by 'waitForEnd' api option
99
86
 
100
- const oldURL = eventName === POPSTATE_TRIGGER ? this.latestHistoryUrl : undefined; // see related comment in 'newURL' handler above, 'popstate'
87
+ const oldURL = eventName === INTERACTION_TRIGGERS[3] ? this.latestHistoryUrl : undefined; // see related comment in 'newURL' handler above, 'popstate'
101
88
  this.interactionInProgress = new Interaction(eventName, startedAt, this.latestRouteSetByApi, oldURL);
102
89
  if (eventName === INTERACTION_TRIGGERS[0]) {
103
90
  // 'click'
@@ -160,30 +147,22 @@ export class Aggregate extends AggregateBase {
160
147
  /**
161
148
  * Handles or redirect ajax event based on the interaction, if any, that it's tied to.
162
149
  * @param {Object} event see Ajax feature's storeXhr function for object definition
163
- * @param {Object} metadata reference to the ajax context, used to pass long task info
164
150
  */
165
- #handleAjaxEvent(event, metadata) {
151
+ #handleAjaxEvent(event) {
166
152
  const associatedInteraction = this.getInteractionFor(event.startTime);
167
153
  if (!associatedInteraction) {
168
154
  // no interaction was happening when this ajax started, so give it back to Ajax feature for processing
169
155
  handle('returnAjax', [event], undefined, FEATURE_NAMES.ajax, this.ee);
170
156
  } else {
171
- if (associatedInteraction.status === INTERACTION_STATUS.FIN) processAjax.call(this, event, metadata, associatedInteraction); // tack ajax onto the ixn object awaiting harvest
157
+ if (associatedInteraction.status === INTERACTION_STATUS.FIN) processAjax(event, associatedInteraction); // tack ajax onto the ixn object awaiting harvest
172
158
  else {
173
159
  // same thing as above, just at a later time -- if the interaction in progress is cancelled, just send the event back to ajax feat unmodified
174
- associatedInteraction.on('finished', () => processAjax.call(this, event, metadata, associatedInteraction));
160
+ associatedInteraction.on('finished', () => processAjax(event, associatedInteraction));
175
161
  associatedInteraction.on('cancelled', () => handle('returnAjax', [event], undefined, FEATURE_NAMES.ajax, this.ee));
176
162
  }
177
163
  }
178
- function processAjax(event, metadata, parentInteraction) {
179
- const finalEnd = parentInteraction.end; // assume: by the time the 'finished' event occurs & this executes, the ixn end time accounts for any long task extension + lookback window exclusion
180
- if (event.startTime > finalEnd) {
181
- handle('returnAjax', [event], undefined, FEATURE_NAMES.ajax, this.ee); // falling outside the final span, returned as standalone
182
- return;
183
- }
184
-
185
- // Metadata(ctx) should contain any long task end time associated with this XHR which should be up-to-date by the time the in-progress ixn & ajax children are being finalized for harvest.
186
- const newNode = new AjaxNode(event, metadata);
164
+ function processAjax(event, parentInteraction) {
165
+ const newNode = new AjaxNode(event);
187
166
  parentInteraction.addChild(newNode);
188
167
  }
189
168
  }
@@ -206,7 +185,7 @@ export class Aggregate extends AggregateBase {
206
185
  } else {
207
186
  // These callbacks may be added multiple times for an ixn, but just a single run will deal with all jserrors associated with the interaction.
208
187
  // As such, be cautious not to use the params object since that's tied to one specific jserror and won't affect the rest of them.
209
- associatedInteraction.on('finished', single(() => handle('softNavFlush', [associatedInteraction.id, true, associatedInteraction.customAttributes, associatedInteraction.end], undefined, FEATURE_NAMES.jserrors, this.ee)));
188
+ associatedInteraction.on('finished', single(() => handle('softNavFlush', [associatedInteraction.id, true, associatedInteraction.customAttributes], undefined, FEATURE_NAMES.jserrors, this.ee)));
210
189
  associatedInteraction.on('cancelled', single(() => handle('softNavFlush', [associatedInteraction.id, false, undefined], undefined, FEATURE_NAMES.jserrors, this.ee))); // don't take custom attrs from cancelled ixns
211
190
  }
212
191
  }
@@ -221,7 +200,7 @@ export class Aggregate extends AggregateBase {
221
200
  this.associatedInteraction = thisClass.getInteractionFor(time);
222
201
  if (this.associatedInteraction?.trigger === IPL_TRIGGER_NAME) this.associatedInteraction = null; // the api get-interaction method cannot target IPL
223
202
  if (!this.associatedInteraction) {
224
- // This new api-driven interaction will be the target of any subsequent .interaction() call, until it is closed by EITHER .end() OR the regular url>dom change process.
203
+ // This new api-driven interaction will be the target of any subsequent .interaction() call, until it is closed by EITHER .end() OR the regular seenHistoryAndDomChange process.
225
204
  this.associatedInteraction = thisClass.interactionInProgress = new Interaction(API_TRIGGER_NAME, time, thisClass.latestRouteSetByApi);
226
205
  thisClass.domObserver.observe(document.body, {
227
206
  attributes: true,
@@ -231,13 +210,10 @@ export class Aggregate extends AggregateBase {
231
210
  }); // start observing for DOM changes like a regular UI-driven interaction
232
211
  thisClass.setClosureHandlers();
233
212
  }
234
- if (waitForEnd === true) {
235
- this.associatedInteraction.keepOpenUntilEndApi = true;
236
- clearTimeout(this.associatedInteraction.cancellationTimer); // get rid of the auto-cancel 30s timer for UI ixns when users specify waitForEnd manual override
237
- }
213
+ if (waitForEnd === true) this.associatedInteraction.keepOpenUntilEndApi = true;
238
214
  }, thisClass.featureName, thisClass.ee);
239
215
  registerHandler(INTERACTION_API + 'end', function (timeNow) {
240
- this.associatedInteraction.done(timeNow, true);
216
+ this.associatedInteraction.done(timeNow);
241
217
  }, thisClass.featureName, thisClass.ee);
242
218
  registerHandler(INTERACTION_API + 'save', function () {
243
219
  this.associatedInteraction.forceSave = true;
@@ -7,7 +7,7 @@ import { generateUuid } from '../../../common/ids/unique-id';
7
7
  import { addCustomAttributes, getAddStringContext, nullable, numeric } from '../../../common/serialize/bel-serializer';
8
8
  import { now } from '../../../common/timing/now';
9
9
  import { cleanURL } from '../../../common/url/clean-url';
10
- import { NODE_TYPE, INTERACTION_STATUS, INTERACTION_TYPE, API_TRIGGER_NAME, IPL_TRIGGER_NAME, NO_LONG_TASK_WINDOW } from '../constants';
10
+ import { NODE_TYPE, INTERACTION_STATUS, INTERACTION_TYPE, API_TRIGGER_NAME, IPL_TRIGGER_NAME } from '../constants';
11
11
  import { BelNode } from './bel-node';
12
12
 
13
13
  /**
@@ -29,9 +29,7 @@ export class Interaction extends BelNode {
29
29
  createdByApi = false;
30
30
  keepOpenUntilEndApi = false;
31
31
  onDone = [];
32
- customEnd = 0;
33
32
  cancellationTimer;
34
- watchLongtaskTimer;
35
33
  constructor(uiEvent, uiEventTimestamp, currentRouteKnown, currentUrl) {
36
34
  super();
37
35
  this.belType = NODE_TYPE.INTERACTION;
@@ -43,48 +41,36 @@ export class Interaction extends BelNode {
43
41
  if (this.trigger === API_TRIGGER_NAME) this.createdByApi = true;
44
42
  this.newURL = this.oldURL = currentUrl || globalScope?.location.href;
45
43
  }
46
- updateHistory(timestamp, newUrl) {
47
- if (this.domTimestamp > 0) return; // url is locked once ui>url>dom change sequence is seen
48
- if (!newUrl || newUrl === this.oldURL) return; // url must be different for interaction heuristic to proceed
49
- this.newURL = newUrl;
50
- this.historyTimestamp = timestamp || now();
51
- }
52
44
  updateDom(timestamp) {
53
- if (!this.historyTimestamp || timestamp < this.historyTimestamp) return; // dom change must come after (any) url change, though this can be updated multiple times, taking the last dom timestamp
54
45
  this.domTimestamp = timestamp || now(); // default timestamp should be precise for accurate isActiveDuring calculations
55
46
  }
56
- checkHistoryAndDomChange() {
57
- if (!(this.historyTimestamp > 0 && this.domTimestamp > this.historyTimestamp)) return false;
58
- if (this.status === INTERACTION_STATUS.PF) return true; // indicate the finishing process has already started for this interaction
59
- this.status = INTERACTION_STATUS.PF; // set for eventual harvest
60
-
61
- // Once the fixed reqs for a nav has been met, start a X countdown timer that watches for any long task, if it doesn't already exist, before completing the interaction.
62
- clearTimeout(this.cancellationTimer); // "pending-finish" ixns cannot be auto cancelled anymore
63
- this.watchLongtaskTimer ??= setTimeout(() => this.done(), NO_LONG_TASK_WINDOW);
64
- // Notice that by not providing a specific end time to `.done()`, the ixn will use the dom timestamp in the event of no long task, which is what we want.
65
- return true;
47
+ updateHistory(timestamp, newUrl) {
48
+ this.newURL = newUrl || '' + globalScope?.location;
49
+ this.historyTimestamp = timestamp || now();
50
+ }
51
+ seenHistoryAndDomChange() {
52
+ return this.historyTimestamp > 0 && this.domTimestamp > this.historyTimestamp; // URL must change before DOM does
66
53
  }
67
54
  on(event, cb) {
68
55
  if (!this.eventSubscription.has(event)) throw new Error('Cannot subscribe to non pre-defined events.');
69
56
  if (typeof cb !== 'function') throw new Error('Must supply function as callback.');
70
57
  this.eventSubscription.get(event).push(cb);
71
58
  }
72
- done(customEndTime = this.customEnd, calledByApi = false) {
73
- // User could've mark this interaction--regardless UI or api started--as "don't close until .end() is called on it".
74
- if (this.keepOpenUntilEndApi && !calledByApi) return false;
59
+ done(customEndTime) {
60
+ // User could've mark this interaction--regardless UI or api started--as "don't close until .end() is called on it". Only .end provides a timestamp; the default flows do not.
61
+ if (this.keepOpenUntilEndApi && customEndTime === undefined) return false;
75
62
  // If interaction is already closed, this is a no-op. However, returning true lets startUIInteraction know that it CAN start a new interaction, as this one is done.
76
- if (this.status === INTERACTION_STATUS.FIN || this.status === INTERACTION_STATUS.CAN) return true;
77
- clearTimeout(this.cancellationTimer); // clean up timers in case this is called by any flow that doesn't already do so
78
- clearTimeout(this.watchLongtaskTimer);
63
+ if (this.status !== INTERACTION_STATUS.IP) return true;
79
64
  this.onDone.forEach(apiProvidedCb => apiProvidedCb(this.customDataByApi)); // this interaction's .save or .ignore can still be set by these user provided callbacks for example
80
65
 
81
66
  if (this.forceIgnore) this.#cancel(); // .ignore() always has precedence over save actions
82
- else if (this.status === INTERACTION_STATUS.PF) this.#finish(customEndTime); // then this should've already finished while it was the interactionInProgress, with a natural end time
67
+ else if (this.seenHistoryAndDomChange()) this.#finish(customEndTime); // then this should've already finished while it was the interactionInProgress, with a natural end time
83
68
  else if (this.forceSave) this.#finish(customEndTime || performance.now()); // a manually saved ixn (did not fulfill conditions) must have a specified end time, if one wasn't provided
84
69
  else this.#cancel();
85
70
  return true;
86
71
  }
87
- #finish(customEndTime) {
72
+ #finish(customEndTime = 0) {
73
+ clearTimeout(this.cancellationTimer);
88
74
  this.end = Math.max(this.domTimestamp, this.historyTimestamp, customEndTime);
89
75
  this.status = INTERACTION_STATUS.FIN;
90
76
 
@@ -93,6 +79,7 @@ export class Interaction extends BelNode {
93
79
  callbacks.forEach(fn => fn());
94
80
  }
95
81
  #cancel() {
82
+ clearTimeout(this.cancellationTimer);
96
83
  this.status = INTERACTION_STATUS.CAN;
97
84
 
98
85
  // Run all the callbacks listening to this interaction's potential cancellation.
@@ -103,13 +90,12 @@ export class Interaction extends BelNode {
103
90
  /**
104
91
  * Given a timestamp, determine if it falls within this interaction's span, i.e. if this was the active interaction during that time.
105
92
  * For in-progress interactions, this only compares the time with the start of span. Cancelled interactions are not considered active at all.
106
- * Pending-finish interactions are also considered still active wrt assigning ajax or jserrors to them during the wait period.
107
93
  * @param {DOMHighResTimeStamp} timestamp
108
94
  * @returns True or false boolean.
109
95
  */
110
96
  isActiveDuring(timestamp) {
111
- if (this.status === INTERACTION_STATUS.IP || this.status === INTERACTION_STATUS.PF) return this.start <= timestamp;
112
- return this.status === INTERACTION_STATUS.FIN && this.start <= timestamp && timestamp < this.end;
97
+ if (this.status === INTERACTION_STATUS.IP) return this.start <= timestamp;
98
+ return this.status === INTERACTION_STATUS.FIN && this.start <= timestamp && this.end > timestamp;
113
99
  }
114
100
 
115
101
  // Following are virtual properties overridden by a subclass:
@@ -137,10 +123,10 @@ export class Interaction extends BelNode {
137
123
  // the very 1st ixn does not require offset so it should fallback to a 0 while rest is offset by the very 1st ixn's start
138
124
  numeric(this.end - this.start),
139
125
  // end -- relative to start
140
- numeric(0),
141
- // callbackEnd -- relative to start; not used by BrowserInteraction events so these are always 0
142
- numeric(0),
143
- // not relative; always 0 for BrowserInteraction
126
+ numeric(this.callbackEnd),
127
+ // cbEnd -- relative to start; not used by BrowserInteraction events
128
+ numeric(this.callbackDuration),
129
+ // not relative
144
130
  addString(this.trigger), addString(cleanURL(this.initialPageURL, true)), addString(cleanURL(this.oldURL, true)), addString(cleanURL(this.newURL, true)), addString(this.customName), ixnType, nullable(this.queueTime, numeric, true) + nullable(this.appTime, numeric, true) + nullable(this.oldRoute, addString, true) + nullable(this.newRoute, addString, true) + addString(this.id), addString(this.nodeId), nullable(this.firstPaint, numeric, true) + nullable(this.firstContentfulPaint, numeric)];
145
131
  const customAttributes = {
146
132
  ...agentRef.info.jsAttributes,
@@ -7,15 +7,13 @@ export const INTERACTION_TRIGGERS = ['click',
7
7
  // e.g. user clicks link or the page back/forward buttons
8
8
  'keydown',
9
9
  // e.g. user presses left and right arrow key to switch between displayed photo gallery
10
- 'submit' // e.g. user clicks submit butotn or presses enter while editing a form field
10
+ 'submit',
11
+ // e.g. user clicks submit butotn or presses enter while editing a form field
12
+ 'popstate' // history api is used to navigate back and forward
11
13
  ];
12
- export const POPSTATE_TRIGGER = 'popstate'; // e.g. user clicks browser back/forward button or history API is used programmatically
13
14
  export const API_TRIGGER_NAME = 'api';
14
15
  export const IPL_TRIGGER_NAME = 'initialPageLoad';
15
16
  export const FEATURE_NAME = FEATURE_NAMES.softNav;
16
- export const NO_LONG_TASK_WINDOW = 5000; // purpose is to wait 5 seconds wherein no long task is detected
17
- export const POPSTATE_MERGE_WINDOW = 500; // "coalesce" (discard) a popstate that happen within this period following an INTERACTION_TRIGGER opening ixn, e.g. click->popstate
18
-
19
17
  export const INTERACTION_TYPE = {
20
18
  INITIAL_PAGE_LOAD: '',
21
19
  ROUTE_CHANGE: 1,
@@ -29,8 +27,6 @@ export const NODE_TYPE = {
29
27
  };
30
28
  export const INTERACTION_STATUS = {
31
29
  IP: 'in progress',
32
- PF: 'pending finish',
33
- // interaction meets the hard criteria but is awaiting flexible conditions to fully finish
34
30
  FIN: 'finished',
35
31
  CAN: 'cancelled'
36
32
  };
@@ -9,7 +9,7 @@ import { windowAddEventListener } from '../../../common/event-listener/event-lis
9
9
  import { debounce } from '../../../common/util/invoke';
10
10
  import { wrapHistory } from '../../../common/wrap/wrap-history';
11
11
  import { InstrumentBase } from '../../utils/instrument-base';
12
- import { FEATURE_NAME, INTERACTION_TRIGGERS, POPSTATE_TRIGGER } from '../constants';
12
+ import { FEATURE_NAME, INTERACTION_TRIGGERS } from '../constants';
13
13
  import { now } from '../../../common/timing/now';
14
14
  import { setupInteractionAPI } from '../../../loaders/api/interaction';
15
15
 
@@ -30,22 +30,19 @@ export class Instrument extends InstrumentBase {
30
30
  if (!isBrowserScope || !gosNREUMOriginals().o.MO) return; // soft navigations is not supported outside web env or browsers without the mutation observer API
31
31
 
32
32
  const historyEE = wrapHistory(this.ee);
33
- try {
34
- this.removeOnAbort = new AbortController();
35
- } catch (e) {}
36
33
  INTERACTION_TRIGGERS.forEach(trigger => {
37
34
  windowAddEventListener(trigger, evt => {
38
35
  processUserInteraction(evt);
39
- }, true, this.removeOnAbort?.signal);
36
+ }, true);
40
37
  });
41
38
  const trackURLChange = () => handle('newURL', [now(), '' + window.location], undefined, this.featureName, this.ee);
42
39
  historyEE.on('pushState-end', trackURLChange);
43
40
  historyEE.on('replaceState-end', trackURLChange);
44
- windowAddEventListener(POPSTATE_TRIGGER, evt => {
45
- // popstate is unique in that it serves as BOTH a UI event and a notification of URL change
46
- processUserInteraction(evt);
47
- handle('newURL', [evt.timeStamp, '' + window.location], undefined, this.featureName, this.ee);
48
- }, true, this.removeOnAbort?.signal);
41
+ try {
42
+ this.removeOnAbort = new AbortController();
43
+ } catch (e) {}
44
+ const trackURLChangeEvent = evt => handle('newURL', [evt.timeStamp, '' + window.location], undefined, this.featureName, this.ee);
45
+ windowAddEventListener('popstate', trackURLChangeEvent, true, this.removeOnAbort?.signal);
49
46
  let oncePerFrame = false; // attempt to reduce dom noice since the observer runs very frequently with below options
50
47
  const domObserver = new (gosNREUMOriginals().o.MO)((domChanges, observer) => {
51
48
  if (oncePerFrame) return;
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-function.d.ts","sourceRoot":"","sources":["../../../../src/common/wrap/wrap-function.js"],"names":[],"mappings":"AA8BA;;;;;GAKG;AACH,mDAJW,MAAM,UACN,OAAO,YAmJjB;AAgBD;;;;;;;;GAQG;AACH,2BANW,MAAM,MACN,MAAM,YACN,MAAM,GAEJ,MAAM,CA2BlB;AA1ND,0BAA6C"}
1
+ {"version":3,"file":"wrap-function.d.ts","sourceRoot":"","sources":["../../../../src/common/wrap/wrap-function.js"],"names":[],"mappings":"AA6BA;;;;;GAKG;AACH,mDAJW,MAAM,UACN,OAAO,YA+IjB;AAgBD;;;;;;;;GAQG;AACH,2BANW,MAAM,MACN,MAAM,YACN,MAAM,GAEJ,MAAM,CA2BlB;AArND,0BAA6C"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/aggregate/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IAEjC,2BAsCC;IAnCC,mBAAwB;IAqC1B,6FA0EC;IAED,iDA6CC;CACF;8BA1K6B,4BAA4B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/aggregate/index.js"],"names":[],"mappings":"AAcA;IACE,2BAAiC;IAEjC,2BA+BC;IA5BC,mBAAwB;IA8B1B,6FA0EC;IAED,iDA6CC;CACF;8BAlK6B,4BAA4B"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/instrument/index.js"],"names":[],"mappings":"AA6BA;IACE,2BAAiC;IACjC,2BAkCC;IA/BC,OAA0B;IAE1B,8DAAkF;CA8BrF;AAmWD,qCAA8B;+BAtZC,6BAA6B;mBAFzC,uBAAuB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/instrument/index.js"],"names":[],"mappings":"AA6BA;IACE,2BAAiC;IACjC,2BAkCC;IA/BC,OAA0B;IAE1B,8DAAkF;CA8BrF;AAkWD,qCAA8B;+BArZC,6BAA6B;mBAFzC,uBAAuB"}
@@ -42,7 +42,7 @@ export class Aggregate extends AggregateBase {
42
42
  */
43
43
  shouldAllowMainAgentToCapture(entityGuid: string): boolean;
44
44
  onInteractionDone(interaction: any, wasSaved: any): void;
45
- onSoftNavNotification(interactionId: any, wasFinished: any, softNavAttrs: any, interactionEndTime: any): void;
45
+ onSoftNavNotification(interactionId: any, wasFinished: any, softNavAttrs: any): void;
46
46
  #private;
47
47
  }
48
48
  export type StackInfo = import("./compute-stack-trace.js").StackInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"AAyBA;;GAEG;AAEH;IACE,2BAAiC;IACjC,2BA4BC;IAzBC,kBAAuB;IACvB,eAAoB;IACpB,qBAA0B;IAC1B,2BAAgC;IAChC,qBAAwB;IAuB1B,oDAEC;IAED;;;MAcC;IAED;;;;;;OAMG;IACH,qCAHW,SAAS,GACP,MAAM,CAgBlB;IAED;;;;;;;;;;OAUG;IACH,gBATW,KAAK,GAAC,aAAa,QACnB,MAAM,aACN,OAAO,YAAC,qBACR,MAAM,YAAC,cACP,OAAO,YAAC,kBACR,MAAM,YAAC,+BAiHjB;IA4BD;;;;;MAKE;IACF,0CAHU,MAAM,GACJ,OAAO,CAIlB;IAGD,yDA6BC;IAED,8GAWC;;CACF;wBAxRY,OAAO,0BAA0B,EAAE,SAAS;8BAT3B,4BAA4B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/jserrors/aggregate/index.js"],"names":[],"mappings":"AAyBA;;GAEG;AAEH;IACE,2BAAiC;IACjC,2BA4BC;IAzBC,kBAAuB;IACvB,eAAoB;IACpB,qBAA0B;IAC1B,2BAAgC;IAChC,qBAAwB;IAuB1B,oDAEC;IAED;;;MAcC;IAED;;;;;;OAMG;IACH,qCAHW,SAAS,GACP,MAAM,CAgBlB;IAED;;;;;;;;;;OAUG;IACH,gBATW,KAAK,GAAC,aAAa,QACnB,MAAM,aACN,OAAO,YAAC,qBACR,MAAM,YAAC,cACP,OAAO,YAAC,kBACR,MAAM,YAAC,+BAiHjB;IA4BD;;;;;MAKE;IACF,0CAHU,MAAM,GACJ,OAAO,CAIlB;IAGD,yDA6BC;IAED,qFAOC;;CACF;wBApRY,OAAO,0BAA0B,EAAE,SAAS;8BAT3B,4BAA4B"}
@@ -1,5 +1,5 @@
1
1
  export class AjaxNode extends BelNode {
2
- constructor(ajaxEvent: any, ajaxContext: any);
2
+ constructor(ajaxEvent: any);
3
3
  belType: number;
4
4
  method: any;
5
5
  status: any;
@@ -12,7 +12,6 @@ export class AjaxNode extends BelNode {
12
12
  traceId: any;
13
13
  spanTimestamp: any;
14
14
  gql: any;
15
- callbackEnd: any;
16
15
  serialize(parentStartTimestamp: any, agentRef: any): string;
17
16
  }
18
17
  import { BelNode } from './bel-node';
@@ -1 +1 @@
1
- {"version":3,"file":"ajax-node.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/ajax-node.js"],"names":[],"mappings":"AAQA;IACE,8CAqBC;IAnBC,gBAA6B;IAC7B,YAA8B;IAC9B,YAA8B;IAC9B,YAA8B;IAC9B,UAA0B;IAC1B,YAAmC;IACnC,YAAoC;IACpC,+BAAwD;IACxD,YAA8B;IAC9B,aAAgC;IAChC,mBAA4C;IAC5C,SAAwB;IAKtB,iBAAoE;IAKxE,4DA+BC;CACF;wBA1DuB,YAAY"}
1
+ {"version":3,"file":"ajax-node.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/ajax-node.js"],"names":[],"mappings":"AAQA;IACE,4BAiBC;IAfC,gBAA6B;IAC7B,YAA8B;IAC9B,YAA8B;IAC9B,YAA8B;IAC9B,UAA0B;IAC1B,YAAmC;IACnC,YAAoC;IACpC,+BAAwD;IACxD,YAA8B;IAC9B,aAAgC;IAChC,mBAA4C;IAC5C,SAAwB;IAM1B,4DA+BC;CACF;wBAtDuB,YAAY"}
@@ -8,7 +8,7 @@ export class Aggregate extends AggregateBase {
8
8
  initialPageLoadInteraction: InitialPageLoadInteraction;
9
9
  latestRouteSetByApi: any;
10
10
  interactionInProgress: Interaction | null;
11
- latestHistoryUrl: string;
11
+ latestHistoryUrl: any;
12
12
  serializer(eventBuffer: any): string;
13
13
  startUIInteraction(eventName: any, startedAt: any, sourceElem: any): void;
14
14
  setClosureHandlers(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IACjC;;OAiEC;IA5DC,2BAAwC;IACxC,iBAA8B;IAE9B,uDAA0E;IAe1E,yBAA+B;IAC/B,0CAAiC;IACjC,yBAA4C;IA0C9C,qCAUC;IAED,0EAmBC;IAED,2BAiBC;IAED;;;;;;;OAOG;IACH,6BAHW,mBAAmB,OAsB7B;;CAwGF;8BAlQ6B,4BAA4B;2CAGf,iCAAiC;4BAChD,eAAe"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IACjC;;OAsDC;IAjDC,2BAAwC;IACxC,iBAA8B;IAE9B,uDAA0E;IAe1E,yBAA+B;IAC/B,0CAAiC;IACjC,sBAA4B;IA+B9B,qCAUC;IAED,0EAiBC;IAED,2BAiBC;IAED;;;;;;;OAOG;IACH,6BAHW,mBAAmB,OAsB7B;;CA6FF;8BA1O6B,4BAA4B;2CAGf,iCAAiC;4BAChD,eAAe"}
@@ -18,9 +18,7 @@ export class Interaction extends BelNode {
18
18
  createdByApi: boolean;
19
19
  keepOpenUntilEndApi: boolean;
20
20
  onDone: any[];
21
- customEnd: number;
22
21
  cancellationTimer: any;
23
- watchLongtaskTimer: any;
24
22
  belType: number;
25
23
  trigger: any;
26
24
  oldRoute: any;
@@ -29,15 +27,14 @@ export class Interaction extends BelNode {
29
27
  forceIgnore: boolean;
30
28
  newURL: any;
31
29
  oldURL: any;
32
- updateHistory(timestamp: any, newUrl: any): void;
33
30
  updateDom(timestamp: any): void;
34
- checkHistoryAndDomChange(): boolean;
31
+ updateHistory(timestamp: any, newUrl: any): void;
32
+ seenHistoryAndDomChange(): boolean;
35
33
  on(event: any, cb: any): void;
36
- done(customEndTime?: number, calledByApi?: boolean): boolean;
34
+ done(customEndTime: any): boolean;
37
35
  /**
38
36
  * Given a timestamp, determine if it falls within this interaction's span, i.e. if this was the active interaction during that time.
39
37
  * For in-progress interactions, this only compares the time with the start of span. Cancelled interactions are not considered active at all.
40
- * Pending-finish interactions are also considered still active wrt assigning ajax or jserrors to them during the wait period.
41
38
  * @param {DOMHighResTimeStamp} timestamp
42
39
  * @returns True or false boolean.
43
40
  */
@@ -1 +1 @@
1
- {"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/interaction.js"],"names":[],"mappings":"AAYA;;IAEI;AACJ;IAoBE,0FAaC;IAhCD,WAAmB;IACnB,uBAAgC;IAChC,gBAAU;IACV,qBAAqB;IACrB,oBAAoB;IACpB,eAAS;IACT,aAAO;IACP,cAAQ;IACR,+EAA+E;IAC/E,eAA8B;IAC9B,qBAAgB;IAChB,yBAAoB;IACpB,sBAAoB;IACpB,6BAA2B;IAC3B,cAAW;IACX,kBAAa;IACb,uBAAiB;IACjB,wBAAkB;IAIhB,gBAAoC;IACpC,aAAsB;IAEtB,cAAiC;IACjC,wCAGE;IACF,mBAAyC;IAAxB,qBAAwB;IAEzC,YAAsE;IAAxD,YAAwD;IAGxE,iDAKC;IAED,gCAGC;IAED,oCAUC;IAED,8BAIC;IAED,6DAeC;IAmBD;;;;;;OAMG;IACH,0BAHW,mBAAmB,WAM7B;IAGD,uBAAoB;IACpB,iCAA8B;IAC9B,sBAAmB;IAEnB;;;;;OAKG;IACH,qDAHW,KAAK,UAgDf;;CACF;wBA7KuB,YAAY"}
1
+ {"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/interaction.js"],"names":[],"mappings":"AAYA;;IAEI;AACJ;IAkBE,0FAaC;IA9BD,WAAmB;IACnB,uBAAgC;IAChC,gBAAU;IACV,qBAAqB;IACrB,oBAAoB;IACpB,eAAS;IACT,aAAO;IACP,cAAQ;IACR,+EAA+E;IAC/E,eAA8B;IAC9B,qBAAgB;IAChB,yBAAoB;IACpB,sBAAoB;IACpB,6BAA2B;IAC3B,cAAW;IACX,uBAAiB;IAIf,gBAAoC;IACpC,aAAsB;IAEtB,cAAiC;IACjC,wCAGE;IACF,mBAAyC;IAAxB,qBAAwB;IAEzC,YAAsE;IAAxD,YAAwD;IAGxE,gCAEC;IAED,iDAGC;IAED,mCAEC;IAED,8BAIC;IAED,kCAaC;IAqBD;;;;;OAKG;IACH,0BAHW,mBAAmB,WAM7B;IAGD,uBAAoB;IACpB,iCAA8B;IAC9B,sBAAmB;IAEnB;;;;;OAKG;IACH,qDAHW,KAAK,UAgDf;;CACF;wBA/JuB,YAAY"}
@@ -1,10 +1,7 @@
1
1
  export const INTERACTION_TRIGGERS: string[];
2
- export const POPSTATE_TRIGGER: "popstate";
3
2
  export const API_TRIGGER_NAME: "api";
4
3
  export const IPL_TRIGGER_NAME: "initialPageLoad";
5
4
  export const FEATURE_NAME: string;
6
- export const NO_LONG_TASK_WINDOW: 5000;
7
- export const POPSTATE_MERGE_WINDOW: 500;
8
5
  export namespace INTERACTION_TYPE {
9
6
  let INITIAL_PAGE_LOAD: string;
10
7
  let ROUTE_CHANGE: number;
@@ -18,7 +15,6 @@ export namespace NODE_TYPE {
18
15
  }
19
16
  export namespace INTERACTION_STATUS {
20
17
  let IP: string;
21
- let PF: string;
22
18
  let FIN: string;
23
19
  let CAN: string;
24
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/soft_navigations/constants.js"],"names":[],"mappings":"AAMA,4CAIC;AACD,+BAAgC,UAAU,CAAA;AAC1C,+BAAgC,KAAK,CAAA;AACrC,+BAAgC,iBAAiB,CAAA;AAEjD,kCAAiD;AACjD,kCAAmC,IAAI,CAAA;AACvC,oCAAqC,GAAG,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/features/soft_navigations/constants.js"],"names":[],"mappings":"AAMA,4CAKC;AACD,+BAAgC,KAAK,CAAA;AACrC,+BAAgC,iBAAiB,CAAA;AAEjD,kCAAiD"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/instrument/index.js"],"names":[],"mappings":"AAsBA;IACE,2BAAiC;IACjC,2BAkDC;IAxCG,2CAA0C;CAyC/C;AAED,wCAAiC;+BAnEF,6BAA6B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/instrument/index.js"],"names":[],"mappings":"AAsBA;IACE,2BAAiC;IACjC,2BAiDC;IA5BG,2CAA0C;CA6B/C;AAED,wCAAiC;+BAlEF,6BAA6B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.297.1-rc.4",
3
+ "version": "1.297.1",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -291,4 +291,4 @@
291
291
  "README.md",
292
292
  "CHANGELOG.md"
293
293
  ]
294
- }
294
+ }
@@ -26,8 +26,7 @@ if (isBrowserScope) {
26
26
  resourceLoadDelay: attribution.resourceLoadDelay,
27
27
  resourceLoadDuration: attribution.resourceLoadDuration,
28
28
  resourceLoadTime: attribution.resourceLoadDuration, // kept for NR backwards compatibility, deprecated in v3->v4
29
- elementRenderDelay: attribution.elementRenderDelay,
30
- ...(attribution.navigationEntry && { pageUrl: cleanURL(attribution.navigationEntry.name) }) // used to ensure the LCP gets the correct URL at harvest time if a soft nav has occurred before page load
29
+ elementRenderDelay: attribution.elementRenderDelay
31
30
  }
32
31
  if (attribution.url) attrs.elUrl = cleanURL(attribution.url)
33
32
  if (lcpEntry.element?.tagName) attrs.elTag = lcpEntry.element.tagName
@@ -11,7 +11,6 @@ import { ee } from '../event-emitter/contextual-ee'
11
11
  import { bundleId } from '../ids/bundle-id'
12
12
 
13
13
  export const flag = `nr@original:${bundleId}`
14
- const LONG_TASK_THRESHOLD = 50
15
14
 
16
15
  /**
17
16
  * A convenience alias of `hasOwnProperty`.
@@ -96,7 +95,7 @@ export function createWrapperWithEmitter (emitter, always) {
96
95
  safeEmit(prefix + 'start', [args, originalThis, methodName], ctx, bubble)
97
96
 
98
97
  const fnStartTime = performance.now()
99
- let fnEndTime
98
+ let fnEndTime = fnStartTime
100
99
  try {
101
100
  result = fn.apply(originalThis, args)
102
101
  fnEndTime = performance.now()
@@ -110,20 +109,16 @@ export function createWrapperWithEmitter (emitter, always) {
110
109
  } finally {
111
110
  const duration = fnEndTime - fnStartTime
112
111
  const task = {
113
- start: fnStartTime,
114
- end: fnEndTime,
115
112
  duration,
116
- isLongTask: duration >= LONG_TASK_THRESHOLD,
113
+ isLongTask: duration >= 50,
117
114
  methodName,
118
115
  thrownError
119
116
  // could add more properties here later if needed by downstream features
120
117
  }
121
118
  // standalone long task message
122
- if (task.isLongTask) {
123
- safeEmit('long-task', [task, originalThis], ctx, bubble)
124
- }
119
+ if (task.isLongTask) safeEmit('long-task', [task], ctx, bubble)
125
120
  // -end message also includes the task execution info
126
- safeEmit(prefix + 'end', [args, originalThis, result], ctx, bubble)
121
+ safeEmit(prefix + 'end', [args, originalThis, result, task], ctx, bubble)
127
122
  }
128
123
  }
129
124
  }