@newrelic/browser-agent 1.321.0-rc.10 → 1.321.0-rc.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.321.0-rc.10";
20
+ const VERSION = exports.VERSION = "1.321.0-rc.12";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.321.0-rc.10";
20
+ const VERSION = exports.VERSION = "1.321.0-rc.12";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -307,21 +307,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
307
307
  }, this.featureName, this.ee);
308
308
  }
309
309
  if (!agentRef.init.feature_flags.includes('no_spv')) {
310
- (0, _registerHandler.registerHandler)('spv', evt => {
310
+ (0, _registerHandler.registerHandler)('spv', (violation, timestamp) => {
311
311
  this.addEvent({
312
312
  eventType: _events.EVENT_TYPES.SPV,
313
- timestamp: this.#toEpoch(evt.timeStamp),
314
- blockedUri: evt.blockedURI,
315
- documentUri: evt.documentURI,
316
- effectiveDirective: evt.effectiveDirective,
317
- originalPolicy: evt.originalPolicy,
318
- sourceFile: evt.sourceFile,
319
- statusCode: evt.statusCode,
320
- lineNumber: evt.lineNumber,
321
- columnNumber: evt.columnNumber,
322
- disposition: evt.disposition,
323
- sample: evt.sample,
324
- referrer: evt.referrer
313
+ timestamp: this.#toEpoch(timestamp),
314
+ ...violation
325
315
  });
326
316
  }, this.featureName, this.ee);
327
317
  }
@@ -7,6 +7,7 @@ exports.Instrument = exports.GenericEvents = void 0;
7
7
  var _runtime = require("../../../common/constants/runtime");
8
8
  var _handle = require("../../../common/event-emitter/handle");
9
9
  var _eventListenerOpts = require("../../../common/event-listener/event-listener-opts");
10
+ var _now = require("../../../common/timing/now");
10
11
  var _invoke = require("../../../common/util/invoke");
11
12
  var _addPageAction = require("../../../loaders/api/addPageAction");
12
13
  var _finished = require("../../../loaders/api/finished");
@@ -56,8 +57,26 @@ class Instrument extends _instrumentBase.InstrumentBase {
56
57
  });
57
58
  }
58
59
  if (securityPolicyViolationEnabled) {
60
+ /** ReportingObserver's `csp-violation` type isn't reliably enabled everywhere out of the box:
61
+ * - Safari only delivers it when the page sets a report-to CSP directive -- https://bugs.webkit.org/show_bug.cgi?id=320750;
62
+ * - Firefox ships it behind the `dom.reporting.enabled` pref, which defaults to false;
63
+ * So it's only used for violations that occur before the agent loaded, targeting Chromium browsers. `buffered: true` replays
64
+ * that backlog in the observer's first callback invocation, after which it's disconnected and all future violations are
65
+ * covered by securitypolicyviolation, which is reliable across all browsers. */
66
+ if (typeof _runtime.globalScope.ReportingObserver === 'function') {
67
+ const cspObserver = new _runtime.globalScope.ReportingObserver(reports => {
68
+ reports.forEach(report => {
69
+ (0, _handle.handle)('spv', [normalizeCspViolation(report), (0, _now.now)()], undefined, _features.FEATURE_NAMES.genericEvents, this.ee);
70
+ });
71
+ cspObserver.disconnect();
72
+ }, {
73
+ types: ['csp-violation'],
74
+ buffered: true
75
+ });
76
+ cspObserver.observe();
77
+ }
59
78
  _runtime.globalScope.addEventListener('securitypolicyviolation', evt => {
60
- (0, _handle.handle)('spv', [evt], undefined, _features.FEATURE_NAMES.genericEvents, this.ee);
79
+ (0, _handle.handle)('spv', [normalizeCspViolation(evt), evt.timeStamp], undefined, _features.FEATURE_NAMES.genericEvents, this.ee);
61
80
  }, (0, _eventListenerOpts.eventListenerOpts)(false, this.removeOnAbort.signal));
62
81
  }
63
82
  if (_runtime.isBrowserScope) {
@@ -122,5 +141,26 @@ class Instrument extends _instrumentBase.InstrumentBase {
122
141
  if (genericEventSourceConfigs.some(x => x)) this.importAggregator(agentRef, () => Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "generic_events-aggregate" */'../aggregate'))));else this.deregisterDrain();
123
142
  }
124
143
  }
