@newrelic/browser-agent 1.232.1 → 1.233.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 (233) hide show
  1. package/dist/cjs/cdn/polyfills.js +5 -2
  2. package/dist/cjs/common/config/state/configurable.js +15 -26
  3. package/dist/cjs/common/config/state/info.js +1 -1
  4. package/dist/cjs/common/config/state/init.js +101 -56
  5. package/dist/cjs/common/config/state/loader-config.js +1 -1
  6. package/dist/cjs/common/config/state/runtime.js +1 -5
  7. package/dist/cjs/common/constants/env.cdn.js +1 -1
  8. package/dist/cjs/common/constants/env.npm.js +1 -1
  9. package/dist/cjs/common/drain/drain.js +1 -1
  10. package/dist/cjs/common/harvest/harvest-scheduler.js +30 -10
  11. package/dist/cjs/common/harvest/harvest.js +119 -55
  12. package/dist/cjs/common/session/session-entity.js +35 -22
  13. package/dist/cjs/common/session/session-entity.test.js +73 -49
  14. package/dist/cjs/common/timer/interaction-timer.js +9 -12
  15. package/dist/cjs/common/url/protocol.test.js +0 -1
  16. package/dist/cjs/common/util/feature-flags.js +2 -1
  17. package/dist/cjs/common/util/submit-data.js +57 -18
  18. package/dist/cjs/common/wrap/wrap-fetch.js +1 -1
  19. package/dist/cjs/common/wrap/wrap-function.js +1 -1
  20. package/dist/cjs/common/wrap/wrap-promise.js +1 -1
  21. package/dist/cjs/features/ajax/aggregate/index.js +2 -2
  22. package/dist/cjs/features/jserrors/aggregate/index.js +7 -5
  23. package/dist/cjs/features/metrics/aggregate/framework-detection.js +67 -0
  24. package/dist/cjs/features/metrics/aggregate/framework-detection.test.js +137 -0
  25. package/dist/cjs/features/metrics/aggregate/index.js +7 -3
  26. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.js +14 -0
  27. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.test.js +17 -0
  28. package/dist/cjs/features/metrics/aggregate/polyfill-detection.js +53 -0
  29. package/dist/cjs/features/metrics/aggregate/polyfill-detection.test.js +165 -0
  30. package/dist/cjs/features/page_action/aggregate/index.js +2 -2
  31. package/dist/cjs/features/page_view_event/aggregate/index.js +6 -3
  32. package/dist/cjs/features/page_view_timing/aggregate/index.js +2 -2
  33. package/dist/cjs/features/session_replay/aggregate/index.js +333 -0
  34. package/dist/cjs/features/session_replay/constants.js +9 -0
  35. package/dist/cjs/features/session_replay/index.js +12 -0
  36. package/dist/cjs/features/session_replay/instrument/index.js +29 -0
  37. package/dist/cjs/features/session_trace/aggregate/index.js +163 -162
  38. package/dist/cjs/features/session_trace/constants.js +2 -9
  39. package/dist/cjs/features/session_trace/instrument/index.js +24 -66
  40. package/dist/cjs/features/spa/aggregate/index.js +2 -2
  41. package/dist/cjs/features/utils/agent-session.js +1 -2
  42. package/dist/cjs/features/utils/aggregate-base.js +64 -0
  43. package/dist/cjs/features/utils/feature-base.js +0 -31
  44. package/dist/cjs/features/utils/handler-cache.js +3 -4
  45. package/dist/cjs/features/utils/instrument-base.js +42 -10
  46. package/dist/cjs/features/utils/{lazy-loader.js → lazy-feature-loader.js} +4 -2
  47. package/dist/cjs/loaders/agent.js +1 -1
  48. package/dist/cjs/loaders/api/apiAsync.js +3 -1
  49. package/dist/cjs/loaders/configure/configure.js +3 -3
  50. package/dist/cjs/loaders/features/featureDependencies.js +0 -12
  51. package/dist/cjs/loaders/features/features.js +3 -1
  52. package/dist/cjs/loaders/micro-agent.js +6 -6
  53. package/dist/esm/cdn/polyfills.js +5 -2
  54. package/dist/esm/common/config/state/configurable.js +14 -24
  55. package/dist/esm/common/config/state/info.js +2 -2
  56. package/dist/esm/common/config/state/init.js +102 -57
  57. package/dist/esm/common/config/state/loader-config.js +2 -2
  58. package/dist/esm/common/config/state/runtime.js +2 -4
  59. package/dist/esm/common/constants/env.cdn.js +1 -1
  60. package/dist/esm/common/constants/env.npm.js +1 -1
  61. package/dist/esm/common/drain/drain.js +1 -1
  62. package/dist/esm/common/harvest/harvest-scheduler.js +30 -10
  63. package/dist/esm/common/harvest/harvest.js +121 -56
  64. package/dist/esm/common/session/session-entity.js +35 -22
  65. package/dist/esm/common/session/session-entity.test.js +73 -49
  66. package/dist/esm/common/timer/interaction-timer.js +9 -12
  67. package/dist/esm/common/url/protocol.test.js +0 -1
  68. package/dist/esm/common/util/feature-flags.js +2 -1
  69. package/dist/esm/common/util/submit-data.js +57 -18
  70. package/dist/esm/common/wrap/wrap-fetch.js +1 -1
  71. package/dist/esm/common/wrap/wrap-function.js +1 -1
  72. package/dist/esm/common/wrap/wrap-promise.js +1 -1
  73. package/dist/esm/features/ajax/aggregate/index.js +2 -2
  74. package/dist/esm/features/jserrors/aggregate/index.js +7 -5
  75. package/dist/esm/features/metrics/aggregate/framework-detection.js +61 -0
  76. package/dist/esm/features/metrics/aggregate/framework-detection.test.js +133 -0
  77. package/dist/esm/features/metrics/aggregate/index.js +7 -3
  78. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.js +8 -0
  79. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.test.js +15 -0
  80. package/dist/esm/features/metrics/aggregate/polyfill-detection.js +47 -0
  81. package/dist/esm/features/metrics/aggregate/polyfill-detection.test.js +163 -0
  82. package/dist/esm/features/page_action/aggregate/index.js +2 -2
  83. package/dist/esm/features/page_view_event/aggregate/index.js +6 -3
  84. package/dist/esm/features/page_view_timing/aggregate/index.js +2 -2
  85. package/dist/esm/features/session_replay/aggregate/index.js +327 -0
  86. package/dist/esm/features/session_replay/constants.js +2 -0
  87. package/dist/esm/features/session_replay/index.js +12 -0
  88. package/dist/esm/features/session_replay/instrument/index.js +21 -0
  89. package/dist/esm/features/session_trace/aggregate/index.js +163 -162
  90. package/dist/esm/features/session_trace/constants.js +1 -5
  91. package/dist/esm/features/session_trace/instrument/index.js +24 -66
  92. package/dist/esm/features/spa/aggregate/index.js +2 -2
  93. package/dist/esm/features/utils/agent-session.js +1 -2
  94. package/dist/esm/features/utils/aggregate-base.js +57 -0
  95. package/dist/esm/features/utils/feature-base.js +1 -32
  96. package/dist/esm/features/utils/handler-cache.js +3 -4
  97. package/dist/esm/features/utils/instrument-base.js +42 -10
  98. package/dist/esm/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
  99. package/dist/esm/loaders/agent.js +1 -1
  100. package/dist/esm/loaders/api/apiAsync.js +3 -1
  101. package/dist/esm/loaders/configure/configure.js +3 -3
  102. package/dist/esm/loaders/features/featureDependencies.js +0 -11
  103. package/dist/esm/loaders/features/features.js +3 -1
  104. package/dist/esm/loaders/micro-agent.js +6 -6
  105. package/dist/types/common/config/state/configurable.d.ts +1 -3
  106. package/dist/types/common/config/state/configurable.d.ts.map +1 -1
  107. package/dist/types/common/config/state/init.d.ts.map +1 -1
  108. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  109. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  110. package/dist/types/common/harvest/harvest.d.ts +37 -34
  111. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  112. package/dist/types/common/session/session-entity.d.ts +6 -3
  113. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  114. package/dist/types/common/timer/interaction-timer.d.ts +2 -1
  115. package/dist/types/common/timer/interaction-timer.d.ts.map +1 -1
  116. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  117. package/dist/types/common/util/submit-data.d.ts +40 -14
  118. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  119. package/dist/types/features/ajax/aggregate/index.d.ts +2 -2
  120. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  121. package/dist/types/features/jserrors/aggregate/index.d.ts +2 -2
  122. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  123. package/dist/types/features/metrics/aggregate/framework-detection.d.ts.map +1 -0
  124. package/dist/types/features/metrics/aggregate/index.d.ts +2 -2
  125. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  126. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts +6 -0
  127. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts.map +1 -0
  128. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts +7 -0
  129. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -0
  130. package/dist/types/features/page_action/aggregate/index.d.ts +2 -2
  131. package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
  132. package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -2
  133. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  134. package/dist/types/features/page_view_timing/aggregate/index.d.ts +2 -2
  135. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  136. package/dist/types/features/session_replay/aggregate/index.d.ts +96 -0
  137. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -0
  138. package/dist/types/features/session_replay/constants.d.ts +2 -0
  139. package/dist/types/features/session_replay/constants.d.ts.map +1 -0
  140. package/dist/types/features/session_replay/index.d.ts +2 -0
  141. package/dist/types/features/session_replay/index.d.ts.map +1 -0
  142. package/dist/types/features/session_replay/instrument/index.d.ts +6 -0
  143. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -0
  144. package/dist/types/features/session_trace/aggregate/index.d.ts +8 -57
  145. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  146. package/dist/types/features/session_trace/constants.d.ts +0 -3
  147. package/dist/types/features/session_trace/constants.d.ts.map +1 -1
  148. package/dist/types/features/session_trace/instrument/index.d.ts +1 -3
  149. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  150. package/dist/types/features/spa/aggregate/index.d.ts +2 -2
  151. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  152. package/dist/types/features/utils/agent-session.d.ts.map +1 -1
  153. package/dist/types/features/utils/aggregate-base.d.ts +11 -0
  154. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -0
  155. package/dist/types/features/utils/feature-base.d.ts +0 -5
  156. package/dist/types/features/utils/feature-base.d.ts.map +1 -1
  157. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  158. package/dist/types/features/utils/instrument-base.d.ts +3 -1
  159. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  160. package/dist/types/features/utils/{lazy-loader.d.ts → lazy-feature-loader.d.ts} +2 -2
  161. package/dist/types/features/utils/lazy-feature-loader.d.ts.map +1 -0
  162. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  163. package/dist/types/loaders/features/featureDependencies.d.ts +0 -1
  164. package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
  165. package/dist/types/loaders/features/features.d.ts +1 -0
  166. package/dist/types/loaders/features/features.d.ts.map +1 -1
  167. package/package.json +28 -19
  168. package/src/cdn/polyfills.js +4 -1
  169. package/src/common/config/state/configurable.js +18 -24
  170. package/src/common/config/state/info.js +2 -2
  171. package/src/common/config/state/init.js +62 -28
  172. package/src/common/config/state/loader-config.js +2 -2
  173. package/src/common/config/state/runtime.js +2 -4
  174. package/src/common/drain/drain.js +1 -1
  175. package/src/common/harvest/harvest-scheduler.js +35 -10
  176. package/src/common/harvest/harvest.js +73 -50
  177. package/src/common/session/session-entity.js +34 -23
  178. package/src/common/session/session-entity.test.js +57 -51
  179. package/src/common/timer/interaction-timer.js +9 -12
  180. package/src/common/url/protocol.test.js +0 -1
  181. package/src/common/util/feature-flags.js +2 -2
  182. package/src/common/util/submit-data.js +28 -17
  183. package/src/common/wrap/wrap-fetch.js +1 -1
  184. package/src/common/wrap/wrap-function.js +1 -1
  185. package/src/common/wrap/wrap-promise.js +1 -1
  186. package/src/features/ajax/aggregate/index.js +2 -2
  187. package/src/features/jserrors/aggregate/index.js +7 -5
  188. package/src/features/metrics/aggregate/framework-detection.js +73 -0
  189. package/src/features/metrics/aggregate/framework-detection.test.js +201 -0
  190. package/src/features/metrics/aggregate/index.js +8 -3
  191. package/src/features/metrics/aggregate/polyfill-detection.es5.js +9 -0
  192. package/src/features/metrics/aggregate/polyfill-detection.es5.test.js +16 -0
  193. package/src/features/metrics/aggregate/polyfill-detection.js +48 -0
  194. package/src/features/metrics/aggregate/polyfill-detection.test.js +163 -0
  195. package/src/features/page_action/aggregate/index.js +2 -2
  196. package/src/features/page_view_event/aggregate/index.js +5 -5
  197. package/src/features/page_view_timing/aggregate/index.js +2 -2
  198. package/src/features/session_replay/aggregate/index.js +314 -0
  199. package/src/features/session_replay/constants.js +3 -0
  200. package/src/features/session_replay/index.js +12 -0
  201. package/src/features/session_replay/instrument/index.js +22 -0
  202. package/src/features/session_trace/aggregate/index.js +148 -187
  203. package/src/features/session_trace/constants.js +0 -4
  204. package/src/features/session_trace/instrument/index.js +17 -69
  205. package/src/features/spa/aggregate/index.js +2 -2
  206. package/src/features/utils/agent-session.js +1 -2
  207. package/src/features/utils/aggregate-base.js +51 -0
  208. package/src/features/utils/feature-base.js +1 -31
  209. package/src/features/utils/handler-cache.js +3 -4
  210. package/src/features/utils/instrument-base.js +40 -8
  211. package/src/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
  212. package/src/loaders/agent.js +1 -1
  213. package/src/loaders/api/apiAsync.js +1 -1
  214. package/src/loaders/configure/configure.js +4 -3
  215. package/src/loaders/features/featureDependencies.js +0 -12
  216. package/src/loaders/features/features.js +3 -1
  217. package/src/loaders/micro-agent.js +4 -4
  218. package/dist/cjs/common/metrics/framework-detection.js +0 -72
  219. package/dist/cjs/common/util/user-agent.js +0 -57
  220. package/dist/cjs/common/window/supports-performance-observer.js +0 -15
  221. package/dist/esm/common/metrics/framework-detection.js +0 -66
  222. package/dist/esm/common/util/user-agent.js +0 -48
  223. package/dist/esm/common/window/supports-performance-observer.js +0 -9
  224. package/dist/types/common/metrics/framework-detection.d.ts.map +0 -1
  225. package/dist/types/common/util/user-agent.d.ts +0 -5
  226. package/dist/types/common/util/user-agent.d.ts.map +0 -1
  227. package/dist/types/common/window/supports-performance-observer.d.ts +0 -2
  228. package/dist/types/common/window/supports-performance-observer.d.ts.map +0 -1
  229. package/dist/types/features/utils/lazy-loader.d.ts.map +0 -1
  230. package/src/common/metrics/framework-detection.js +0 -71
  231. package/src/common/util/user-agent.js +0 -56
  232. package/src/common/window/supports-performance-observer.js +0 -10
  233. /package/dist/types/{common/metrics → features/metrics/aggregate}/framework-detection.d.ts +0 -0
