@newrelic/browser-agent 1.278.0 → 1.278.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.278.2](https://github.com/newrelic/newrelic-browser-agent/compare/v1.278.1...v1.278.2) (2025-01-09)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * Allow the page view feature to have access to an event buffer ([#1315](https://github.com/newrelic/newrelic-browser-agent/issues/1315)) ([64babe1](https://github.com/newrelic/newrelic-browser-agent/commit/64babe18a5c4190f6d7bdc775fe5f55db095c892))
12
+
13
+ ## [1.278.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.278.0...v1.278.1) (2025-01-08)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * Make Metrics harvest only on EoL for new Harvester ([#1311](https://github.com/newrelic/newrelic-browser-agent/issues/1311)) ([5cecedc](https://github.com/newrelic/newrelic-browser-agent/commit/5cecedcad6af7a14ec0e6777eba059ff1a5c008d))
19
+
6
20
  ## [1.278.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.277.0...v1.278.0) (2025-01-07)
7
21
 
8
22
 
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = exports.VERSION = "1.278.0";
15
+ const VERSION = exports.VERSION = "1.278.2";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = exports.VERSION = "1.278.0";
15
+ const VERSION = exports.VERSION = "1.278.2";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -64,7 +64,7 @@ class Harvester {
64
64
  let ranSend = false;
65
65
  if (!localOpts.directSend) {
66
66
  // primarily used by rum call to bypass makeHarvestPayload by providing payload directly
67
- dataToSendArr = aggregateInst.makeHarvestPayload(shouldRetryOnFail); // be sure the 'this' of makeHarvestPayload is the aggregate w/ access to its harvestOpts
67
+ dataToSendArr = aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts); // be sure the 'this' of makeHarvestPayload is the aggregate w/ access to its harvestOpts
68
68
  if (!dataToSendArr) return false; // can be undefined if storage is empty or preharvest checks failed
69
69
  } else dataToSendArr = [localOpts.directSend];
70
70
  dataToSendArr.forEach(({
@@ -38,9 +38,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
38
38
  this.singleChecks(); // checks that are run only one time, at script load
39
39
  this.eachSessionChecks(); // the start of every time user engages with page
40
40
  }
41
- preHarvestChecks() {
42
- return this.drained;
43
- } // only allow any metrics to be sent if we know for sure it has gotten the go-ahead RUM flag
41
+ preHarvestChecks(opts) {
42
+ return this.drained && opts.isFinalHarvest;
43
+ } // only allow any metrics to be sent after we get the right RUM flag and only on EoL
44
44
 
45
45
  storeSupportabilityMetrics(name, value) {
46
46
  if (this.blocked) return;
@@ -125,8 +125,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
125
125
  xhr
126
126
  }) {
127
127
  const rumEndTime = (0, _now.now)();
128
- this.blocked = true; // this prevents harvester from polling this feature's event buffer (DNE) on interval; in other words, harvests will skip PVE
129
-
130
128
  if (status >= 400 || status === 0) {
131
129
  (0, _console.warn)(18, status);
132
130
  // Adding retry logic for the rum call will be a separate change; this.blocked will need to be changed since that prevents another triggerHarvestFor()
@@ -23,8 +23,7 @@ class AggregateBase extends _featureBase.FeatureBase {
23
23
 
24
24
  // This switch needs to be after doOnceForAllAggregate which may new sharedAggregator and reset mainAppKey.
25
25
  switch (this.featureName) {
26
- // PVE has no need for eventBuffer, and SessionTrace + Replay have their own storage mechanisms.
27
- case _features.FEATURE_NAMES.pageViewEvent:
26
+ // SessionTrace + Replay have their own storage mechanisms.
28
27
  case _features.FEATURE_NAMES.sessionTrace:
29
28
  case _features.FEATURE_NAMES.sessionReplay:
30
29
  break;
@@ -33,6 +32,9 @@ class AggregateBase extends _featureBase.FeatureBase {
33
32
  case _features.FEATURE_NAMES.metrics:
34
33
  this.events = agentRef.sharedAggregator;
35
34
  break;
35
+ /** All other features get EventBuffer in the ESM by default. Note: PVE is included here, but event buffer will always be empty so future harvests will still not happen by interval or EOL.
36
+ This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
37
+ Its easier to just keep an empty event buffer in place. */
36
38
  default:
37
39
  this.events = new _eventStoreManager.EventStoreManager(agentRef.mainAppKey, 1);
38
40
  break;
@@ -75,17 +77,17 @@ class AggregateBase extends _featureBase.FeatureBase {
75
77
  /**
76
78
  * Return harvest payload. A "serializer" function can be defined on a derived class to format the payload.
77
79
  * @param {Boolean} shouldRetryOnFail - harvester flag to backup payload for retry later if harvest request fails; this should be moved to harvester logic
78
- * @param {object|undefined} target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
80
+ * @param {object|undefined} opts.target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
79
81
  * @returns {Array} Final payload tagged with their targeting browser app. The value of `payload` can be undefined if there are no pending events for an app. This should be a minimum length of 1.
80
82
  */
81
- makeHarvestPayload(shouldRetryOnFail = false, target) {
82
- if (this.events.isEmpty(this.harvestOpts, target)) return;
83
+ makeHarvestPayload(shouldRetryOnFail = false, opts = {}) {
84
+ if (this.events.isEmpty(this.harvestOpts, opts.target)) return;
83
85
  // Other conditions and things to do when preparing harvest that is required.
84
- if (this.preHarvestChecks && !this.preHarvestChecks()) return;
85
- if (shouldRetryOnFail) this.events.save(this.harvestOpts, target);
86
- const returnedDataArr = this.events.get(this.harvestOpts, target);
86
+ if (this.preHarvestChecks && !this.preHarvestChecks(opts)) return;
87
+ if (shouldRetryOnFail) this.events.save(this.harvestOpts, opts.target);
88
+ const returnedDataArr = this.events.get(this.harvestOpts, opts.target);
87
89
  if (!returnedDataArr.length) throw new Error('Unexpected problem encountered. There should be at least one app for harvest!');
88
- this.events.clear(this.harvestOpts, target);
90
+ this.events.clear(this.harvestOpts, opts.target);
89
91
  return returnedDataArr.map(({
90
92
  targetApp,
91
93
  data
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.278.0";
9
+ export const VERSION = "1.278.2";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.278.0";
9
+ export const VERSION = "1.278.2";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -58,7 +58,7 @@ export class Harvester {
58
58
  let ranSend = false;
59
59
  if (!localOpts.directSend) {
60
60
  // primarily used by rum call to bypass makeHarvestPayload by providing payload directly
61
- dataToSendArr = aggregateInst.makeHarvestPayload(shouldRetryOnFail); // be sure the 'this' of makeHarvestPayload is the aggregate w/ access to its harvestOpts
61
+ dataToSendArr = aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts); // be sure the 'this' of makeHarvestPayload is the aggregate w/ access to its harvestOpts
62
62
  if (!dataToSendArr) return false; // can be undefined if storage is empty or preharvest checks failed
63
63
  } else dataToSendArr = [localOpts.directSend];
64
64
  dataToSendArr.forEach(({
@@ -32,9 +32,9 @@ export class Aggregate extends AggregateBase {
32
32
  this.singleChecks(); // checks that are run only one time, at script load
33
33
  this.eachSessionChecks(); // the start of every time user engages with page
34
34
  }
35
- preHarvestChecks() {
36
- return this.drained;
37
- } // only allow any metrics to be sent if we know for sure it has gotten the go-ahead RUM flag
35
+ preHarvestChecks(opts) {
36
+ return this.drained && opts.isFinalHarvest;
37
+ } // only allow any metrics to be sent after we get the right RUM flag and only on EoL
38
38
 
39
39
  storeSupportabilityMetrics(name, value) {
40
40
  if (this.blocked) return;
@@ -117,8 +117,6 @@ export class Aggregate extends AggregateBase {
117
117
  xhr
118
118
  }) {
119
119
  const rumEndTime = now();
120
- this.blocked = true; // this prevents harvester from polling this feature's event buffer (DNE) on interval; in other words, harvests will skip PVE
121
-
122
120
  if (status >= 400 || status === 0) {
123
121
  warn(18, status);
124
122
  // Adding retry logic for the rum call will be a separate change; this.blocked will need to be changed since that prevents another triggerHarvestFor()
@@ -17,8 +17,7 @@ export class AggregateBase extends FeatureBase {
17
17
 
18
18
  // This switch needs to be after doOnceForAllAggregate which may new sharedAggregator and reset mainAppKey.
19
19
  switch (this.featureName) {
20
- // PVE has no need for eventBuffer, and SessionTrace + Replay have their own storage mechanisms.
21
- case FEATURE_NAMES.pageViewEvent:
20
+ // SessionTrace + Replay have their own storage mechanisms.
22
21
  case FEATURE_NAMES.sessionTrace:
23
22
  case FEATURE_NAMES.sessionReplay:
24
23
  break;
@@ -27,6 +26,9 @@ export class AggregateBase extends FeatureBase {
27
26
  case FEATURE_NAMES.metrics:
28
27
  this.events = agentRef.sharedAggregator;
29
28
  break;
29
+ /** All other features get EventBuffer in the ESM by default. Note: PVE is included here, but event buffer will always be empty so future harvests will still not happen by interval or EOL.
30
+ This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
31
+ Its easier to just keep an empty event buffer in place. */
30
32
  default:
31
33
  this.events = new EventStoreManager(agentRef.mainAppKey, 1);
32
34
  break;
@@ -69,17 +71,17 @@ export class AggregateBase extends FeatureBase {
69
71
  /**
70
72
  * Return harvest payload. A "serializer" function can be defined on a derived class to format the payload.
71
73
  * @param {Boolean} shouldRetryOnFail - harvester flag to backup payload for retry later if harvest request fails; this should be moved to harvester logic
72
- * @param {object|undefined} target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
74
+ * @param {object|undefined} opts.target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
73
75
  * @returns {Array} Final payload tagged with their targeting browser app. The value of `payload` can be undefined if there are no pending events for an app. This should be a minimum length of 1.
74
76
  */
75
- makeHarvestPayload(shouldRetryOnFail = false, target) {
76
- if (this.events.isEmpty(this.harvestOpts, target)) return;
77
+ makeHarvestPayload(shouldRetryOnFail = false, opts = {}) {
78
+ if (this.events.isEmpty(this.harvestOpts, opts.target)) return;
77
79
  // Other conditions and things to do when preparing harvest that is required.
78
- if (this.preHarvestChecks && !this.preHarvestChecks()) return;
79
- if (shouldRetryOnFail) this.events.save(this.harvestOpts, target);
80
- const returnedDataArr = this.events.get(this.harvestOpts, target);
80
+ if (this.preHarvestChecks && !this.preHarvestChecks(opts)) return;
81
+ if (shouldRetryOnFail) this.events.save(this.harvestOpts, opts.target);
82
+ const returnedDataArr = this.events.get(this.harvestOpts, opts.target);
81
83
  if (!returnedDataArr.length) throw new Error('Unexpected problem encountered. There should be at least one app for harvest!');
82
- this.events.clear(this.harvestOpts, target);
84
+ this.events.clear(this.harvestOpts, opts.target);
83
85
  return returnedDataArr.map(({
84
86
  targetApp,
85
87
  data
@@ -1,7 +1,7 @@
1
1
  export class Aggregate extends AggregateBase {
2
2
  static featureName: string;
3
3
  constructor(agentRef: any);
4
- preHarvestChecks(): boolean | undefined;
4
+ preHarvestChecks(opts: any): any;
5
5
  storeSupportabilityMetrics(name: any, value: any): void;
6
6
  storeEventMetrics(name: any, metrics: any): void;
7
7
  singleChecks(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/metrics/aggregate/index.js"],"names":[],"mappings":"AAYA;IACE,2BAAiC;IACjC,2BAoBC;IAED,wCAA2C;IAE3C,wDAKC;IAED,iDAKC;IAED,qBAqEC;IAED,0BAOC;CACF;8BA5H6B,4BAA4B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/metrics/aggregate/index.js"],"names":[],"mappings":"AAYA;IACE,2BAAiC;IACjC,2BAoBC;IAED,iCAAsE;IAEtE,wDAKC;IAED,iDAKC;IAED,qBAqEC;IAED,0BAOC;CACF;8BA5H6B,4BAA4B"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_event/aggregate/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAA2C;IAC3C,2BA0BC;IAvBC,wBAAwB;IACxB,8BAA8B;IAC9B,8BAA8B;IAuBhC,gBAmEC;IATC,iCAAyB;IAW3B;;;;aAwBC;CACF;8BApI6B,4BAA4B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_event/aggregate/index.js"],"names":[],"mappings":"AAgBA;IACE,2BAA2C;IAC3C,2BA0BC;IAvBC,wBAAwB;IACxB,8BAA8B;IAC9B,8BAA8B;IAuBhC,gBAmEC;IATC,iCAAyB;IAW3B;;;;aAuBC;CACF;8BAnI6B,4BAA4B"}
@@ -13,10 +13,10 @@ export class AggregateBase extends FeatureBase {
13
13
  /**
14
14
  * Return harvest payload. A "serializer" function can be defined on a derived class to format the payload.
15
15
  * @param {Boolean} shouldRetryOnFail - harvester flag to backup payload for retry later if harvest request fails; this should be moved to harvester logic
16
- * @param {object|undefined} target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
16
+ * @param {object|undefined} opts.target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
17
17
  * @returns {Array} Final payload tagged with their targeting browser app. The value of `payload` can be undefined if there are no pending events for an app. This should be a minimum length of 1.
18
18
  */
19
- makeHarvestPayload(shouldRetryOnFail: boolean | undefined, target: object | undefined): any[];
19
+ makeHarvestPayload(shouldRetryOnFail?: boolean, opts?: {}): any[];
20
20
  /**
21
21
  * Cleanup task after a harvest.
22
22
  * @param {object} result - the cbResult object from the harvester's send method
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"AAWA;IAGI,cAAwB;IAcpB,YAAuC;IAM3C,gBAAqB;IAGvB;;;;OAIG;IACH,yBAHW,MAAM,EAAE,gBAwBlB;IAED,cAGC;IADC,6BAAmB;IAGrB;;;;;OAKG;IACH,mEAHW,MAAM,GAAC,SAAS,SAwB1B;IAED;;;OAGG;IACH,4BAFW,MAAM,QAMhB;IAED;;;OAGG;IACH,6CAsBC;IAED;;;OAGG;IACH,2CASC;IAPC,gBAA6C;CAQhD;4BAvJ2B,gBAAgB"}
1
+ {"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"AAWA;IAGI,cAAwB;IAapB,YAAuC;IAS3C,gBAAqB;IAGvB;;;;OAIG;IACH,yBAHW,MAAM,EAAE,gBAwBlB;IAED,cAGC;IADC,6BAAmB;IAGrB;;;;;OAKG;IACH,kEAqBC;IAED;;;OAGG;IACH,4BAFW,MAAM,QAMhB;IAED;;;OAGG;IACH,6CAsBC;IAED;;;OAGG;IACH,2CASC;IAPC,gBAA6C;CAQhD;4BAzJ2B,gBAAgB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.278.0",
3
+ "version": "1.278.2",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -57,7 +57,7 @@ export class Harvester {
57
57
  const shouldRetryOnFail = !localOpts.isFinalHarvest && submitMethod === xhrMethod // always retry all features harvests except for final
58
58
  let dataToSendArr; let ranSend = false
59
59
  if (!localOpts.directSend) { // primarily used by rum call to bypass makeHarvestPayload by providing payload directly
60
- dataToSendArr = aggregateInst.makeHarvestPayload(shouldRetryOnFail) // be sure the 'this' of makeHarvestPayload is the aggregate w/ access to its harvestOpts
60
+ dataToSendArr = aggregateInst.makeHarvestPayload(shouldRetryOnFail, localOpts) // be sure the 'this' of makeHarvestPayload is the aggregate w/ access to its harvestOpts
61
61
  if (!dataToSendArr) return false // can be undefined if storage is empty or preharvest checks failed
62
62
  } else dataToSendArr = [localOpts.directSend]
63
63
 
@@ -34,7 +34,7 @@ export class Aggregate extends AggregateBase {
34
34
  this.eachSessionChecks() // the start of every time user engages with page
35
35
  }
36
36
 
37
- preHarvestChecks () { return this.drained } // only allow any metrics to be sent if we know for sure it has gotten the go-ahead RUM flag
37
+ preHarvestChecks (opts) { return this.drained && opts.isFinalHarvest } // only allow any metrics to be sent after we get the right RUM flag and only on EoL
38
38
 
39
39
  storeSupportabilityMetrics (name, value) {
40
40
  if (this.blocked) return
@@ -115,7 +115,6 @@ export class Aggregate extends AggregateBase {
115
115
 
116
116
  postHarvestCleanup ({ status, responseText, xhr }) {
117
117
  const rumEndTime = now()
118
- this.blocked = true // this prevents harvester from polling this feature's event buffer (DNE) on interval; in other words, harvests will skip PVE
119
118
 
120
119
  if (status >= 400 || status === 0) {
121
120
  warn(18, status)
@@ -18,8 +18,7 @@ export class AggregateBase extends FeatureBase {
18
18
 
19
19
  // This switch needs to be after doOnceForAllAggregate which may new sharedAggregator and reset mainAppKey.
20
20
  switch (this.featureName) {
21
- // PVE has no need for eventBuffer, and SessionTrace + Replay have their own storage mechanisms.
22
- case FEATURE_NAMES.pageViewEvent:
21
+ // SessionTrace + Replay have their own storage mechanisms.
23
22
  case FEATURE_NAMES.sessionTrace:
24
23
  case FEATURE_NAMES.sessionReplay:
25
24
  break
@@ -28,6 +27,9 @@ export class AggregateBase extends FeatureBase {
28
27
  case FEATURE_NAMES.metrics:
29
28
  this.events = agentRef.sharedAggregator
30
29
  break
30
+ /** All other features get EventBuffer in the ESM by default. Note: PVE is included here, but event buffer will always be empty so future harvests will still not happen by interval or EOL.
31
+ This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
32
+ Its easier to just keep an empty event buffer in place. */
31
33
  default:
32
34
  this.events = new EventStoreManager(agentRef.mainAppKey, 1)
33
35
  break
@@ -71,18 +73,18 @@ export class AggregateBase extends FeatureBase {
71
73
  /**
72
74
  * Return harvest payload. A "serializer" function can be defined on a derived class to format the payload.
73
75
  * @param {Boolean} shouldRetryOnFail - harvester flag to backup payload for retry later if harvest request fails; this should be moved to harvester logic
74
- * @param {object|undefined} target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
76
+ * @param {object|undefined} opts.target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
75
77
  * @returns {Array} Final payload tagged with their targeting browser app. The value of `payload` can be undefined if there are no pending events for an app. This should be a minimum length of 1.
76
78
  */
77
- makeHarvestPayload (shouldRetryOnFail = false, target) {
78
- if (this.events.isEmpty(this.harvestOpts, target)) return
79
+ makeHarvestPayload (shouldRetryOnFail = false, opts = {}) {
80
+ if (this.events.isEmpty(this.harvestOpts, opts.target)) return
79
81
  // Other conditions and things to do when preparing harvest that is required.
80
- if (this.preHarvestChecks && !this.preHarvestChecks()) return
82
+ if (this.preHarvestChecks && !this.preHarvestChecks(opts)) return
81
83
 
82
- if (shouldRetryOnFail) this.events.save(this.harvestOpts, target)
83
- const returnedDataArr = this.events.get(this.harvestOpts, target)
84
+ if (shouldRetryOnFail) this.events.save(this.harvestOpts, opts.target)
85
+ const returnedDataArr = this.events.get(this.harvestOpts, opts.target)
84
86
  if (!returnedDataArr.length) throw new Error('Unexpected problem encountered. There should be at least one app for harvest!')
85
- this.events.clear(this.harvestOpts, target)
87
+ this.events.clear(this.harvestOpts, opts.target)
86
88
 
87
89
  return returnedDataArr.map(({ targetApp, data }) => {
88
90
  // A serializer or formatter assists in creating the payload `body` from stored events on harvest when defined by derived feature class.