144
+ /** `Report.body` (ReportingObserver) and `SecurityPolicyViolationEvent` (securitypolicyviolation) describe the same
145
+ * violation with differently-named/shaped fields -- collapse both into one shape so downstream code doesn't care
146
+ * which mechanism produced it. `source` is either of those: a Report (fields under `.body`, URLs as blockedURL/
147
+ * documentURL) or the event (fields at the top level, URLs as blockedURI/documentURI). Also normalizes disposition's
148
+ * "reporting" (Report body) to "report" (event) so the value is consistent regardless of source. */
125
149
  exports.Instrument = Instrument;
150
+ function normalizeCspViolation(source) {
151
+ const body = source.body ?? source;
152
+ return {
153
+ blockedUrl: body.blockedURL ?? source.blockedURI,
154
+ documentUrl: body.documentURL ?? source.documentURI,
155
+ effectiveDirective: body.effectiveDirective,
156
+ originalPolicy: body.originalPolicy,
157
+ sourceFile: body.sourceFile,
158
+ statusCode: body.statusCode,
159
+ lineNumber: body.lineNumber,
160
+ columnNumber: body.columnNumber,
161
+ disposition: body.disposition === 'reporting' ? 'report' : body.disposition,
162
+ sample: body.sample,
163
+ referrer: body.referrer
164
+ };
165
+ }
126
166
  const GenericEvents = exports.GenericEvents = Instrument;
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.321.0-rc.10";
14
+ export const VERSION = "1.321.0-rc.12";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.321.0-rc.10";
14
+ export const VERSION = "1.321.0-rc.12";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -300,21 +300,11 @@ export class Aggregate extends AggregateBase {
300
300
  }, this.featureName, this.ee);
301
301
  }
302
302
  if (!agentRef.init.feature_flags.includes('no_spv')) {
303
- registerHandler('spv', evt => {
303
+ registerHandler('spv', (violation, timestamp) => {
304
304
  this.addEvent({
305
305
  eventType: EVENT_TYPES.SPV,
306
- timestamp: this.#toEpoch(evt.timeStamp),
307
- blockedUri: evt.blockedURI,
308
- documentUri: evt.documentURI,
309
- effectiveDirective: evt.effectiveDirective,
310
- originalPolicy: evt.originalPolicy,
311
- sourceFile: evt.sourceFile,
312
- statusCode: evt.statusCode,
313
- lineNumber: evt.lineNumber,
314
- columnNumber: evt.columnNumber,
315
- disposition: evt.disposition,
316
- sample: evt.sample,
317
- referrer: evt.referrer
306
+ timestamp: this.#toEpoch(timestamp),
307
+ ...violation
318
308
  });
319
309
  }, this.featureName, this.ee);
320
310
  }
@@ -6,6 +6,7 @@
6
6
  import { globalScope, isBrowserScope } from '../../../common/constants/runtime';
7
7
  import { handle } from '../../../common/event-emitter/handle';
8
8
  import { eventListenerOpts, windowAddEventListener } from '../../../common/event-listener/event-listener-opts';
9
+ import { now } from '../../../common/timing/now';
9
10
  import { debounce } from '../../../common/util/invoke';
10
11
  import { setupAddPageActionAPI } from '../../../loaders/api/addPageAction';
11
12
  import { setupFinishedAPI } from '../../../loaders/api/finished';
@@ -51,8 +52,26 @@ export class Instrument extends InstrumentBase {
51
52
  });
52
53
  }
53
54
  if (securityPolicyViolationEnabled) {
55
+ /** ReportingObserver's `csp-violation` type isn't reliably enabled everywhere out of the box:
56
+ * - Safari only delivers it when the page sets a report-to CSP directive -- https://bugs.webkit.org/show_bug.cgi?id=320750;
57
+ * - Firefox ships it behind the `dom.reporting.enabled` pref, which defaults to false;
58
+ * So it's only used for violations that occur before the agent loaded, targeting Chromium browsers. `buffered: true` replays
59
+ * that backlog in the observer's first callback invocation, after which it's disconnected and all future violations are
60
+ * covered by securitypolicyviolation, which is reliable across all browsers. */
61
+ if (typeof globalScope.ReportingObserver === 'function') {
62
+ const cspObserver = new globalScope.ReportingObserver(reports => {
63
+ reports.forEach(report => {
64
+ handle('spv', [normalizeCspViolation(report), now()], undefined, FEATURE_NAMES.genericEvents, this.ee);
65
+ });
66
+ cspObserver.disconnect();
67
+ }, {
68
+ types: ['csp-violation'],
69
+ buffered: true
70
+ });
71
+ cspObserver.observe();
72
+ }
54
73
  globalScope.addEventListener('securitypolicyviolation', evt => {
55
- handle('spv', [evt], undefined, FEATURE_NAMES.genericEvents, this.ee);
74
+ handle('spv', [normalizeCspViolation(evt), evt.timeStamp], undefined, FEATURE_NAMES.genericEvents, this.ee);
56
75
  }, eventListenerOpts(false, this.removeOnAbort.signal));
57
76
  }
