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