@newrelic/browser-agent 1.253.0 → 1.254.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +1 -1
  3. package/dist/cjs/cdn/polyfills.js +2 -1
  4. package/dist/cjs/common/config/state/runtime.js +4 -1
  5. package/dist/cjs/common/constants/env.cdn.js +1 -1
  6. package/dist/cjs/common/constants/env.npm.js +1 -1
  7. package/dist/cjs/common/drain/drain.js +41 -27
  8. package/dist/cjs/common/event-emitter/contextual-ee.js +24 -22
  9. package/dist/cjs/common/harvest/harvest.js +5 -1
  10. package/dist/cjs/common/timing/time-keeper.js +94 -0
  11. package/dist/cjs/common/util/feature-flags.js +14 -31
  12. package/dist/cjs/common/wrap/wrap-events.js +2 -2
  13. package/dist/cjs/common/wrap/wrap-fetch.js +1 -2
  14. package/dist/cjs/common/wrap/wrap-function.js +7 -5
  15. package/dist/cjs/common/wrap/wrap-promise.js +1 -2
  16. package/dist/cjs/features/ajax/aggregate/index.js +7 -13
  17. package/dist/cjs/features/jserrors/aggregate/index.js +25 -24
  18. package/dist/cjs/features/metrics/aggregate/index.js +25 -24
  19. package/dist/cjs/features/page_action/aggregate/index.js +6 -4
  20. package/dist/cjs/features/page_view_event/aggregate/index.js +22 -2
  21. package/dist/cjs/features/page_view_timing/aggregate/index.js +15 -16
  22. package/dist/cjs/features/session_replay/aggregate/index.js +12 -4
  23. package/dist/cjs/features/session_trace/aggregate/index.js +11 -8
  24. package/dist/cjs/features/soft_navigations/aggregate/index.js +17 -12
  25. package/dist/cjs/features/spa/aggregate/index.js +19 -14
  26. package/dist/cjs/features/utils/aggregate-base.js +18 -5
  27. package/dist/cjs/features/utils/feature-base.js +2 -0
  28. package/dist/cjs/features/utils/instrument-base.js +1 -0
  29. package/dist/cjs/loaders/agent-base.js +2 -7
  30. package/dist/cjs/loaders/agent.js +4 -4
  31. package/dist/cjs/loaders/api/api.js +1 -1
  32. package/dist/cjs/loaders/configure/configure.js +1 -1
  33. package/dist/cjs/loaders/configure/nonce.cdn.js +13 -0
  34. package/dist/cjs/loaders/configure/nonce.js +2 -13
  35. package/dist/cjs/loaders/configure/public-path.cdn.js +16 -0
  36. package/dist/cjs/loaders/configure/public-path.js +2 -8
  37. package/dist/esm/cdn/polyfills.js +2 -1
  38. package/dist/esm/common/config/state/runtime.js +4 -1
  39. package/dist/esm/common/constants/env.cdn.js +1 -1
  40. package/dist/esm/common/constants/env.npm.js +1 -1
  41. package/dist/esm/common/drain/drain.js +40 -27
  42. package/dist/esm/common/event-emitter/contextual-ee.js +24 -22
  43. package/dist/esm/common/harvest/harvest.js +5 -1
  44. package/dist/esm/common/timing/time-keeper.js +88 -0
  45. package/dist/esm/common/util/feature-flags.js +14 -31
  46. package/dist/esm/common/wrap/wrap-events.js +3 -3
  47. package/dist/esm/common/wrap/wrap-fetch.js +2 -3
  48. package/dist/esm/common/wrap/wrap-function.js +5 -4
  49. package/dist/esm/common/wrap/wrap-promise.js +2 -3
  50. package/dist/esm/features/ajax/aggregate/index.js +7 -13
  51. package/dist/esm/features/jserrors/aggregate/index.js +25 -24
  52. package/dist/esm/features/metrics/aggregate/index.js +25 -24
  53. package/dist/esm/features/page_action/aggregate/index.js +6 -4
  54. package/dist/esm/features/page_view_event/aggregate/index.js +22 -2
  55. package/dist/esm/features/page_view_timing/aggregate/index.js +15 -16
  56. package/dist/esm/features/session_replay/aggregate/index.js +12 -4
  57. package/dist/esm/features/session_trace/aggregate/index.js +11 -8
  58. package/dist/esm/features/soft_navigations/aggregate/index.js +17 -12
  59. package/dist/esm/features/spa/aggregate/index.js +19 -14
  60. package/dist/esm/features/utils/aggregate-base.js +18 -5
  61. package/dist/esm/features/utils/feature-base.js +2 -0
  62. package/dist/esm/features/utils/instrument-base.js +1 -0
  63. package/dist/esm/loaders/agent-base.js +2 -7
  64. package/dist/esm/loaders/agent.js +4 -4
  65. package/dist/esm/loaders/api/api.js +1 -1
  66. package/dist/esm/loaders/configure/configure.js +1 -1
  67. package/dist/esm/loaders/configure/nonce.cdn.js +11 -0
  68. package/dist/esm/loaders/configure/nonce.js +1 -11
  69. package/dist/esm/loaders/configure/public-path.cdn.js +9 -0
  70. package/dist/esm/loaders/configure/public-path.js +2 -8
  71. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  72. package/dist/types/common/drain/drain.d.ts +6 -0
  73. package/dist/types/common/drain/drain.d.ts.map +1 -1
  74. package/dist/types/common/event-emitter/contextual-ee.d.ts +4 -3
  75. package/dist/types/common/event-emitter/contextual-ee.d.ts.map +1 -1
  76. package/dist/types/common/event-emitter/event-context.d.ts.map +1 -0
  77. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  78. package/dist/types/common/timing/time-keeper.d.ts +31 -0
  79. package/dist/types/common/timing/time-keeper.d.ts.map +1 -0
  80. package/dist/types/common/util/feature-flags.d.ts +11 -2
  81. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  82. package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
  83. package/dist/types/common/wrap/wrap-function.d.ts +1 -0
  84. package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
  85. package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
  86. package/dist/types/features/ajax/aggregate/index.d.ts +5 -5
  87. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  88. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  89. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  90. package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
  91. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  92. package/dist/types/features/page_view_timing/aggregate/index.d.ts +0 -2
  93. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  94. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  95. package/dist/types/features/soft_navigations/aggregate/index.d.ts +0 -2
  96. package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
  97. package/dist/types/features/spa/aggregate/index.d.ts +2 -0
  98. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  99. package/dist/types/features/utils/aggregate-base.d.ts +2 -2
  100. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  101. package/dist/types/features/utils/feature-base.d.ts +1 -0
  102. package/dist/types/features/utils/feature-base.d.ts.map +1 -1
  103. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  104. package/dist/types/loaders/agent-base.d.ts +2 -2
  105. package/dist/types/loaders/agent-base.d.ts.map +1 -1
  106. package/dist/types/loaders/configure/public-path.d.ts +1 -1
  107. package/dist/types/loaders/configure/public-path.d.ts.map +1 -1
  108. package/package.json +1 -1
  109. package/src/cdn/polyfills.js +1 -0
  110. package/src/common/config/state/runtime.js +4 -1
  111. package/src/common/drain/drain.js +41 -28
  112. package/src/common/event-emitter/contextual-ee.js +29 -31
  113. package/src/common/harvest/harvest.js +4 -1
  114. package/src/common/timing/time-keeper.js +96 -0
  115. package/src/common/util/feature-flags.js +13 -31
  116. package/src/common/wrap/wrap-events.js +3 -3
  117. package/src/common/wrap/wrap-fetch.js +2 -3
  118. package/src/common/wrap/wrap-function.js +6 -4
  119. package/src/common/wrap/wrap-promise.js +2 -3
  120. package/src/features/ajax/aggregate/index.js +8 -16
  121. package/src/features/jserrors/aggregate/index.js +12 -14
  122. package/src/features/metrics/aggregate/index.js +18 -17
  123. package/src/features/page_action/aggregate/index.js +6 -5
  124. package/src/features/page_view_event/aggregate/index.js +18 -2
  125. package/src/features/page_view_timing/aggregate/index.js +15 -15
  126. package/src/features/session_replay/aggregate/index.js +10 -4
  127. package/src/features/session_trace/aggregate/index.js +2 -2
  128. package/src/features/soft_navigations/aggregate/index.js +14 -12
  129. package/src/features/spa/aggregate/index.js +15 -13
  130. package/src/features/utils/aggregate-base.js +16 -8
  131. package/src/features/utils/feature-base.js +3 -0
  132. package/src/features/utils/instrument-base.js +1 -0
  133. package/src/loaders/agent-base.js +2 -7
  134. package/src/loaders/agent.js +2 -2
  135. package/src/loaders/api/api.js +1 -1
  136. package/src/loaders/configure/nonce.cdn.js +12 -0
  137. package/src/loaders/configure/nonce.js +1 -12
  138. package/src/loaders/configure/public-path.cdn.js +9 -0
  139. package/src/loaders/configure/public-path.js +2 -8
  140. package/dist/cjs/common/context/observation-context-manager.js +0 -56
  141. package/dist/cjs/loaders/configure/nonce.npm.js +0 -2
  142. package/dist/cjs/loaders/configure/public-path.npm.js +0 -10
  143. package/dist/esm/common/context/observation-context-manager.js +0 -49
  144. package/dist/esm/loaders/configure/nonce.npm.js +0 -1
  145. package/dist/esm/loaders/configure/public-path.npm.js +0 -3
  146. package/dist/types/common/context/event-context.d.ts.map +0 -1
  147. package/dist/types/common/context/observation-context-manager.d.ts +0 -28
  148. package/dist/types/common/context/observation-context-manager.d.ts.map +0 -1
  149. package/dist/types/loaders/configure/nonce.npm.d.ts +0 -1
  150. package/dist/types/loaders/configure/nonce.npm.d.ts.map +0 -1
  151. package/dist/types/loaders/configure/public-path.npm.d.ts +0 -2
  152. package/dist/types/loaders/configure/public-path.npm.d.ts.map +0 -1
  153. package/src/common/context/observation-context-manager.js +0 -55
  154. package/src/loaders/configure/nonce.npm.js +0 -1
  155. package/src/loaders/configure/public-path.npm.js +0 -3
  156. /package/dist/cjs/common/{context → event-emitter}/event-context.js +0 -0
  157. /package/dist/esm/common/{context → event-emitter}/event-context.js +0 -0
  158. /package/dist/types/common/{context → event-emitter}/event-context.d.ts +0 -0
  159. /package/src/common/{context → event-emitter}/event-context.js +0 -0