@@ -4,86 +4,62 @@
4
4
  */
5
5
  import { registerHandler } from '../../../common/event-emitter/register-handler';
6
6
  import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
7
- import { mapOwn } from '../../../common/util/map-own';
8
7
  import { stringify } from '../../../common/util/stringify';
9
8
  import { parseUrl } from '../../../common/url/parse-url';
10
- import { supportsPerformanceObserver } from '../../../common/window/supports-performance-observer';
11
9
  import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config';
12
10
  import { now } from '../../../common/timing/now';
13
11
  import { FEATURE_NAME } from '../constants';
14
12
  import { drain } from '../../../common/drain/drain';
15
13
  import { HandlerCache } from '../../utils/handler-cache';
16
- import { FeatureBase } from '../../utils/feature-base';
17
- export class Aggregate extends FeatureBase {
14
+ import { AggregateBase } from '../../utils/aggregate-base';
15
+ const ignoredEvents = {
16
+ // we find that certain events make the data too noisy to be useful
17
+ global: {
18
+ mouseup: true,
19
+ mousedown: true
20
+ },
21
+ // certain events are present both in the window and in PVT metrics. PVT metrics are prefered so the window events should be ignored
22
+ window: {
23
+ load: true,
24
+ pagehide: true
25
+ },
26
+ // when ajax instrumentation is disabled, all XMLHttpRequest events will return with origin = xhrOriginMissing and should be ignored
27
+ xhrOriginMissing: {
28
+ ignoreAll: true
29
+ }
30
+ };
31
+ const toAggregate = {
32
+ typing: [1000, 2000],
33
+ scrolling: [100, 1000],
34
+ mousing: [1000, 2000],
35
+ touching: [1000, 2000]
36
+ };
37
+ const MAX_TRACE_DURATION = 15 * 60 * 1000; // 15 minutes
38
+
39
+ export class Aggregate extends AggregateBase {
18
40
  static featureName = FEATURE_NAME;
19
- constructor(agentIdentifier, aggregator) {
41
+ constructor(agentIdentifier, aggregator, argsObj) {
20
42
  var _this;
21
43
  // Very unlikely, but in case the existing XMLHttpRequest.prototype object on the page couldn't be wrapped.
22
44
  super(agentIdentifier, aggregator, FEATURE_NAME);
23
45
  _this = this;
24
46
  if (!getRuntime(agentIdentifier).xhrWrappable) return;
25
- const handlerCache = new HandlerCache();
47
+ this.resourceObserver = argsObj?.resourceObserver; // undefined if observer couldn't be created
26
48
  this.ptid = '';
27
- this.ignoredEvents = {
28
- // we find that certain events make the data too noisy to be useful
29
- global: {
30
- mouseup: true,
31
- mousedown: true
32
- },
33
- // certain events are present both in the window and in PVT metrics. PVT metrics are prefered so the window events should be ignored
34
- window: {
35
- load: true,
36
- pagehide: true
37
- },
38
- // when ajax instrumentation is disabled, all XMLHttpRequest events will return with origin = xhrOriginMissing and should be ignored
39
- xhrOriginMissing: {
40
- ignoreAll: true
41
- }
42
- };
43
- this.toAggregate = {
44
- typing: [1000, 2000],
45
- scrolling: [100, 1000],
46
- mousing: [1000, 2000],
47
- touching: [1000, 2000]
48
- };
49
- this.rename = {
50
- typing: {
51
- keydown: true,
52
- keyup: true,
53
- keypress: true
54
- },
55
- mousing: {
56
- mousemove: true,
57
- mouseenter: true,
58
- mouseleave: true,
59
- mouseover: true,
60
- mouseout: true
61
- },
62
- scrolling: {
63
- scroll: true
64
- },
65
- touching: {
66
- touchstart: true,
67
- touchmove: true,
68
- touchend: true,
69
- touchcancel: true,
70
- touchenter: true,
71
- touchleave: true
72
- }
73
- };
74
49
  this.trace = {};
75
50
  this.nodeCount = 0;
76
51
  this.sentTrace = null;
77
52
  this.harvestTimeSeconds = getConfigurationValue(agentIdentifier, 'session_trace.harvestTimeSeconds') || 10;
78
53
  this.maxNodesPerHarvest = getConfigurationValue(agentIdentifier, 'session_trace.maxNodesPerHarvest') || 1000;
79
54
  this.laststart = 0;
55
+ const handlerCache = new HandlerCache();
80
56
  registerHandler('feat-stn', () => {
81
57
  if (typeof PerformanceNavigationTiming !== 'undefined') {
82
- this.storeTiming(window.performance?.getEntriesByType('navigation')?.[0] || {});
58
+ this.storeTiming(window.performance.getEntriesByType('navigation')[0]);
83
59
  } else {
84
- this.storeTiming(window.performance?.timing);
60
+ this.storeTiming(window.performance.timing);
85
61
  }
86
- var scheduler = new HarvestScheduler('resources', {
62
+ const scheduler = new HarvestScheduler('resources', {
87
63
  onFinished: onHarvestFinished.bind(this),
88
64
  retryDelay: this.harvestTimeSeconds
89
65
  }, this);
@@ -91,38 +67,37 @@ export class Aggregate extends FeatureBase {
91
67
  scheduler.runHarvest({
92
68
  needResponse: true
93
69
  }); // sends first stn harvest immediately
94
-
70
+ handlerCache.decide(true);
95
71
  function onHarvestFinished(result) {
96
- // start timer only if ptid was returned by server
97
72
  if (result.sent && result.responseText && !this.ptid) {
98
- this.ptid = result.responseText;
99
- getRuntime(this.agentIdentifier).ptid = this.ptid;
73
+ // continue interval harvest only if ptid was returned by server on the first
74
+ getRuntime(this.agentIdentifier).ptid = this.ptid = result.responseText;
100
75
  scheduler.startTimer(this.harvestTimeSeconds);
101
76
  }
102
77
  if (result.sent && result.retry && this.sentTrace) {
103
- mapOwn(this.sentTrace, (name, nodes) => {
104
- this.mergeSTNs(name, nodes);
78
+ // merge previous trace back into buffer to retry for next harvest
79
+ Object.entries(this.sentTrace).forEach(_ref => {
80
+ let [name, listOfSTNodes] = _ref;
81
+ if (this.nodeCount >= this.maxNodesPerHarvest) return;
82
+ this.nodeCount += listOfSTNodes.length;
83
+ this.trace[name] = this.trace[name] ? listOfSTNodes.concat(this.trace[name]) : listOfSTNodes;
105
84
  });
106
85
  this.sentTrace = null;
107
86
  }
108
87
  }
109
88
  function prepareHarvest(options) {
110
- if (now() > 15 * 60 * 1000) {
89
+ if (now() > MAX_TRACE_DURATION) {
111
90
  // been collecting for over 15 min, empty trace object and bail
112
91
  scheduler.stopTimer();
113
92
  this.trace = {};
114
93
  return;
115
94
  }
116
-
117
- // only send when there are more than 30 nodes to send
95
+ // Only harvest when there are more than 30 nodes to send after the very first.
118
96
  if (this.ptid && this.nodeCount <= 30) return;
119
97
  return this.takeSTNs(options.retry);
120
98
  }
121
- handlerCache.decide(true);
122
- }, this.featureName, this.ee);
123
- registerHandler('block-stn', () => {
124
- handlerCache.decide(false);
125
99
  }, this.featureName, this.ee);
100
+ registerHandler('block-stn', () => handlerCache.decide(false), this.featureName, this.ee);
126
101
 
127
102
  // register the handlers immediately... but let the handlerCache decide if the data should actually get stored...
128
103
  registerHandler('bst', function () {
@@ -175,19 +150,28 @@ export class Aggregate extends FeatureBase {
175
150
  }, this.featureName, this.ee);
176
151
  drain(this.agentIdentifier, this.featureName);
177
152
  }
153
+
154
+ // PageViewTiming (FEATURE) events and metrics, such as 'load', 'lcp', etc. pipes into ST here.
178
155
  processPVT(name, value, attrs) {
179
- var t = {};
180
- t[name] = value;
181
- this.storeTiming(t);
182
- if (this.hasFID(name, attrs)) this.storeEvent({
156
+ this.storeTiming({
157
+ [name]: value
158
+ });
159
+ if (hasFID(name, attrs)) this.storeEvent({
183
160
  type: 'fid',
184
161
  target: 'document'
185
162
  }, 'document', value, value + attrs.fid);
163
+ function hasFID(name, attrs) {
164
+ return name === 'fi' && !!attrs && typeof attrs.fid === 'number';
165
+ }
186
166
  }
187
- storeTiming(_t) {
167
+
168
+ // This processes the aforementioned PVT and the first navigation entry of the page.
169
+ storeTiming(timingEntry) {
170
+ if (!timingEntry) return;
171
+
188
172
  // loop iterates through prototype also (for FF)
189
- for (let key in _t) {
190
- const val = _t[key];
173
+ for (let key in timingEntry) {
174
+ let val = timingEntry[key];
191
175
 
192
176
  // ignore size and status type nodes that do not map to timestamp metrics
193
177
  const lck = key.toLowerCase();
@@ -196,31 +180,33 @@ export class Aggregate extends FeatureBase {
196
180
  // ignore inherited methods, meaningless 0 values, and bogus timestamps
197
181
  // that are in the future (Microsoft Edge seems to sometimes produce these)
198
182
  if (!(typeof val === 'number' && val >= 0)) continue;
199
- const timeOffset = Math.round(_t[key]);
183
+ val = Math.round(val);
200
184
  this.storeSTN({
201
185
  n: key,
202
- s: timeOffset,
203
- e: timeOffset,
186
+ s: val,
187
+ e: val,
204
188
  o: 'document',
205
189
  t: 'timing'
206
190
  });
207
191
  }
208
192
  }
193
+
194
+ // Tracks duration of native APIs wrapped by wrap-timer & wrap-raf.
209
195
  storeTimer(target, start, end, type) {
210
- var category = 'timer';
211
- if (type === 'requestAnimationFrame') category = type;
212
- var evt = {
196
+ const evt = {
213
197
  n: type,
214
198
  s: start,
215
199
  e: end,
216
200
  o: 'window',
217
- t: category
201
+ t: type === 'requestAnimationFrame' ? type : 'timer'
218
202
  };
219
203
  this.storeSTN(evt);
220
204
  }
205
+
206
+ // Tracks the events and their listener's duration on objects wrapped by wrap-events.
221
207
  storeEvent(currentEvent, target, start, end) {
222
- if (this.shouldIgnoreEvent(currentEvent, target)) return false;
223
- var evt = {
208
+ if (this.shouldIgnoreEvent(currentEvent, target)) return;
209
+ const evt = {
224
210
  n: this.evtName(currentEvent.type),
225
211
  s: start,
226
212
  e: end,
@@ -235,31 +221,60 @@ export class Aggregate extends FeatureBase {
235
221
  }
236
222
  this.storeSTN(evt);
237
223
  }
224
+ shouldIgnoreEvent(event, target) {
225
+ const origin = this.evtOrigin(event.target, target);
226
+ if (event.type in ignoredEvents.global) return true;
227
+ if (!!ignoredEvents[origin] && ignoredEvents[origin].ignoreAll) return true;
228
+ if (!!ignoredEvents[origin] && event.type in ignoredEvents[origin]) return true;
229
+ return false;
230
+ }
238
231
  evtName(type) {
239
- var name = type;
240
- mapOwn(this.rename, function (key, val) {
241
- if (type in val) name = key;
242
- });
243
- return name;
232
+ switch (type) {
233
+ case 'keydown':
234
+ case 'keyup':
235
+ case 'keypress':
236
+ return 'typing';
237
+ case 'mousemove':
238
+ case 'mouseenter':
239
+ case 'mouseleave':
240
+ case 'mouseover':
241
+ case 'mouseout':
242
+ return 'mousing';
243
+ case 'scroll':
244
+ return 'scrolling';
245
+ case 'touchstart':
246
+ case 'touchmove':
247
+ case 'touchend':
248
+ case 'touchcancel':
249
+ case 'touchenter':
250
+ case 'touchleave':
251
+ return 'touching';
252
+ default:
253
+ return type;
254
+ }
244
255
  }
245
256
  evtOrigin(t, target) {
246
- var origin = 'unknown';
257
+ let origin = 'unknown';
247
258
  if (t && t instanceof XMLHttpRequest) {
248
- var params = this.ee.context(t).params;
259
+ const params = this.ee.context(t).params;
249
260
  if (!params || !params.status || !params.method || !params.host || !params.pathname) return 'xhrOriginMissing';
250
261
  origin = params.status + ' ' + params.method + ': ' + params.host + params.pathname;
251
262
  } else if (t && typeof t.tagName === 'string') {
252
263
  origin = t.tagName.toLowerCase();
253
264
  if (t.id) origin += '#' + t.id;
254
- if (t.className) origin += '.' + Array.from(t.classList).join('.');
265
+ if (t.className) {
266
+ for (let i = 0; i < t.classList.length; i++) origin += '.' + t.classList[i];
267
+ }
255
268
  }
256
269
  if (origin === 'unknown') {
257
270
  if (typeof target === 'string') origin = target;else if (target === document) origin = 'document';else if (target === window) origin = 'window';else if (target instanceof FileReader) origin = 'FileReader';
258
271
  }
259
272
  return origin;
260
273
  }
274
+
275
+ // Tracks when the window history API specified by wrap-history is used.
261
276
  storeHist(path, old, time) {
262
- var node = {
277
+ const node = {
263
278
  n: 'history.pushState',
264
279
  s: time,
265
280
  e: time,
@@ -268,11 +283,15 @@ export class Aggregate extends FeatureBase {
268
283
  };
269
284
  this.storeSTN(node);
270
285
  }
286
+
287
+ // Processes all the PerformanceResourceTiming entries captured (by observer).
271
288
  storeResources(resources) {
272
289
  if (!resources || resources.length === 0) return;
273
290
  resources.forEach(currentResource => {
274
- var parsed = parseUrl(currentResource.name);
275
- var res = {
291
+ if ((currentResource.fetchStart | 0) <= this.laststart) return; // don't recollect already-seen resources
292
+
293
+ const parsed = parseUrl(currentResource.name);
294
+ const res = {
276
295
  n: currentResource.initiatorType,
277
296
  s: currentResource.fetchStart | 0,
278
297
  e: currentResource.responseEnd | 0,
@@ -280,16 +299,15 @@ export class Aggregate extends FeatureBase {
280
299
  // resource.name is actually a URL so it's the source
281
300
  t: currentResource.entryType
282
301
  };
283
-
284
- // don't recollect old resources
285
- if (res.s <= this.laststart) return;
286
302
  this.storeSTN(res);
287
303
  });
288
304
  this.laststart = resources[resources.length - 1].fetchStart | 0;
289
305
  }
306
+
307
+ // JavascriptError (FEATURE) events pipes into ST here.
290
308
  storeErrorAgg(type, name, params, metrics) {
291
- if (type !== 'err') return;
292
- var node = {
309
+ if (type !== 'err') return; // internal errors are purposefully ignored
310
+ const node = {
293
311
  n: 'error',
294
312
  s: metrics.time,
295
313
  e: metrics.time,
@@ -298,9 +316,11 @@ export class Aggregate extends FeatureBase {
298
316
  };
299
317
  this.storeSTN(node);
300
318
  }
319
+
320
+ // Ajax (FEATURE) events--XML & fetches--pipes into ST here.
301
321
  storeXhrAgg(type, name, params, metrics) {
302
322
  if (type !== 'xhr') return;
303
- var node = {
323
+ const node = {
304
324
  n: 'Ajax',
305
325
  s: metrics.time,
306
326
  e: metrics.time + metrics.duration,
@@ -309,46 +329,46 @@ export class Aggregate extends FeatureBase {
309
329
  };
310
330
  this.storeSTN(node);
311
331
  }
332
+
333
+ // Central function called by all the other store__ & addToTrace API to append a trace node.
312
334
  storeSTN(stn) {
313
- // limit the number of data that is stored
314
- if (this.nodeCount >= this.maxNodesPerHarvest) return;
315
- var traceArr = this.trace[stn.n];
316
- if (!traceArr) traceArr = this.trace[stn.n] = [];
317
- traceArr.push(stn);
335
+ if (this.nodeCount >= this.maxNodesPerHarvest) return; // limit the amount of data that is stored at once
336
+
337
+ if (this.trace[stn.n]) this.trace[stn.n].push(stn);else this.trace[stn.n] = [stn];
318
338
  this.nodeCount++;
319
339
  }
320
- mergeSTNs(key, nodes) {
321
- // limit the number of data that is stored
322
- if (this.nodeCount >= this.maxNodesPerHarvest) return;
323
- var traceArr = this.trace[key];
324
- if (!traceArr) traceArr = this.trace[key] = [];
325
- this.trace[key] = nodes.concat(traceArr);
326
- this.nodeCount += nodes.length;
327
- }
340
+
341
+ // Used by session trace's harvester to create the payload body.
328
342
  takeSTNs(retry) {
329
- // if the observer is not being used, this checks resourcetiming buffer every harvest
330
- if (!supportsPerformanceObserver()) {
343
+ if (!this.resourceObserver) {
344
+ // if PO isn't supported, this checks resourcetiming buffer every harvest.
331
345
  this.storeResources(window.performance.getEntriesByType('resource'));
332
346
  }
333
- var stns = mapOwn(this.trace, (name, nodes) => {
334
- if (!(name in this.toAggregate)) return nodes;
335
- return mapOwn(nodes.sort(this.byStart).reduce(this.smearEvtsByOrigin(name), {}), this.val).reduce(this.flatten, []);
336
- }).reduce(this.flatten, []);
347
+ const stns = Object.entries(this.trace).flatMap(_ref2 => {
348
+ let [name, listOfSTNodes] = _ref2;
349
+ // basically take the "this.trace" map-obj and concat all the list-type values
350
+ if (!(name in toAggregate)) return listOfSTNodes;
351
+ // Special processing for event nodes dealing with user inputs:
352
+ const reindexByOriginFn = this.smearEvtsByOrigin(name);
353
+ const partitionListByOriginMap = listOfSTNodes.sort((a, b) => a.s - b.s).reduce(reindexByOriginFn, {});
354
+ return Object.values(partitionListByOriginMap).flat(); // join the partitions back into 1-D, now ordered by origin then start time
355
+ }, this);
337
356
  if (stns.length === 0) return {};
338
357
  if (retry) {
339
358
  this.sentTrace = this.trace;
340
359
  }
341
360
  this.trace = {};
342
361
  this.nodeCount = 0;
343
- var stnInfo = {
362
+ const stnInfo = {
344
363
  qs: {
345
- st: '' + getRuntime(this.agentIdentifier).offset
364
+ st: String(getRuntime(this.agentIdentifier).offset)
346
365
  },
347
366
  body: {
348
367
  res: stns
349
368
  }
350
369
  };
351
370
  if (!this.ptid) {
371
+ // send custom and user attributes on the very first ST harvest only
352
372
  const {
353
373
  userAttributes,
354
374
  atts,
@@ -356,53 +376,34 @@ export class Aggregate extends FeatureBase {
356
376
  } = getInfo(this.agentIdentifier);
357
377
  stnInfo.qs.ua = userAttributes;
358
378
  stnInfo.qs.at = atts;
359
- var ja = stringify(jsAttributes);
379
+ const ja = stringify(jsAttributes);
360
380
  stnInfo.qs.ja = ja === '{}' ? null : ja;
361
381
  }
362
382
  return stnInfo;
363
383
  }
364
- byStart(a, b) {
365
- return a.s - b.s;
366
- }
367
384
  smearEvtsByOrigin(name) {
368
- var maxGap = this.toAggregate[name][0];
369
- var maxLen = this.toAggregate[name][1];
370
- var lastO = {};
371
- return (byOrigin, evt) => {
372
- var lastArr = byOrigin[evt.o];
373
- lastArr || (lastArr = byOrigin[evt.o] = []);
374
- var last = lastO[evt.o];
375
- if (name === 'scrolling' && !this.trivial(evt)) {
376
- lastO[evt.o] = null;
377
- evt.n = 'scroll';
378
- lastArr.push(evt);
379
- } else if (last && evt.s - last.s < maxLen && last.e > evt.s - maxGap) {
380
- last.e = evt.e;
385
+ const maxGap = toAggregate[name][0];
386
+ const maxLen = toAggregate[name][1];
387
+ const lastO = {};
388
+ return (byOrigin, evtNode) => {
389
+ let lastArr = byOrigin[evtNode.o];
390
+ if (!lastArr) lastArr = byOrigin[evtNode.o] = [];
391
+ const last = lastO[evtNode.o];
392
+ if (name === 'scrolling' && !trivial(evtNode)) {
393
+ lastO[evtNode.o] = null;
394
+ evtNode.n = 'scroll';
395
+ lastArr.push(evtNode);
396
+ } else if (last && evtNode.s - last.s < maxLen && last.e > evtNode.s - maxGap) {
397
+ last.e = evtNode.e;
381
398
  } else {
382
- lastO[evt.o] = evt;
383
- lastArr.push(evt);
399
+ lastO[evtNode.o] = evtNode;
400
+ lastArr.push(evtNode);
384
401
  }
385
402
  return byOrigin;
386
403
  };
387
- }
388
- val(key, value) {
389
- return value;
390
- }
391
- flatten(a, b) {
392
- return a.concat(b);
393
- }
394
- hasFID(name, attrs) {
395
- return name === 'fi' && !!attrs && typeof attrs.fid === 'number';
396
- }
397
- trivial(node) {
398
- var limit = 4;
399
- if (node && typeof node.e === 'number' && typeof node.s === 'number' && node.e - node.s < limit) return true;else return false;
400
- }
401
- shouldIgnoreEvent(event, target) {
402
- var origin = this.evtOrigin(event.target, target);
403
- if (event.type in this.ignoredEvents.global) return true;
404
- if (!!this.ignoredEvents[origin] && this.ignoredEvents[origin].ignoreAll) return true;
405
- if (!!this.ignoredEvents[origin] && event.type in this.ignoredEvents[origin]) return true;
406
- return false;
404
+ function trivial(node) {
405
+ const limit = 4;
406
+ if (node && typeof node.e === 'number' && typeof node.s === 'number' && node.e - node.s < limit) return true;else return false;
407
+ }
407
408
  }
408
409
  }
@@ -1,7 +1,5 @@
1
- import { originals } from '../../common/config/config';
2
1
  import { FEATURE_NAMES } from '../../loaders/features/features';
3
2
  export const FEATURE_NAME = FEATURE_NAMES.sessionTrace;
4
- export const RESOURCE_TIMING_BUFFER_FULL = 'resourcetimingbufferfull';
5
3
  export const BST_RESOURCE = 'bstResource';
6
4
  export const RESOURCE = 'resource';
7
5
  export const START = '-start';
@@ -9,6 +7,4 @@ export const END = '-end';
9
7
  export const FN_START = 'fn' + START;
10
8
  export const FN_END = 'fn' + END;
11
9
  export const BST_TIMER = 'bstTimer';
12
- export const PUSH_STATE = 'pushState';
13
- export const ORIG_EVENT = originals.EV;
14
- export const ADD_EVENT_LISTENER = 'addEventListener';
10
+ export const PUSH_STATE = 'pushState';
@@ -4,8 +4,6 @@
4
4
  */
5
5
  import { handle } from '../../../common/event-emitter/handle';
6
6
  import { wrapHistory, wrapEvents, wrapTimer, wrapRaf } from '../../../common/wrap';
7
- import { supportsPerformanceObserver } from '../../../common/window/supports-performance-observer';
8
- import { eventListenerOpts } from '../../../common/event-listener/event-listener-opts';
9
7
  import { now } from '../../../common/timing/now';
10
8
  import { InstrumentBase } from '../../utils/instrument-base';
11
9
  import * as CONSTANTS from '../constants';
@@ -13,19 +11,15 @@ import { FEATURE_NAMES } from '../../../loaders/features/features';
13
11
  import { isBrowserScope } from '../../../common/util/global-scope';
14
12
  const {
15
13
  BST_RESOURCE,
14
+ RESOURCE,
16
15
  BST_TIMER,
16
+ START,
17
17
  END,
18
18
  FEATURE_NAME,
19
19
  FN_END,
20
20
  FN_START,
21
- ADD_EVENT_LISTENER,
22
- PUSH_STATE,
23
- RESOURCE,
24
- RESOURCE_TIMING_BUFFER_FULL,
25
- START,
26
- ORIG_EVENT: origEvent
21
+ PUSH_STATE
27
22
  } = CONSTANTS;
28
- const CRT = 'clearResourceTimings';
29
23
  export class Instrument extends InstrumentBase {
30
24
  static featureName = FEATURE_NAME;
31
25
  constructor(agentIdentifier, aggregator) {
@@ -37,20 +31,14 @@ export class Instrument extends InstrumentBase {
37
31
  this.timerEE = wrapTimer(thisInstrumentEE);
38
32
  this.rafEE = wrapRaf(thisInstrumentEE);
39
33
  wrapHistory(thisInstrumentEE);
40
- wrapEvents(thisInstrumentEE);
41
- thisInstrumentEE.on(FN_START, function (args, target) {
42
- var evt = args[0];
43
- if (evt instanceof origEvent) {
44
- this.bstStart = now();
45
- }
34
+ this.eventsEE = wrapEvents(thisInstrumentEE);
35
+ this.eventsEE.on(FN_START, function (args, target) {
36
+ this.bstStart = now();
46
37
  });
47
- thisInstrumentEE.on(FN_END, function (args, target) {
48
- var evt = args[0];
49
- if (evt instanceof origEvent) {
50
- // ISSUE: when target is XMLHttpRequest, nr@context should have params so we can calculate event origin
51
- // When ajax is disabled, this may fail without making ajax a dependency of session_trace
52
- handle('bst', [evt, target, this.bstStart, now()], undefined, FEATURE_NAMES.sessionTrace, thisInstrumentEE);
53
- }
38
+ this.eventsEE.on(FN_END, function (args, target) {
39
+ // ISSUE: when target is XMLHttpRequest, nr@context should have params so we can calculate event origin
40
+ // When ajax is disabled, this may fail without making ajax a dependency of session_trace
41
+ handle('bst', [args[0], target, this.bstStart, now()], undefined, FEATURE_NAMES.sessionTrace, thisInstrumentEE);
54
42
  });
55
43
  this.timerEE.on(FN_START, function (args, obj, type) {
56
44
  this.bstStart = now();
@@ -72,53 +60,23 @@ export class Instrument extends InstrumentBase {
72
60
  thisInstrumentEE.on(PUSH_STATE + END, function (args) {
73
61
  handle('bstHist', [location.pathname + location.hash, this.startPath, this.time], undefined, FEATURE_NAMES.sessionTrace, thisInstrumentEE);
74
62
  });
75
- if (supportsPerformanceObserver()) {
76
- // capture initial resources, in case our observer missed anything
77
- handle(BST_RESOURCE, [window.performance.getEntriesByType('resource')], undefined, FEATURE_NAMES.sessionTrace, thisInstrumentEE);
78
- observeResourceTimings();
79
- } else {
80
- // collect resource timings once when buffer is full
81
- if (window.performance[CRT] && window.performance[ADD_EVENT_LISTENER]) {
82
- window.performance.addEventListener(RESOURCE_TIMING_BUFFER_FULL, this.onResourceTimingBufferFull, eventListenerOpts(false));
83
- }
84
- }
85
- function observeResourceTimings() {
86
- var observer = new PerformanceObserver((list, observer) => {
63
+ let observer;
64
+ try {
65
+ // Capture initial resources and watch for future ones. Don't defer this given there's a default cap on the number of buffered entries.
66
+ observer = new PerformanceObserver(list => {
87
67
  // eslint-disable-line no-undef
88
- var entries = list.getEntries();
68
+ const entries = list.getEntries();
89
69
  handle(BST_RESOURCE, [entries], undefined, FEATURE_NAMES.sessionTrace, thisInstrumentEE);
90
70
  });
91
- try {
92
- observer.observe({
93
- entryTypes: ['resource']
94
- });
95
- } catch (e) {
96
- // do nothing
97
- }
98
- }
99
- document.addEventListener('scroll', this.noOp, eventListenerOpts(false));
100
- document.addEventListener('keypress', this.noOp, eventListenerOpts(false));
101
- document.addEventListener('click', this.noOp, eventListenerOpts(false));
102
- this.abortHandler = this.#abort;
103
- this.importAggregator();
104
- }
105
-
106
- /** Restoration and resource release tasks to be done if Session trace loader is being aborted. Unwind changes to globals. */
107
- #abort() {
108
- window.performance.removeEventListener(RESOURCE_TIMING_BUFFER_FULL, this.onResourceTimingBufferFull, false);
109
- // The doc interaction noOp listeners are harmless--cannot buffer data into EE.
110
- this.abortHandler = undefined; // weakly allow this abort op to run only once
111
- }
112
-
113
- noOp(e) {/* no-op */}
114
- onResourceTimingBufferFull(evt) {
115
- handle(BST_RESOURCE, [window.performance.getEntriesByType(RESOURCE)], undefined, FEATURE_NAMES.sessionTrace, this.ee);
116
-
117
- // stop recording once buffer is full
118
- if (window.performance[CRT]) {
119
- try {
120
- window.performance.removeEventListener(RESOURCE_TIMING_BUFFER_FULL, this.onResourceTimingBufferFull, false);
121
- } catch (e) {}
71
+ observer.observe({
72
+ type: RESOURCE,
73
+ buffered: true
74
+ });
75
+ } catch (e) {
76
+ // Per NEWRELIC-8525, we don't have a fallback for capturing resources for older versions that don't support PO at this time.
122
77
  }
78
+ this.importAggregator({
79
+ resourceObserver: observer
80
+ });
123
81
  }
124
82
  }
@@ -19,7 +19,7 @@ import { ee } from '../../../common/event-emitter/contextual-ee';
19
19
  import * as CONSTANTS from '../constants';
20
20
  import { drain } from '../../../common/drain/drain';
21
21
  import { FEATURE_NAMES } from '../../../loaders/features/features';
22
- import { FeatureBase } from '../../utils/feature-base';
22
+ import { AggregateBase } from '../../utils/aggregate-base';
23
23
  const {
24
24
  FEATURE_NAME,
25
25
  INTERACTION_EVENTS,
@@ -38,7 +38,7 @@ const {
38
38
  JSONP_END,
39
39
  originalSetTimeout
40
40
  } = CONSTANTS;
41
- export class Aggregate extends FeatureBase {
41
+ export class Aggregate extends AggregateBase {
42
42
  static featureName = FEATURE_NAME;
43
43
  constructor(agentIdentifier, aggregator) {
44
44
  super(agentIdentifier, aggregator, FEATURE_NAME);