58
77
  if (isBrowserScope) {
@@ -117,4 +136,25 @@ export class Instrument extends InstrumentBase {
117
136
  if (genericEventSourceConfigs.some(x => x)) this.importAggregator(agentRef, () => import(/* webpackChunkName: "generic_events-aggregate" */'../aggregate'));else this.deregisterDrain();
118
137
  }
119
138
  }
139
+ /** `Report.body` (ReportingObserver) and `SecurityPolicyViolationEvent` (securitypolicyviolation) describe the same
140
+ * violation with differently-named/shaped fields -- collapse both into one shape so downstream code doesn't care
141
+ * which mechanism produced it. `source` is either of those: a Report (fields under `.body`, URLs as blockedURL/
142
+ * documentURL) or the event (fields at the top level, URLs as blockedURI/documentURI). Also normalizes disposition's
143
+ * "reporting" (Report body) to "report" (event) so the value is consistent regardless of source. */
144
+ function normalizeCspViolation(source) {
145
+ const body = source.body ?? source;
146
+ return {
147
+ blockedUrl: body.blockedURL ?? source.blockedURI,
148
+ documentUrl: body.documentURL ?? source.documentURI,
149
+ effectiveDirective: body.effectiveDirective,
150
+ originalPolicy: body.originalPolicy,
151
+ sourceFile: body.sourceFile,
152
+ statusCode: body.statusCode,
153
+ lineNumber: body.lineNumber,
154
+ columnNumber: body.columnNumber,
155
+ disposition: body.disposition === 'reporting' ? 'report' : body.disposition,
156
+ sample: body.sample,
157
+ referrer: body.referrer
158
+ };
159
+ }
120
160
  export const GenericEvents = Instrument;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/generic_events/aggregate/index.js"],"names":[],"mappings":"AAoBA;IACE,2BAAiC;IAGjC,2BAkSC;IAhSC,gCAAkG;IAIlG,uBAA0C;IA+R5C;;;;;;;;;;;;OAYG;IACH,eAJW,MAAM,YAAC,WACP,MAAM,YAAC,QAkCjB;IAED,6CAEC;IAED;;;MAEC;;CAsBF;8BA/X6B,4BAA4B;2BAI/B,gCAAgC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/generic_events/aggregate/index.js"],"names":[],"mappings":"AAoBA;IACE,2BAAiC;IAGjC,2BAwRC;IAtRC,gCAAkG;IAIlG,uBAA0C;IAqR5C;;;;;;;;;;;;OAYG;IACH,eAJW,MAAM,YAAC,WACP,MAAM,YAAC,QAkCjB;IAED,6CAEC;IAED;;;MAEC;;CAsBF;8BArX6B,4BAA4B;2BAI/B,gCAAgC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/generic_events/instrument/index.js"],"names":[],"mappings":"AAwBA;IACE,2BAAiC;IACjC,2BA0GC;IAnFC,+BAA0C;IAC1C,yBAGC;CAgFJ;AAED,8CAAuC;+BAzHR,6BAA6B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/generic_events/instrument/index.js"],"names":[],"mappings":"AAyBA;IACE,2BAAiC;IACjC,2BA0HC;IAnGC,+BAA0C;IAC1C,yBAGC;CAgGJ;AAuBD,8CAAuC;+BA9JR,6BAA6B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.321.0-rc.10",
3
+ "version": "1.321.0-rc.12",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -291,21 +291,11 @@ export class Aggregate extends AggregateBase {
291
291
  }, this.featureName, this.ee)
292
292
  }