@@ -35,15 +35,6 @@ export class Aggregate extends AggregateBase {
35
35
  this.timingsSent = []
36
36
  this.curSessEndRecorded = false
37
37
 
38
- firstPaint.subscribe(this.#handleVitalMetric)
39
- firstContentfulPaint.subscribe(this.#handleVitalMetric)
40
- firstInputDelay.subscribe(this.#handleVitalMetric)
41
- largestContentfulPaint.subscribe(this.#handleVitalMetric)
42
- interactionToNextPaint.subscribe(this.#handleVitalMetric)
43
- timeToFirstByte.subscribe(({ entries }) => {
44
- this.addTiming('load', Math.round(entries[0].loadEventEnd))
45
- })
46
-
47
38
  if (getConfigurationValue(this.agentIdentifier, 'page_view_timing.long_task') === true) longTask.subscribe(this.#handleVitalMetric)
48
39
 
49
40
  /* It's important that CWV api, like "onLCP", is called before this scheduler is initialized. The reason is because they listen to the same
@@ -54,16 +45,25 @@ export class Aggregate extends AggregateBase {
54
45
 
55
46
  const initialHarvestSeconds = getConfigurationValue(this.agentIdentifier, 'page_view_timing.initialHarvestSeconds') || 10
56
47
  const harvestTimeSeconds = getConfigurationValue(this.agentIdentifier, 'page_view_timing.harvestTimeSeconds') || 30
57
- // send initial data sooner, then start regular
58
- this.ee.on(`drain-${this.featureName}`, () => {
59
- this.scheduler = new HarvestScheduler('events', {
48
+
49
+ this.waitForFlags(([])).then(() => {
50
+ firstPaint.subscribe(this.#handleVitalMetric)
51
+ firstContentfulPaint.subscribe(this.#handleVitalMetric)
52
+ firstInputDelay.subscribe(this.#handleVitalMetric)
53
+ largestContentfulPaint.subscribe(this.#handleVitalMetric)
54
+ interactionToNextPaint.subscribe(this.#handleVitalMetric)
55
+ timeToFirstByte.subscribe(({ entries }) => {
56
+ this.addTiming('load', Math.round(entries[0].loadEventEnd))
57
+ })
58
+
59
+ const scheduler = new HarvestScheduler('events', {
60
60
  onFinished: (...args) => this.onHarvestFinished(...args),
61
61
  getPayload: (...args) => this.prepareHarvest(...args)
62
62
  }, this)
63
- this.scheduler.startTimer(harvestTimeSeconds, initialHarvestSeconds)
64
- })
63
+ scheduler.startTimer(harvestTimeSeconds, initialHarvestSeconds)
65
64
 
66
- this.drain()
65
+ this.drain()
66
+ })
67
67
  }
68
68
 
69
69
  /**
@@ -27,6 +27,7 @@ import { now } from '../../../common/timing/now'
27
27
  import { MODE, SESSION_EVENTS, SESSION_EVENT_TYPES } from '../../../common/session/constants'
28
28
  import { stringify } from '../../../common/util/stringify'
29
29
  import { stylesheetEvaluator } from '../shared/stylesheet-evaluator'
30
+ import { deregisterDrain } from '../../../common/drain/drain'
30
31
 
31
32
  export class Aggregate extends AggregateBase {
32
33
  static featureName = FEATURE_NAME
@@ -116,11 +117,15 @@ export class Aggregate extends AggregateBase {
116
117
 
117
118
  this.waitForFlags(['sr']).then(([flagOn]) => {
118
119
  this.entitled = flagOn
119
- if (!this.entitled && this.recorder?.recording) {
120
- this.abort(ABORT_REASONS.ENTITLEMENTS)
121
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/EnabledNotEntitled/Detected'], undefined, FEATURE_NAMES.metrics, this.ee)
120
+ if (!this.entitled) {
121
+ deregisterDrain(this.agentIdentifier, this.featureName)
122
+ if (this.recorder?.recording) {
123
+ this.abort(ABORT_REASONS.ENTITLEMENTS)
124
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/EnabledNotEntitled/Detected'], undefined, FEATURE_NAMES.metrics, this.ee)
125
+ }
122
126
  return
123
127
  }
128
+ this.drain()
124
129
  this.initializeRecording(
125
130
  (Math.random() * 100) < error_sampling_rate,
126
131
  (Math.random() * 100) < sampling_rate
@@ -141,7 +146,6 @@ export class Aggregate extends AggregateBase {
141
146
 
142
147
  handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/SamplingRate/Value', sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee)
143
148
  handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/ErrorSamplingRate/Value', error_sampling_rate], undefined, FEATURE_NAMES.metrics, this.ee)
144
- this.drain()
145
149
  }
146
150
 
147
151
  switchToFull () {
@@ -304,6 +308,7 @@ export class Aggregate extends AggregateBase {
304
308
  const firstTimestamp = firstEventTimestamp || recorderEvents.cycleTimestamp // from rrweb node || from when the harvest cycle started
305
309
  const lastTimestamp = lastEventTimestamp || agentOffset + relativeNow
306
310
 
311
+ const agentMetadata = agentRuntime.appMetadata?.agents?.[0] || {}
307
312
  return {
308
313
  qs: {
309
314
  browser_monitoring_key: info.licenseKey,
@@ -314,6 +319,7 @@ export class Aggregate extends AggregateBase {
314
319
  // this section of attributes must be controllable and stay below the query param padding limit -- see QUERY_PARAM_PADDING
315
320
  // if not, data could be lost to truncation at time of sending, potentially breaking parsing / API behavior in NR1
316
321
  ...(!!this.gzipper && !!this.u8 && { content_encoding: 'gzip' }),
322
+ ...(agentMetadata.entityGuid && { entityGuid: agentMetadata.entityGuid }),
317
323
  'replay.firstTimestamp': firstTimestamp,
318
324
  'replay.firstTimestampOffset': firstTimestamp - agentOffset,
319
325
  'replay.lastTimestamp': lastTimestamp,
@@ -109,7 +109,7 @@ export class Aggregate extends AggregateBase {
109
109
  if (!sessionEntity) {
110
110
  // Since session manager isn't around, do the old Trace behavior of waiting for RUM response to decide feature activation.
111
111
  this.isStandalone = true
112
- registerHandler('rumresp-stn', (on) => controlTraceOp(on), this.featureName, this.ee)
112
+ this.waitForFlags((['stn'])).then(([on]) => controlTraceOp(on), this.featureName, this.ee)
113
113
  } else {
114
114
  registerHandler('errorAgg', () => {
115
115
  seenAnError = true
@@ -151,7 +151,7 @@ export class Aggregate extends AggregateBase {
151
151
  if (replayMode === MODE.OFF) this.isStandalone = true // without SR, Traces are still subject to old harvest limits
152
152
 
153
153
  let startingMode
154
- if (traceOn === true) { // CASE: both trace (entitlement+sampling) & replay (entitlement) flags are true from RUM
154
+ if (traceOn) { // CASE: both trace (entitlement+sampling) & replay (entitlement) flags are true from RUM
155
155
  startingMode = MODE.FULL // always full capture regardless of replay sampling decisions
156
156
  } else { // CASE: trace flag is off, BUT it must still run if replay is on (possibly)
157
157
  // At this point, it's possible that 1 or more exception was thrown, in which case just start in full if Replay originally started in ERROR mode.
@@ -1,4 +1,5 @@
1
1
  import { getConfigurationValue } from '../../../common/config/config'
2
+ import { deregisterDrain } from '../../../common/drain/drain'
2
3
  import { handle } from '../../../common/event-emitter/handle'
3
4
  import { registerHandler } from '../../../common/event-emitter/register-handler'
4
5
  import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
@@ -22,13 +23,6 @@ export class Aggregate extends AggregateBase {
22
23
  this.interactionsAwaitingRetry = []
23
24
  this.domObserver = domObserver
24
25
 
25
- this.scheduler = new HarvestScheduler('events', {
26
- onFinished: this.onHarvestFinished.bind(this),
27
- retryDelay: harvestTimeSeconds,
28
- onUnload: () => this.interactionInProgress?.done() // return any held ajax or jserr events so they can be sent with EoL harvest
29
- }, { agentIdentifier, ee: this.ee })
30
- this.scheduler.harvest.on('events', this.onHarvestStarted.bind(this))
31
-
32
26
  this.initialPageLoadInteraction = new InitialPageLoadInteraction(agentIdentifier)
33
27
  timeToFirstByte.subscribe(({ entries }) => {
34
28
  const loadEventTime = entries[0].loadEventEnd
@@ -45,8 +39,19 @@ export class Aggregate extends AggregateBase {
45
39
 
46
40
  this.blocked = false
47
41
  this.waitForFlags(['spa']).then(([spaOn]) => {
48
- if (spaOn) this.scheduler.startTimer(harvestTimeSeconds, 0)
49
- else this.blocked = true // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
42
+ if (spaOn) {
43
+ this.drain()
44
+ const scheduler = new HarvestScheduler('events', {
45
+ onFinished: this.onHarvestFinished.bind(this),
46
+ retryDelay: harvestTimeSeconds,
47
+ onUnload: () => this.interactionInProgress?.done() // return any held ajax or jserr events so they can be sent with EoL harvest
48
+ }, { agentIdentifier, ee: this.ee })
49
+ scheduler.harvest.on('events', this.onHarvestStarted.bind(this))
50
+ scheduler.startTimer(harvestTimeSeconds, 0)
51
+ } else {
52
+ this.blocked = true // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
53
+ deregisterDrain(this.agentIdentifier, this.featureName)
54
+ }
50
55
  })
51
56
 
52
57
  // By default, a complete UI driven interaction requires event -> URL change -> DOM mod in that exact order.
@@ -61,13 +66,10 @@ export class Aggregate extends AggregateBase {
61
66
 
62
67
  registerHandler('ajax', this.#handleAjaxEvent.bind(this), this.featureName, this.ee)
63
68
  registerHandler('jserror', this.#handleJserror.bind(this), this.featureName, this.ee)
64
-
65
- this.drain()
66
69
  }
67
70
 
68
71
  onHarvestStarted (options) {
69
72
  if (this.interactionsToHarvest.length === 0 || this.blocked) return
70
-
71
73
  // The payload depacker takes the first ixn of a payload (if there are multiple ixns) and positively offset the subsequent ixns timestamps by that amount.
72
74
  // In order to accurately portray the real start & end times of the 2nd & onward ixns, we hence need to negatively offset their start timestamps with that of the 1st ixn.
73
75
  let firstIxnStartTime = 0 // the very 1st ixn does not require any offsetting
@@ -24,6 +24,7 @@ import { bundleId } from '../../../common/ids/bundle-id'
24
24
  import { loadedAsDeferredBrowserScript } from '../../../common/constants/runtime'
25
25
  import { handle } from '../../../common/event-emitter/handle'
26
26
  import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
27
+ import { deregisterDrain } from '../../../common/drain/drain'
27
28
 
28
29
  const {
29
30
  FEATURE_NAME, INTERACTION_EVENTS, MAX_TIMER_BUDGET, FN_START, FN_END, CB_START, INTERACTION_API, REMAINING,
@@ -54,6 +55,7 @@ export class Aggregate extends AggregateBase {
54
55
  disableSpaFix: (getConfigurationValue(agentIdentifier, 'feature_flags') || []).indexOf('disable-spa-fix') > -1
55
56
  }
56
57
 
58
+ let scheduler
57
59
  this.serializer = new Serializer(this)
58
60
 
59
61
  const { state, serializer } = this
@@ -70,12 +72,6 @@ export class Aggregate extends AggregateBase {
70
72
  const xhrEE = baseEE.get('xhr')
71
73
  const tracerEE = baseEE.get('tracer')
72
74
 
73
- const scheduler = new HarvestScheduler('events', {
74
- onFinished: onHarvestFinished,
75
- retryDelay: state.harvestTimeSeconds
76
- }, { agentIdentifier, ee: baseEE })
77
- scheduler.harvest.on('events', onHarvestStarted)
78
-
79
75
  // childTime is used when calculating exclusive time for a cb duration.
80
76
  //
81
77
  // Exclusive time will be different than the total time for either callbacks
@@ -108,11 +104,19 @@ export class Aggregate extends AggregateBase {
108
104
  // | click ending: | 65 | 50 | | | |
109
105
  // click fn-end | 70 | 0 | 0 | 70 | 20 |
110
106
 
111
- // if rum response determines that customer lacks entitlements for spa endpoint, block it
112
- register('block-spa', () => {
113
- blocked = true
114
- scheduler.stopTimer(true)
115
- }, this.featureName, baseEE)
107
+ this.waitForFlags((['spa'])).then(([spaFlag]) => {
108
+ if (spaFlag) {
109
+ scheduler = this.scheduler = new HarvestScheduler('events', {
110
+ onFinished: onHarvestFinished,
111
+ retryDelay: state.harvestTimeSeconds
112
+ }, { agentIdentifier, ee: baseEE })
113
+ this.scheduler.harvest.on('events', onHarvestStarted)
114
+ this.drain()
115
+ } else {
116
+ this.blocked = true
117
+ deregisterDrain(this.agentIdentifier, this.featureName)
118
+ }
119
+ })
116
120
 
117
121
  if (!isEnabled()) return
118
122
 
@@ -740,7 +744,5 @@ export class Aggregate extends AggregateBase {
740
744
  var enabled = getConfigurationValue(agentIdentifier, 'spa.enabled')
741
745
  return enabled !== false
742
746
  }
743
-
744
- this.drain()
745
747
  }
746
748
  }
@@ -1,9 +1,9 @@
1
- import { registerHandler } from '../../common/event-emitter/register-handler'
2
1
  import { FeatureBase } from './feature-base'
3
2
  import { getInfo, isConfigured, getRuntime } from '../../common/config/config'
4
3
  import { configure } from '../../loaders/configure/configure'
5
4
  import { gosCDN } from '../../common/window/nreum'
6
5
  import { drain } from '../../common/drain/drain'
6
+ import { activatedFeatures } from '../../common/util/feature-flags'
7
7
 
8
8
  export class AggregateBase extends FeatureBase {
9
9
  constructor (...args) {
@@ -14,16 +14,24 @@ export class AggregateBase extends FeatureBase {
14
14
  /**
15
15
  * New handler for waiting for multiple flags. Useful when expecting multiple flags simultaneously (ex. stn vs sr)
16
16
  * @param {string[]} flagNames
17
- * @returns
17
+ * @returns {Promise}
18
18
  */
19
19
  waitForFlags (flagNames = []) {
20
- return Promise.all(
21
- flagNames.map(fName =>
22
- new Promise((resolve) => {
23
- registerHandler(`rumresp-${fName}`, isOn => resolve(isOn), this.featureName, this.ee)
20
+ return new Promise((resolve, reject) => {
21
+ if (activatedFeatures[this.agentIdentifier]) {
22
+ resolve(buildOutput(activatedFeatures[this.agentIdentifier]))
23
+ } else {
24
+ this.ee.on('rumresp', (resp = {}) => {
25
+ resolve(buildOutput(resp))
24
26
  })
25
- )
26
- )
27
+ }
28
+ function buildOutput (ref) {
29
+ return flagNames.map(flag => {
30
+ if (!ref[flag]) return 0
31
+ return ref[flag]
32
+ })
33
+ }
34
+ })
27
35
  }
28
36
 
29
37
  drain () {
@@ -1,4 +1,5 @@
1
1
  import { ee } from '../../common/event-emitter/contextual-ee'
2
+ import { TimeKeeper } from '../../common/timing/time-keeper'
2
3
 
3
4
  export class FeatureBase {
4
5
  constructor (agentIdentifier, aggregator, featureName) {
@@ -16,5 +17,7 @@ export class FeatureBase {
16
17
  * @type {boolean}
17
18
  */
18
19
  this.blocked = false
20
+
21
+ this.timeKeeper = TimeKeeper.getTimeKeeperByAgentIdentifier(this.agentIdentifier)
19
22
  }
20
23
  }
@@ -111,6 +111,7 @@ export class InstrumentBase extends FeatureBase {
111
111
  // not supported yet but nice to do: "abort" this agent's EE for this feature specifically
112
112
  drain(this.agentIdentifier, this.featureName, true)
113
113
  loadedSuccessfully(false)
114
+ if (this.ee) this.ee.abort()
114
115
  }
115
116
  }
116
117
 
@@ -2,9 +2,8 @@
2
2
 
3
3
  import { warn } from '../common/util/console'
4
4
  import { SR_EVENT_EMITTER_TYPES } from '../features/session_replay/constants'
5
- import { ObservationContextManager } from '../common/context/observation-context-manager'
6
5
  import { generateRandomHexString } from '../common/ids/unique-id'
7
- import { ee } from '../common/event-emitter/contextual-ee'
6
+ import { TimeKeeper } from '../common/timing/time-keeper'
8
7
 
9
8
  /**
10
9
  * @typedef {import('./api/interaction-types').InteractionInstance} InteractionInstance
@@ -12,14 +11,10 @@ import { ee } from '../common/event-emitter/contextual-ee'
12
11
 
13
12
  export class AgentBase {
14
13
  agentIdentifier
15
- observationContext = new ObservationContextManager()
14
+ timeKeeper = new TimeKeeper(this)
16
15
 
17
16
  constructor (agentIdentifier = generateRandomHexString(16)) {
18
17
  this.agentIdentifier = agentIdentifier
19
-
20
- // Assign the observation context to the event emitter, so it knows how to create observation contexts
21
- const eventEmitter = ee.get(agentIdentifier)
22
- eventEmitter.observationContext = this.observationContext
23
18
  }
24
19
 
25
20
  /**
@@ -85,8 +85,8 @@ export class Agent extends AgentBase {
85
85
  delete newrelic.initializedAgents[this.agentIdentifier]?.features // GC mem used internally by features
86
86
  delete this.sharedAggregator
87
87
  // Keep the initialized agent object with its configs for troubleshooting purposes.
88
- newrelic.ee?.abort() // set flag and clear global backlog
89
- delete newrelic.ee?.get(this.agentIdentifier) // clear this agent's own backlog too
88
+ const thisEE = newrelic.ee.get(this.agentIdentifier)
89
+ thisEE.abort() // set flag and clear backlog
90
90
  return false
91
91
  }
92
92
  }
@@ -198,7 +198,7 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
198
198
  drain(agentIdentifier, 'api')
199
199
  }).catch(() => {
200
200
  warn('Downloading runtime APIs failed...')
201
- drain(agentIdentifier, 'api', true)
201
+ instanceEE.abort()
202
202
  })
203
203
  }
204
204
 
@@ -0,0 +1,12 @@
1
+ /* global __webpack_require__ */
2
+
3
+ __webpack_require__.nc = (() => {
4
+ try {
5
+ return document?.currentScript?.nonce
6
+ } catch (ex) {
7
+ // Swallow error and proceed like nonce is not defined
8
+ // This will happen when the agent is loaded in a worker scope
9
+ }
10
+
11
+ return ''
12
+ })()
@@ -1,12 +1 @@
1
- /* global __webpack_require__ */
2
-
3
- __webpack_require__.nc = (() => {
4
- try {
5
- return document?.currentScript?.nonce
6
- } catch (ex) {
7
- // Swallow error and proceed like nonce is not defined
8
- // This will happen when the agent is loaded in a worker scope
9
- }
10
-
11
- return ''
12
- })()
1
+ // We don't support setting automating the nonce attribute in the npm package
@@ -0,0 +1,9 @@
1
+ // Set the default CDN or remote for fetching the assets; NPM shouldn't change this var.
2
+
3
+ export const redefinePublicPath = (urlString) => {
4
+ const isOrigin = urlString.startsWith('http')
5
+ // Input is not expected to end in a slash, but webpack concats as-is, so one is inserted.
6
+ urlString += '/'
7
+ // If there's no existing HTTP scheme, the secure protocol is prepended by default.
8
+ __webpack_public_path__ = isOrigin ? urlString : 'https://' + urlString // eslint-disable-line
9
+ }
@@ -1,9 +1,3 @@
1
- // Set the default CDN or remote for fetching the assets; NPM shouldn't change this var.
2
-
3
- export const redefinePublicPath = (urlString) => {
4
- const isOrigin = urlString.startsWith('http')
5
- // Input is not expected to end in a slash, but webpack concats as-is, so one is inserted.
6
- urlString += '/'
7
- // If there's no existing HTTP scheme, the secure protocol is prepended by default.
8
- __webpack_public_path__ = isOrigin ? urlString : 'https://' + urlString // eslint-disable-line
1
+ export const redefinePublicPath = () => {
2
+ // We don't support setting public path in webpack via NPM build.
9
3
  }
@@ -1,56 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.ObservationContextManager = void 0;
7
- var _nreum = require("../window/nreum");
8
- var _bundleId = require("../ids/bundle-id");
9
- var _eventContext = require("./event-context");
10
- class ObservationContextManager {
11
- // These IDs are provided for backwards compatibility until the agent is fully updated
12
- // use the observation context class.
13
-
14
- static contextId = "nr@context:".concat(_bundleId.bundleId);
15
- static contextOriginalId = "nr@original:".concat(_bundleId.bundleId);
16
- static contextWrappedId = "nr@wrapped:".concat(ObservationContextManager.contextId);
17
- static getObservationContextByAgentIdentifier(agentIdentifier) {
18
- const nr = (0, _nreum.gosNREUM)();
19
- return Object.keys(nr?.initializedAgents || {}).indexOf(agentIdentifier) > -1 ? nr.initializedAgents[agentIdentifier].observationContext : undefined;
20
- }
21
-
22
- /**
23
- * @type {WeakMap<WeakKey, {[key: string]: unknown}>}
24
- */
25
- #observationContext = new WeakMap();
26
-
27
- /**
28
- * Returns the observation context tied to the supplied construct. If there has been
29
- * no observation construct created, an empty object is created and stored as the current
30
- * context.
31
- * @param key {unknown} The construct being observed such as an XHR instance
32
- * @return {EventContext} An object of key:value pairs to track as
33
- * part of the observation
34
- */
35
- getCreateContext(key) {
36
- if (!this.#observationContext.has(key)) {
37
- this.#observationContext.set(key, new _eventContext.EventContext());
38
- }
39
- return this.#observationContext.get(key);
40
- }
41
-
42
- /**
43
- * Set the observation context for an observed construct. If values of the context
44
- * need to be updated, they should be done so directly on the context. This function
45
- * is only for the setting of a whole context.
46
- * @param key {unknown} The construct being observed such as an XHR instance
47
- * @param value {EventContext} An object of key:value pairs to track as
48
- * part of the observation
49
- * @return {EventContext} The updated observation context
50
- */
51
- setContext(key, value) {
52
- this.#observationContext.set(key, value);
53
- return this.#observationContext.get(key);
54
- }
55
- }
56
- exports.ObservationContextManager = ObservationContextManager;
@@ -1,2 +0,0 @@
1
- // We don't support setting automating the nonce attribute in the npm package
2
- "use strict";
@@ -1,10 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.redefinePublicPath = void 0;
7
- const redefinePublicPath = () => {
8
- // We don't support setting public path in webpack via NPM build.
9
- };
10
- exports.redefinePublicPath = redefinePublicPath;
@@ -1,49 +0,0 @@
1
- import { gosNREUM } from '../window/nreum';
2
- import { bundleId } from '../ids/bundle-id';
3
- import { EventContext } from './event-context';
4
- export class ObservationContextManager {
5
- // These IDs are provided for backwards compatibility until the agent is fully updated
6
- // use the observation context class.
7
-
8
- static contextId = "nr@context:".concat(bundleId);
9
- static contextOriginalId = "nr@original:".concat(bundleId);
10
- static contextWrappedId = "nr@wrapped:".concat(ObservationContextManager.contextId);
11
- static getObservationContextByAgentIdentifier(agentIdentifier) {
12
- const nr = gosNREUM();
13
- return Object.keys(nr?.initializedAgents || {}).indexOf(agentIdentifier) > -1 ? nr.initializedAgents[agentIdentifier].observationContext : undefined;
14
- }
15
-
16
- /**
17
- * @type {WeakMap<WeakKey, {[key: string]: unknown}>}
18
- */
19
- #observationContext = new WeakMap();
20
-
21
- /**
22
- * Returns the observation context tied to the supplied construct. If there has been
23
- * no observation construct created, an empty object is created and stored as the current
24
- * context.
25
- * @param key {unknown} The construct being observed such as an XHR instance
26
- * @return {EventContext} An object of key:value pairs to track as
27
- * part of the observation
28
- */
29
- getCreateContext(key) {
30
- if (!this.#observationContext.has(key)) {
31
- this.#observationContext.set(key, new EventContext());
32
- }
33
- return this.#observationContext.get(key);
34
- }
35
-
36
- /**
37
- * Set the observation context for an observed construct. If values of the context
38
- * need to be updated, they should be done so directly on the context. This function
39
- * is only for the setting of a whole context.
40
- * @param key {unknown} The construct being observed such as an XHR instance
41
- * @param value {EventContext} An object of key:value pairs to track as
42
- * part of the observation
43
- * @return {EventContext} The updated observation context
44
- */
45
- setContext(key, value) {
46
- this.#observationContext.set(key, value);
47
- return this.#observationContext.get(key);
48
- }
49
- }
@@ -1 +0,0 @@
1
- // We don't support setting automating the nonce attribute in the npm package
@@ -1,3 +0,0 @@
1
- export const redefinePublicPath = () => {
2
- // We don't support setting public path in webpack via NPM build.
3
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-context.d.ts","sourceRoot":"","sources":["../../../../src/common/context/event-context.js"],"names":[],"mappings":"AAAA;IACE,4BAEC;IADC,eAA0B;CAE7B"}
@@ -1,28 +0,0 @@
1
- export class ObservationContextManager {
2
- static contextId: string;
3
- static contextOriginalId: string;
4
- static contextWrappedId: string;
5
- static getObservationContextByAgentIdentifier(agentIdentifier: any): any;
6
- /**
7
- * Returns the observation context tied to the supplied construct. If there has been
8
- * no observation construct created, an empty object is created and stored as the current
9
- * context.
10
- * @param key {unknown} The construct being observed such as an XHR instance
11
- * @return {EventContext} An object of key:value pairs to track as
12
- * part of the observation
13
- */
14
- getCreateContext(key: unknown): EventContext;
15
- /**
16
- * Set the observation context for an observed construct. If values of the context
17
- * need to be updated, they should be done so directly on the context. This function
18
- * is only for the setting of a whole context.
19
- * @param key {unknown} The construct being observed such as an XHR instance
20
- * @param value {EventContext} An object of key:value pairs to track as
21
- * part of the observation
22
- * @return {EventContext} The updated observation context
23
- */
24
- setContext(key: unknown, value: EventContext): EventContext;
25
- #private;
26
- }
27
- import { EventContext } from './event-context';
28
- //# sourceMappingURL=observation-context-manager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"observation-context-manager.d.ts","sourceRoot":"","sources":["../../../../src/common/context/observation-context-manager.js"],"names":[],"mappings":"AAIA;IAIE,yBAA2C;IAC3C,iCAAoD;IACpD,gCAA6E;IAE7E,yEAKC;IAOD;;;;;;;OAOG;IACH,sBAJe,OAAO,GACV,YAAY,CASvB;IAED;;;;;;;;OAQG;IACH,gBALe,OAAO,SACL,YAAY,GAEjB,YAAY,CAMvB;;CACF;6BApD4B,iBAAiB"}
@@ -1 +0,0 @@
1
- //# sourceMappingURL=nonce.npm.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"nonce.npm.d.ts","sourceRoot":"","sources":["../../../../src/loaders/configure/nonce.npm.js"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export function redefinePublicPath(): void;
2
- //# sourceMappingURL=public-path.npm.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"public-path.npm.d.ts","sourceRoot":"","sources":["../../../../src/loaders/configure/public-path.npm.js"],"names":[],"mappings":"AAAO,2CAEN"}
@@ -1,55 +0,0 @@
1
- import { gosNREUM } from '../window/nreum'
2
- import { bundleId } from '../ids/bundle-id'
3
- import { EventContext } from './event-context'
4
-
5
- export class ObservationContextManager {
6
- // These IDs are provided for backwards compatibility until the agent is fully updated
7
- // use the observation context class.
8
-
9
- static contextId = `nr@context:${bundleId}`
10
- static contextOriginalId = `nr@original:${bundleId}`
11
- static contextWrappedId = `nr@wrapped:${ObservationContextManager.contextId}`
12
-
13
- static getObservationContextByAgentIdentifier (agentIdentifier) {
14
- const nr = gosNREUM()
15
- return Object.keys(nr?.initializedAgents || {}).indexOf(agentIdentifier) > -1
16
- ? nr.initializedAgents[agentIdentifier].observationContext
17
- : undefined
18
- }
19
-
20
- /**
21
- * @type {WeakMap<WeakKey, {[key: string]: unknown}>}
22
- */
23
- #observationContext = new WeakMap()
24
-
25
- /**
26
- * Returns the observation context tied to the supplied construct. If there has been
27
- * no observation construct created, an empty object is created and stored as the current
28
- * context.
29
- * @param key {unknown} The construct being observed such as an XHR instance
30
- * @return {EventContext} An object of key:value pairs to track as
31
- * part of the observation
32
- */
33
- getCreateContext (key) {
34
- if (!this.#observationContext.has(key)) {
35
- this.#observationContext.set(key, new EventContext())
36
- }
37
-
38
- return this.#observationContext.get(key)
39
- }
40
-
41
- /**
42
- * Set the observation context for an observed construct. If values of the context
43
- * need to be updated, they should be done so directly on the context. This function
44
- * is only for the setting of a whole context.
45
- * @param key {unknown} The construct being observed such as an XHR instance
46
- * @param value {EventContext} An object of key:value pairs to track as
47
- * part of the observation
48
- * @return {EventContext} The updated observation context
49
- */
50
- setContext (key, value) {
51
- this.#observationContext.set(key, value)
52
-
53
- return this.#observationContext.get(key)
54
- }
55
- }
@@ -1 +0,0 @@
1
- // We don't support setting automating the nonce attribute in the npm package