293
293
  if (!agentRef.init.feature_flags.includes('no_spv')) {
294
- registerHandler('spv', (evt) => {
294
+ registerHandler('spv', (violation, timestamp) => {
295
295
  this.addEvent({
296
296
  eventType: EVENT_TYPES.SPV,
297
- timestamp: this.#toEpoch(evt.timeStamp),
298
- blockedUri: evt.blockedURI,
299
- documentUri: evt.documentURI,
300
- effectiveDirective: evt.effectiveDirective,
301
- originalPolicy: evt.originalPolicy,
302
- sourceFile: evt.sourceFile,
303
- statusCode: evt.statusCode,
304
- lineNumber: evt.lineNumber,
305
- columnNumber: evt.columnNumber,
306
- disposition: evt.disposition,
307
- sample: evt.sample,
308
- referrer: evt.referrer
297
+ timestamp: this.#toEpoch(timestamp),
298
+ ...violation
309
299
  })
310
300
  }, this.featureName, this.ee)
311
301
  }
@@ -6,6 +6,7 @@
6
6
  import { globalScope, isBrowserScope } from '../../../common/constants/runtime'
7
7
  import { handle } from '../../../common/event-emitter/handle'
8
8
  import { eventListenerOpts, windowAddEventListener } from '../../../common/event-listener/event-listener-opts'
9
+ import { now } from '../../../common/timing/now'
9
10
  import { debounce } from '../../../common/util/invoke'
10
11
  import { setupAddPageActionAPI } from '../../../loaders/api/addPageAction'
11
12
  import { setupFinishedAPI } from '../../../loaders/api/finished'
@@ -61,8 +62,24 @@ export class Instrument extends InstrumentBase {
61
62
  })
62
63
  }
63
64
  if (securityPolicyViolationEnabled) {
65
+ /** ReportingObserver's `csp-violation` type isn't reliably enabled everywhere out of the box:
66
+ * - Safari only delivers it when the page sets a report-to CSP directive -- https://bugs.webkit.org/show_bug.cgi?id=320750;
67
+ * - Firefox ships it behind the `dom.reporting.enabled` pref, which defaults to false;
68
+ * So it's only used for violations that occur before the agent loaded, targeting Chromium browsers. `buffered: true` replays
69
+ * that backlog in the observer's first callback invocation, after which it's disconnected and all future violations are
70
+ * covered by securitypolicyviolation, which is reliable across all browsers. */
71
+ if (typeof globalScope.ReportingObserver === 'function') {
72
+ const cspObserver = new globalScope.ReportingObserver((reports) => {
73
+ reports.forEach(report => {
74
+ handle('spv', [normalizeCspViolation(report), now()], undefined, FEATURE_NAMES.genericEvents, this.ee)
75
+ })
76
+ cspObserver.disconnect()
77
+ }, { types: ['csp-violation'], buffered: true })
78
+ cspObserver.observe()
79
+ }
80
+
64
81
  globalScope.addEventListener('securitypolicyviolation', (evt) => {
65
- handle('spv', [evt], undefined, FEATURE_NAMES.genericEvents, this.ee)
82
+ handle('spv', [normalizeCspViolation(evt), evt.timeStamp], undefined, FEATURE_NAMES.genericEvents, this.ee)
66
83
  }, eventListenerOpts(false, this.removeOnAbort.signal))
67
84
  }
68
85
  if (isBrowserScope) {
@@ -132,5 +149,26 @@ export class Instrument extends InstrumentBase {
132
149
  else this.deregisterDrain()
133
150
  }
134
151
  }
152
+ /** `Report.body` (ReportingObserver) and `SecurityPolicyViolationEvent` (securitypolicyviolation) describe the same
153
+ * violation with differently-named/shaped fields -- collapse both into one shape so downstream code doesn't care
154
+ * which mechanism produced it. `source` is either of those: a Report (fields under `.body`, URLs as blockedURL/
155
+ * documentURL) or the event (fields at the top level, URLs as blockedURI/documentURI). Also normalizes disposition's
156
+ * "reporting" (Report body) to "report" (event) so the value is consistent regardless of source. */
157
+ function normalizeCspViolation (source) {
158
+ const body = source.body ?? source
159
+ return {
160
+ blockedUrl: body.blockedURL ?? source.blockedURI,
161
+ documentUrl: body.documentURL ?? source.documentURI,
162
+ effectiveDirective: body.effectiveDirective,
163
+ originalPolicy: body.originalPolicy,
164
+ sourceFile: body.sourceFile,
165
+ statusCode: body.statusCode,
166
+ lineNumber: body.lineNumber,
167
+ columnNumber: body.columnNumber,
168
+ disposition: body.disposition === 'reporting' ? 'report' : body.disposition,
169
+ sample: body.sample,
170
+ referrer: body.referrer
171
+ }
172
+ }
135
173
 
136
174
  export const GenericEvents = Instrument