@newrelic/browser-agent 1.235.0 → 1.237.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 (389) hide show
  1. package/README.md +41 -1
  2. package/dist/cjs/common/config/state/init.js +4 -0
  3. package/dist/cjs/common/config/state/runtime.js +6 -5
  4. package/dist/cjs/common/constants/env.cdn.js +2 -2
  5. package/dist/cjs/common/constants/env.npm.js +1 -1
  6. package/dist/cjs/common/constants/runtime.js +52 -0
  7. package/dist/cjs/common/deny-list/deny-list.js +14 -10
  8. package/dist/cjs/common/event-listener/event-listener-opts.js +3 -3
  9. package/dist/cjs/common/harvest/harvest-scheduler.js +22 -19
  10. package/dist/cjs/common/harvest/harvest.js +154 -148
  11. package/dist/cjs/common/harvest/types.js +54 -0
  12. package/dist/cjs/common/ids/id.js +2 -2
  13. package/dist/cjs/common/ids/unique-id.js +3 -3
  14. package/dist/cjs/common/session/session-entity.js +2 -2
  15. package/dist/cjs/common/timer/interaction-timer.js +2 -2
  16. package/dist/cjs/common/unload/eol.js +10 -11
  17. package/dist/cjs/common/url/canonicalize-url.js +2 -2
  18. package/dist/cjs/common/url/parse-url.js +3 -3
  19. package/dist/cjs/common/url/protocol.js +2 -2
  20. package/dist/cjs/common/util/submit-data.js +31 -81
  21. package/dist/cjs/common/window/nreum.js +14 -14
  22. package/dist/cjs/common/wrap/wrap-events.js +3 -3
  23. package/dist/cjs/common/wrap/wrap-fetch.js +5 -5
  24. package/dist/cjs/common/wrap/wrap-history.js +2 -2
  25. package/dist/cjs/common/wrap/wrap-jsonp.js +14 -8
  26. package/dist/cjs/common/wrap/wrap-mutation.js +2 -2
  27. package/dist/cjs/common/wrap/wrap-promise.js +2 -2
  28. package/dist/cjs/common/wrap/wrap-raf.js +2 -2
  29. package/dist/cjs/common/wrap/wrap-timer.js +4 -4
  30. package/dist/cjs/common/wrap/wrap-xhr.js +3 -3
  31. package/dist/cjs/features/ajax/aggregate/index.js +25 -28
  32. package/dist/cjs/features/ajax/instrument/distributed-tracing.js +2 -2
  33. package/dist/cjs/features/ajax/instrument/index.js +6 -7
  34. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +1 -1
  35. package/dist/cjs/features/jserrors/aggregate/index.js +7 -4
  36. package/dist/cjs/features/jserrors/constants.js +2 -4
  37. package/dist/cjs/features/jserrors/instrument/index.js +80 -89
  38. package/dist/cjs/features/jserrors/instrument/uncaught-error.js +22 -0
  39. package/dist/cjs/features/metrics/aggregate/framework-detection.js +2 -2
  40. package/dist/cjs/features/metrics/aggregate/index.js +3 -3
  41. package/dist/cjs/features/page_action/aggregate/index.js +3 -3
  42. package/dist/cjs/features/page_view_event/aggregate/index.js +10 -11
  43. package/dist/cjs/features/page_view_event/aggregate/initialized-features.js +23 -19
  44. package/dist/cjs/features/page_view_event/instrument/index.js +2 -2
  45. package/dist/cjs/features/page_view_timing/aggregate/index.js +3 -5
  46. package/dist/cjs/features/page_view_timing/instrument/index.js +2 -2
  47. package/dist/cjs/features/session_replay/aggregate/index.js +65 -34
  48. package/dist/cjs/features/session_replay/replay-mode.js +2 -2
  49. package/dist/cjs/features/session_trace/aggregate/index.js +3 -4
  50. package/dist/cjs/features/session_trace/instrument/index.js +2 -2
  51. package/dist/cjs/features/spa/aggregate/index.js +1 -1
  52. package/dist/cjs/features/spa/instrument/index.js +2 -2
  53. package/dist/cjs/features/utils/instrument-base.js +12 -15
  54. package/dist/cjs/index.js +7 -0
  55. package/dist/cjs/loaders/agent-base.js +87 -0
  56. package/dist/cjs/loaders/agent.js +48 -1
  57. package/dist/cjs/loaders/api/api.js +3 -3
  58. package/dist/cjs/loaders/api/apiAsync.js +6 -4
  59. package/dist/cjs/loaders/api/interaction-types.js +87 -0
  60. package/dist/cjs/loaders/configure/configure.js +4 -3
  61. package/dist/cjs/loaders/micro-agent.js +32 -39
  62. package/dist/esm/common/config/state/init.js +4 -0
  63. package/dist/esm/common/config/state/runtime.js +3 -2
  64. package/dist/esm/common/constants/env.cdn.js +2 -2
  65. package/dist/esm/common/constants/env.npm.js +1 -1
  66. package/dist/esm/common/constants/runtime.js +38 -0
  67. package/dist/esm/common/deny-list/deny-list.js +14 -10
  68. package/dist/esm/common/event-listener/event-listener-opts.js +1 -1
  69. package/dist/esm/common/harvest/harvest-scheduler.js +21 -20
  70. package/dist/esm/common/harvest/harvest.js +150 -146
  71. package/dist/esm/common/harvest/types.js +47 -0
  72. package/dist/esm/common/ids/id.js +1 -1
  73. package/dist/esm/common/ids/unique-id.js +1 -1
  74. package/dist/esm/common/session/session-entity.js +1 -1
  75. package/dist/esm/common/timer/interaction-timer.js +1 -1
  76. package/dist/esm/common/unload/eol.js +1 -2
  77. package/dist/esm/common/url/canonicalize-url.js +1 -1
  78. package/dist/esm/common/url/parse-url.js +1 -1
  79. package/dist/esm/common/url/protocol.js +1 -1
  80. package/dist/esm/common/util/submit-data.js +29 -78
  81. package/dist/esm/common/window/nreum.js +1 -1
  82. package/dist/esm/common/wrap/wrap-events.js +1 -1
  83. package/dist/esm/common/wrap/wrap-fetch.js +1 -1
  84. package/dist/esm/common/wrap/wrap-history.js +1 -1
  85. package/dist/esm/common/wrap/wrap-jsonp.js +13 -7
  86. package/dist/esm/common/wrap/wrap-mutation.js +1 -1
  87. package/dist/esm/common/wrap/wrap-promise.js +1 -1
  88. package/dist/esm/common/wrap/wrap-raf.js +1 -1
  89. package/dist/esm/common/wrap/wrap-timer.js +1 -1
  90. package/dist/esm/common/wrap/wrap-xhr.js +1 -1
  91. package/dist/esm/features/ajax/aggregate/index.js +26 -29
  92. package/dist/esm/features/ajax/instrument/distributed-tracing.js +1 -1
  93. package/dist/esm/features/ajax/instrument/index.js +1 -2
  94. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +1 -1
  95. package/dist/esm/features/jserrors/aggregate/index.js +6 -3
  96. package/dist/esm/features/jserrors/constants.js +1 -2
  97. package/dist/esm/features/jserrors/instrument/index.js +79 -88
  98. package/dist/esm/features/jserrors/instrument/uncaught-error.js +15 -0
  99. package/dist/esm/features/metrics/aggregate/framework-detection.js +1 -1
  100. package/dist/esm/features/metrics/aggregate/index.js +1 -1
  101. package/dist/esm/features/page_action/aggregate/index.js +1 -1
  102. package/dist/esm/features/page_view_event/aggregate/index.js +1 -2
  103. package/dist/esm/features/page_view_event/aggregate/initialized-features.js +23 -19
  104. package/dist/esm/features/page_view_event/instrument/index.js +1 -1
  105. package/dist/esm/features/page_view_timing/aggregate/index.js +2 -4
  106. package/dist/esm/features/page_view_timing/instrument/index.js +1 -1
  107. package/dist/esm/features/session_replay/aggregate/index.js +65 -34
  108. package/dist/esm/features/session_replay/replay-mode.js +2 -2
  109. package/dist/esm/features/session_trace/aggregate/index.js +3 -4
  110. package/dist/esm/features/session_trace/instrument/index.js +1 -1
  111. package/dist/esm/features/spa/aggregate/index.js +1 -1
  112. package/dist/esm/features/spa/instrument/index.js +1 -1
  113. package/dist/esm/features/utils/instrument-base.js +11 -14
  114. package/dist/esm/index.js +1 -4
  115. package/dist/esm/loaders/agent-base.js +80 -0
  116. package/dist/esm/loaders/agent.js +48 -1
  117. package/dist/esm/loaders/api/api.js +2 -2
  118. package/dist/esm/loaders/api/apiAsync.js +3 -3
  119. package/dist/esm/loaders/api/interaction-types.js +80 -0
  120. package/dist/esm/loaders/configure/configure.js +4 -3
  121. package/dist/esm/loaders/micro-agent.js +32 -39
  122. package/dist/types/common/config/state/init.d.ts.map +1 -1
  123. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  124. package/dist/types/common/constants/runtime.d.ts +29 -0
  125. package/dist/types/common/constants/runtime.d.ts.map +1 -0
  126. package/dist/types/common/event-emitter/register-handler.d.ts +1 -1
  127. package/dist/types/common/harvest/harvest-scheduler.d.ts +1 -1
  128. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  129. package/dist/types/common/harvest/harvest.d.ts +49 -38
  130. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  131. package/dist/types/common/harvest/types.d.ts +100 -0
  132. package/dist/types/common/harvest/types.d.ts.map +1 -0
  133. package/dist/types/common/session/session-entity.d.ts +6 -6
  134. package/dist/types/common/unload/eol.d.ts.map +1 -1
  135. package/dist/types/common/util/submit-data.d.ts +44 -64
  136. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  137. package/dist/types/common/window/nreum.d.ts +2 -2
  138. package/dist/types/common/wrap/wrap-jsonp.d.ts.map +1 -1
  139. package/dist/types/features/ajax/aggregate/index.d.ts +5 -5
  140. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  141. package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
  142. package/dist/types/features/jserrors/aggregate/index.d.ts +1 -1
  143. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  144. package/dist/types/features/jserrors/constants.d.ts +0 -1
  145. package/dist/types/features/jserrors/constants.d.ts.map +1 -1
  146. package/dist/types/features/jserrors/instrument/index.d.ts +0 -13
  147. package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
  148. package/dist/types/features/jserrors/instrument/uncaught-error.d.ts +15 -0
  149. package/dist/types/features/jserrors/instrument/uncaught-error.d.ts.map +1 -0
  150. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts +5 -5
  151. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  152. package/dist/types/features/page_view_event/aggregate/initialized-features.d.ts.map +1 -1
  153. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  154. package/dist/types/features/session_replay/aggregate/index.d.ts +16 -30
  155. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  156. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  157. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  158. package/dist/types/index.d.ts +1 -0
  159. package/dist/types/loaders/agent-base.d.ts +59 -0
  160. package/dist/types/loaders/agent-base.d.ts.map +1 -0
  161. package/dist/types/loaders/agent.d.ts +39 -5
  162. package/dist/types/loaders/agent.d.ts.map +1 -1
  163. package/dist/types/loaders/api/interaction-types.d.ts +122 -0
  164. package/dist/types/loaders/api/interaction-types.d.ts.map +1 -0
  165. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  166. package/dist/types/loaders/features/features.d.ts +9 -9
  167. package/dist/types/loaders/micro-agent.d.ts +6 -6
  168. package/dist/types/loaders/micro-agent.d.ts.map +1 -1
  169. package/package.json +6 -1
  170. package/src/common/config/__mocks__/config.js +11 -0
  171. package/src/common/config/state/init.js +2 -1
  172. package/src/common/config/state/runtime.js +3 -2
  173. package/src/common/constants/__mocks__/env.js +3 -0
  174. package/src/common/constants/__mocks__/runtime.js +8 -0
  175. package/src/common/constants/env.cdn.test.js +7 -0
  176. package/src/common/constants/env.npm.test.js +7 -0
  177. package/src/common/constants/env.test.js +7 -0
  178. package/src/common/constants/runtime.js +71 -0
  179. package/src/common/constants/runtime.test.js +168 -0
  180. package/src/common/context/__mocks__/shared-context.js +8 -0
  181. package/src/common/deny-list/deny-list.js +11 -11
  182. package/src/common/deny-list/deny-list.test.js +31 -0
  183. package/src/common/event-listener/__mocks__/event-listener-opts.js +7 -0
  184. package/src/common/event-listener/event-listener-opts.js +1 -1
  185. package/src/common/harvest/__mocks__/harvest.js +13 -0
  186. package/src/common/harvest/harvest-scheduler.js +21 -20
  187. package/src/common/harvest/harvest-scheduler.test.js +496 -0
  188. package/src/common/harvest/harvest.js +142 -134
  189. package/src/common/harvest/harvest.test.js +798 -0
  190. package/src/common/harvest/types.js +47 -0
  191. package/src/common/ids/id.js +1 -1
  192. package/src/common/ids/unique-id.js +1 -1
  193. package/src/common/session/__mocks__/session-entity.js +25 -0
  194. package/src/common/session/session-entity.component-test.js +1 -1
  195. package/src/common/session/session-entity.js +1 -1
  196. package/src/common/timer/interaction-timer.js +1 -1
  197. package/src/common/timing/__mocks__/now.js +1 -0
  198. package/src/common/unload/__mocks__/eol.js +1 -0
  199. package/src/common/unload/eol.js +1 -2
  200. package/src/common/url/__mocks__/clean-url.js +1 -0
  201. package/src/common/url/__mocks__/encode.js +7 -0
  202. package/src/common/url/__mocks__/location.js +1 -0
  203. package/src/common/url/canonicalize-url.js +1 -1
  204. package/src/common/url/canonicalize-url.test.js +2 -2
  205. package/src/common/url/parse-url.js +1 -1
  206. package/src/common/url/parse-url.test.js +3 -3
  207. package/src/common/url/protocol.js +1 -1
  208. package/src/common/util/__mocks__/obfuscate.js +10 -0
  209. package/src/common/util/__mocks__/stringify.js +1 -0
  210. package/src/common/util/__mocks__/submit-data.js +5 -0
  211. package/src/common/util/__mocks__/traverse.js +1 -0
  212. package/src/common/util/submit-data.js +22 -58
  213. package/src/common/util/submit-data.test.js +30 -73
  214. package/src/common/window/nreum.js +1 -1
  215. package/src/common/wrap/wrap-events.js +1 -1
  216. package/src/common/wrap/wrap-fetch.js +1 -1
  217. package/src/common/wrap/wrap-history.js +1 -1
  218. package/src/common/wrap/wrap-jsonp.js +12 -7
  219. package/src/common/wrap/wrap-mutation.js +1 -1
  220. package/src/common/wrap/wrap-promise.js +1 -1
  221. package/src/common/wrap/wrap-promise.test.js +2 -2
  222. package/src/common/wrap/wrap-raf.js +1 -1
  223. package/src/common/wrap/wrap-timer.js +1 -1
  224. package/src/common/wrap/wrap-xhr.js +1 -1
  225. package/src/features/ajax/aggregate/index.js +26 -32
  226. package/src/features/ajax/instrument/distributed-tracing.js +1 -1
  227. package/src/features/ajax/instrument/index.js +1 -2
  228. package/src/features/jserrors/aggregate/compute-stack-trace.js +1 -1
  229. package/src/features/jserrors/aggregate/compute-stack-trace.test.js +1 -1
  230. package/src/features/jserrors/aggregate/index.js +7 -3
  231. package/src/features/jserrors/constants.js +0 -1
  232. package/src/features/jserrors/instrument/index.js +92 -88
  233. package/src/features/jserrors/instrument/uncaught-error.js +15 -0
  234. package/src/features/metrics/aggregate/framework-detection.js +1 -1
  235. package/src/features/metrics/aggregate/framework-detection.test.js +2 -2
  236. package/src/features/metrics/aggregate/index.js +1 -1
  237. package/src/features/page_action/aggregate/index.js +1 -1
  238. package/src/features/page_view_event/aggregate/index.js +1 -2
  239. package/src/features/page_view_event/aggregate/initialized-features.js +18 -14
  240. package/src/features/page_view_event/instrument/index.js +1 -1
  241. package/src/features/page_view_timing/aggregate/index.js +2 -4
  242. package/src/features/page_view_timing/instrument/index.js +1 -1
  243. package/src/features/session_replay/aggregate/index.component-test.js +17 -56
  244. package/src/features/session_replay/aggregate/index.js +47 -28
  245. package/src/features/session_replay/replay-mode.js +2 -2
  246. package/src/features/session_trace/aggregate/index.js +3 -4
  247. package/src/features/session_trace/instrument/index.js +1 -1
  248. package/src/features/spa/aggregate/index.js +1 -1
  249. package/src/features/spa/instrument/index.js +1 -1
  250. package/src/features/utils/agent-session.test.js +2 -2
  251. package/src/features/utils/instrument-base.js +11 -14
  252. package/src/features/utils/instrument-base.test.js +29 -3
  253. package/src/index.js +1 -3
  254. package/src/loaders/agent-base.js +81 -0
  255. package/src/loaders/agent.js +50 -1
  256. package/src/loaders/api/api.js +2 -2
  257. package/src/loaders/api/apiAsync.js +3 -3
  258. package/src/loaders/api/interaction-types.js +80 -0
  259. package/src/loaders/configure/configure.js +5 -4
  260. package/src/loaders/micro-agent.js +30 -31
  261. package/dist/cjs/common/browser-version/firefox-version.js +0 -17
  262. package/dist/cjs/common/browser-version/ios-version.js +0 -19
  263. package/dist/cjs/common/event-emitter/contextual-ee.test.js +0 -282
  264. package/dist/cjs/common/event-emitter/handle.test.js +0 -58
  265. package/dist/cjs/common/event-emitter/register-handler.test.js +0 -55
  266. package/dist/cjs/common/harvest/harvest-scheduler.component-test.js +0 -39
  267. package/dist/cjs/common/harvest/harvest.component-test.js +0 -224
  268. package/dist/cjs/common/ids/id.test.js +0 -85
  269. package/dist/cjs/common/ids/unique-id.test.js +0 -49
  270. package/dist/cjs/common/session/session-entity.component-test.js +0 -497
  271. package/dist/cjs/common/storage/local-storage.test.js +0 -14
  272. package/dist/cjs/common/timer/interaction-timer.component-test.js +0 -216
  273. package/dist/cjs/common/timer/timer.test.js +0 -105
  274. package/dist/cjs/common/timing/nav-timing.test.js +0 -192
  275. package/dist/cjs/common/url/canonicalize-url.test.js +0 -38
  276. package/dist/cjs/common/url/clean-url.test.js +0 -9
  277. package/dist/cjs/common/url/encode.component-test.js +0 -74
  278. package/dist/cjs/common/url/location.test.js +0 -13
  279. package/dist/cjs/common/url/parse-url.test.js +0 -111
  280. package/dist/cjs/common/url/protocol.component-test.js +0 -15
  281. package/dist/cjs/common/util/console.test.js +0 -30
  282. package/dist/cjs/common/util/data-size.test.js +0 -64
  283. package/dist/cjs/common/util/feature-flags.test.js +0 -84
  284. package/dist/cjs/common/util/get-or-set.test.js +0 -47
  285. package/dist/cjs/common/util/global-scope.js +0 -27
  286. package/dist/cjs/common/util/global-scope.test.js +0 -72
  287. package/dist/cjs/common/util/invoke.test.js +0 -49
  288. package/dist/cjs/common/util/map-own.test.js +0 -49
  289. package/dist/cjs/common/util/obfuscate.component-test.js +0 -129
  290. package/dist/cjs/common/util/stringify.test.js +0 -48
  291. package/dist/cjs/common/util/submit-data.test.js +0 -245
  292. package/dist/cjs/common/util/traverse.test.js +0 -44
  293. package/dist/cjs/common/wrap/wrap-promise.test.js +0 -119
  294. package/dist/cjs/features/jserrors/aggregate/canonical-function-name.test.js +0 -31
  295. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +0 -383
  296. package/dist/cjs/features/jserrors/aggregate/format-stack-trace.test.js +0 -40
  297. package/dist/cjs/features/jserrors/aggregate/string-hash-code.test.js +0 -27
  298. package/dist/cjs/features/jserrors/instrument/debug.js +0 -40
  299. package/dist/cjs/features/metrics/aggregate/framework-detection.test.js +0 -137
  300. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.test.js +0 -17
  301. package/dist/cjs/features/metrics/aggregate/polyfill-detection.test.js +0 -165
  302. package/dist/cjs/features/session_replay/aggregate/index.component-test.js +0 -457
  303. package/dist/cjs/features/spa/aggregate/interaction-node.test.js +0 -16
  304. package/dist/cjs/features/utils/agent-session.test.js +0 -211
  305. package/dist/cjs/features/utils/aggregate-base.test.js +0 -110
  306. package/dist/cjs/features/utils/feature-base.test.js +0 -42
  307. package/dist/cjs/features/utils/handler-cache.test.js +0 -53
  308. package/dist/cjs/features/utils/instrument-base.test.js +0 -179
  309. package/dist/cjs/features/utils/lazy-feature-loader.test.js +0 -30
  310. package/dist/esm/common/browser-version/firefox-version.js +0 -10
  311. package/dist/esm/common/browser-version/ios-version.js +0 -11
  312. package/dist/esm/common/event-emitter/contextual-ee.test.js +0 -278
  313. package/dist/esm/common/event-emitter/handle.test.js +0 -54
  314. package/dist/esm/common/event-emitter/register-handler.test.js +0 -51
  315. package/dist/esm/common/harvest/harvest-scheduler.component-test.js +0 -37
  316. package/dist/esm/common/harvest/harvest.component-test.js +0 -222
  317. package/dist/esm/common/ids/id.test.js +0 -81
  318. package/dist/esm/common/ids/unique-id.test.js +0 -44
  319. package/dist/esm/common/session/session-entity.component-test.js +0 -495
  320. package/dist/esm/common/storage/local-storage.test.js +0 -12
  321. package/dist/esm/common/timer/interaction-timer.component-test.js +0 -214
  322. package/dist/esm/common/timer/timer.test.js +0 -103
  323. package/dist/esm/common/timing/nav-timing.test.js +0 -190
  324. package/dist/esm/common/url/canonicalize-url.test.js +0 -34
  325. package/dist/esm/common/url/clean-url.test.js +0 -7
  326. package/dist/esm/common/url/encode.component-test.js +0 -70
  327. package/dist/esm/common/url/location.test.js +0 -11
  328. package/dist/esm/common/url/parse-url.test.js +0 -107
  329. package/dist/esm/common/url/protocol.component-test.js +0 -13
  330. package/dist/esm/common/util/console.test.js +0 -28
  331. package/dist/esm/common/util/data-size.test.js +0 -60
  332. package/dist/esm/common/util/feature-flags.test.js +0 -80
  333. package/dist/esm/common/util/get-or-set.test.js +0 -45
  334. package/dist/esm/common/util/global-scope.js +0 -17
  335. package/dist/esm/common/util/global-scope.test.js +0 -70
  336. package/dist/esm/common/util/invoke.test.js +0 -47
  337. package/dist/esm/common/util/map-own.test.js +0 -47
  338. package/dist/esm/common/util/obfuscate.component-test.js +0 -125
  339. package/dist/esm/common/util/stringify.test.js +0 -46
  340. package/dist/esm/common/util/submit-data.test.js +0 -241
  341. package/dist/esm/common/util/traverse.test.js +0 -42
  342. package/dist/esm/common/wrap/wrap-promise.test.js +0 -115
  343. package/dist/esm/features/jserrors/aggregate/canonical-function-name.test.js +0 -29
  344. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +0 -379
  345. package/dist/esm/features/jserrors/aggregate/format-stack-trace.test.js +0 -38
  346. package/dist/esm/features/jserrors/aggregate/string-hash-code.test.js +0 -25
  347. package/dist/esm/features/jserrors/instrument/debug.js +0 -38
  348. package/dist/esm/features/metrics/aggregate/framework-detection.test.js +0 -133
  349. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.test.js +0 -15
  350. package/dist/esm/features/metrics/aggregate/polyfill-detection.test.js +0 -163
  351. package/dist/esm/features/session_replay/aggregate/index.component-test.js +0 -453
  352. package/dist/esm/features/spa/aggregate/interaction-node.test.js +0 -14
  353. package/dist/esm/features/utils/agent-session.test.js +0 -207
  354. package/dist/esm/features/utils/aggregate-base.test.js +0 -108
  355. package/dist/esm/features/utils/feature-base.test.js +0 -40
  356. package/dist/esm/features/utils/handler-cache.test.js +0 -51
  357. package/dist/esm/features/utils/instrument-base.test.js +0 -175
  358. package/dist/esm/features/utils/lazy-feature-loader.test.js +0 -29
  359. package/dist/types/common/browser-version/firefox-version.d.ts +0 -2
  360. package/dist/types/common/browser-version/firefox-version.d.ts.map +0 -1
  361. package/dist/types/common/browser-version/ios-version.d.ts +0 -3
  362. package/dist/types/common/browser-version/ios-version.d.ts.map +0 -1
  363. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts +0 -2
  364. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts.map +0 -1
  365. package/dist/types/common/harvest/harvest.component-test.d.ts +0 -2
  366. package/dist/types/common/harvest/harvest.component-test.d.ts.map +0 -1
  367. package/dist/types/common/session/session-entity.component-test.d.ts +0 -2
  368. package/dist/types/common/session/session-entity.component-test.d.ts.map +0 -1
  369. package/dist/types/common/timer/interaction-timer.component-test.d.ts +0 -2
  370. package/dist/types/common/timer/interaction-timer.component-test.d.ts.map +0 -1
  371. package/dist/types/common/url/encode.component-test.d.ts +0 -2
  372. package/dist/types/common/url/encode.component-test.d.ts.map +0 -1
  373. package/dist/types/common/url/protocol.component-test.d.ts +0 -2
  374. package/dist/types/common/url/protocol.component-test.d.ts.map +0 -1
  375. package/dist/types/common/util/global-scope.d.ts +0 -5
  376. package/dist/types/common/util/global-scope.d.ts.map +0 -1
  377. package/dist/types/common/util/obfuscate.component-test.d.ts +0 -2
  378. package/dist/types/common/util/obfuscate.component-test.d.ts.map +0 -1
  379. package/dist/types/features/jserrors/instrument/debug.d.ts +0 -2
  380. package/dist/types/features/jserrors/instrument/debug.d.ts.map +0 -1
  381. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts +0 -2
  382. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts.map +0 -1
  383. package/src/common/browser-version/firefox-version.js +0 -10
  384. package/src/common/browser-version/ios-version.js +0 -11
  385. package/src/common/harvest/harvest-scheduler.component-test.js +0 -25
  386. package/src/common/harvest/harvest.component-test.js +0 -169
  387. package/src/common/util/global-scope.js +0 -23
  388. package/src/common/util/global-scope.test.js +0 -87
  389. package/src/features/jserrors/instrument/debug.js +0 -36
@@ -5,63 +5,53 @@
5
5
 
6
6
  import { handle } from '../../../common/event-emitter/handle';
7
7
  import { now } from '../../../common/timing/now';
8
- import { getOrSet } from '../../../common/util/get-or-set';
9
- import { wrapRaf, wrapTimer, wrapEvents, wrapXhr } from '../../../common/wrap';
10
- import './debug';
11
8
  import { InstrumentBase } from '../../utils/instrument-base';
12
- import { FEATURE_NAME, NR_ERR_PROP } from '../constants';
9
+ import { FEATURE_NAME } from '../constants';
13
10
  import { FEATURE_NAMES } from '../../../loaders/features/features';
14
- import { globalScope } from '../../../common/util/global-scope';
11
+ import { globalScope } from '../../../common/constants/runtime';
15
12
  import { eventListenerOpts } from '../../../common/event-listener/event-listener-opts';
16
- import { getRuntime } from '../../../common/config/config';
17
13
  import { stringify } from '../../../common/util/stringify';
14
+ import { UncaughtError } from './uncaught-error';
18
15
  export class Instrument extends InstrumentBase {
19
16
  static featureName = FEATURE_NAME;
17
+ #seenErrors = new Set();
20
18
  constructor(agentIdentifier, aggregator) {
21
19
  let auto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
22
20
  super(agentIdentifier, aggregator, FEATURE_NAME, auto);
23
- // skipNext counter to keep track of uncaught
24
- // errors that will be the same as caught errors.
25
- this.skipNext = 0;
26
21
  try {
27
22
  // this try-catch can be removed when IE11 is completely unsupported & gone
28
23
  this.removeOnAbort = new AbortController();
29
24
  } catch (e) {}
30
- const thisInstrument = this;
31
- thisInstrument.ee.on('fn-start', function (args, obj, methodName) {
32
- if (thisInstrument.abortHandler) thisInstrument.skipNext += 1;
33
- });
34
- thisInstrument.ee.on('fn-err', function (args, obj, err) {
35
- if (thisInstrument.abortHandler && !err[NR_ERR_PROP]) {
36
- getOrSet(err, NR_ERR_PROP, function getVal() {
37
- return true;
38
- });
39
- this.thrown = true;
40
- handle('err', [err, now()], undefined, FEATURE_NAMES.jserrors, thisInstrument.ee);
41
- }
42
- });
43
- thisInstrument.ee.on('fn-end', function () {
44
- if (!thisInstrument.abortHandler) return;
45
- if (!this.thrown && thisInstrument.skipNext > 0) thisInstrument.skipNext -= 1;
25
+
26
+ // Capture function errors early in case the spa feature is loaded
27
+ this.ee.on('fn-err', (args, obj, error) => {
28
+ if (!this.abortHandler || this.#seenErrors.has(error)) return;
29
+ this.#seenErrors.add(error);
30
+ handle('err', [this.#castError(error), now()], undefined, FEATURE_NAMES.jserrors, this.ee);
46
31
  });
47
- thisInstrument.ee.on('internal-error', function (e) {
48
- handle('ierr', [e, now(), true], undefined, FEATURE_NAMES.jserrors, thisInstrument.ee);
32
+ this.ee.on('internal-error', error => {
33
+ if (!this.abortHandler) return;
34
+ handle('ierr', [this.#castError(error), now(), true], undefined, FEATURE_NAMES.jserrors, this.ee);
49
35
  });
50
-
51
- // Replace global error handler with our own.
52
- this.origOnerror = globalScope.onerror;
53
- globalScope.onerror = this.onerrorHandler.bind(this);
54
- globalScope.addEventListener('unhandledrejection', e => {
55
- /** rejections can contain data of any type -- this is an effort to keep the message human readable */
56
- const err = castReasonToError(e.reason);
57
- handle('err', [err, now(), false, {
36
+ globalScope.addEventListener('unhandledrejection', promiseRejectionEvent => {
37
+ if (!this.abortHandler) return;
38
+ handle('err', [this.#castPromiseRejectionEvent(promiseRejectionEvent), now(), false, {
58
39
  unhandledPromiseRejection: 1
59
40
  }], undefined, FEATURE_NAMES.jserrors, this.ee);
60
41
  }, eventListenerOpts(false, this.removeOnAbort?.signal));
61
- wrapRaf(this.ee);
62
- wrapTimer(this.ee);
63
- wrapEvents(this.ee);
64
- if (getRuntime(agentIdentifier).xhrWrappable) wrapXhr(this.ee);
42
+ globalScope.addEventListener('error', errorEvent => {
43
+ if (!this.abortHandler) return;
44
+
45
+ /**
46
+ * If the spa feature is loaded, errors may already have been captured in the `fn-err` listener above.
47
+ * This ensures those errors are not captured twice.
48
+ */
49
+ if (this.#seenErrors.has(errorEvent.error)) {
50
+ this.#seenErrors.delete(errorEvent.error);
51
+ return;
52
+ }
53
+ handle('err', [this.#castErrorEvent(errorEvent), now()], undefined, FEATURE_NAMES.jserrors, this.ee);
54
+ }, eventListenerOpts(false, this.removeOnAbort?.signal));
65
55
  this.abortHandler = this.#abort; // we also use this as a flag to denote that the feature is active or on and handling errors
66
56
  this.importAggregator();
67
57
  }
@@ -69,65 +59,66 @@ export class Instrument extends InstrumentBase {
69
59
  /** Restoration and resource release tasks to be done if JS error loader is being aborted. Unwind changes to globals. */
70
60
  #abort() {
71
61
  this.removeOnAbort?.abort();
62
+ this.#seenErrors.clear();
72
63
  this.abortHandler = undefined; // weakly allow this abort op to run only once
73
64
  }
74
65
 
75
66
  /**
76
- * FF and Android browsers do not provide error info to the 'error' event callback,
77
- * so we must use window.onerror
78
- * @param {string} message
79
- * @param {string} filename
80
- * @param {number} lineno
81
- * @param {number} column
82
- * @param {Error | *} errorObj
83
- * @returns
67
+ * Any value can be used with the `throw` keyword. This function ensures that the value is
68
+ * either a proper Error instance or attempts to convert it to an UncaughtError instance.
69
+ * @param {any} error The value thrown
70
+ * @returns {Error|UncaughtError} The converted error instance
84
71
  */
85
- onerrorHandler(message, filename, lineno, column, errorObj) {
86
- if (typeof this.origOnerror === 'function') this.origOnerror(...arguments);
87
- try {
88
- if (this.skipNext) this.skipNext -= 1;else handle('err', [errorObj || new UncaughtException(message, filename, lineno), now()], undefined, FEATURE_NAMES.jserrors, this.ee);
89
- } catch (e) {
72
+ #castError(error) {
73
+ if (error instanceof Error) {
74
+ return error;
75
+ }
76
+
77
+ /**
78
+ * The thrown value may contain a message property. If it does, try to treat the thrown
79
+ * value as an Error-like object.
80
+ */
81
+ if (typeof error?.message !== 'undefined') {
82
+ return new UncaughtError(error.message, error.filename || error.sourceURL, error.lineno || error.line, error.colno || error.col);
83
+ }
84
+ return new UncaughtError(typeof error === 'string' ? error : stringify(error));
85
+ }
86
+
87
+ /**
88
+ * Attempts to convert a PromiseRejectionEvent object to an Error object
89
+ * @param {PromiseRejectionEvent} unhandledRejectionEvent The unhandled promise rejection event
90
+ * @returns {Error} An Error object with the message as the casted reason
91
+ */
92
+ #castPromiseRejectionEvent(promiseRejectionEvent) {
93
+ let prefix = 'Unhandled Promise Rejection: ';
94
+ if (promiseRejectionEvent?.reason instanceof Error) {
90
95
  try {
91
- handle('ierr', [e, now(), true], undefined, FEATURE_NAMES.jserrors, this.ee);
92
- } catch (err) {
93
- // do nothing
96
+ promiseRejectionEvent.reason.message = prefix + promiseRejectionEvent.reason.message;
97
+ return promiseRejectionEvent.reason;
98
+ } catch (e) {
99
+ return promiseRejectionEvent.reason;
94
100
  }
95
101
  }
96
- return false; // maintain default behavior of the error event of Window
102
+ if (typeof promiseRejectionEvent.reason === 'undefined') return new UncaughtError(prefix);
103
+ const error = this.#castError(promiseRejectionEvent.reason);
104
+ error.message = prefix + error.message;
105
+ return error;
97
106
  }
98
- }
99
-
100
- /**
101
- *
102
- * @param {string} message
103
- * @param {string} filename
104
- * @param {number} lineno
105
- */
106
- function UncaughtException(message, filename, lineno) {
107
- this.message = message || 'Uncaught error with no additional information';
108
- this.sourceURL = filename;
109
- this.line = lineno;
110
- }
111
107
 
112
- /**
113
- * Attempts to cast an unhandledPromiseRejection reason (reject(...)) to an Error object
114
- * @param {*} reason - The reason property from an unhandled promise rejection
115
- * @returns {Error} - An Error object with the message as the casted reason
116
- */
117
- function castReasonToError(reason) {
118
- let prefix = 'Unhandled Promise Rejection: ';
119
- if (reason instanceof Error) {
120
- try {
121
- reason.message = prefix + reason.message;
122
- return reason;
123
- } catch (e) {
124
- return reason;
108
+ /**
109
+ * Attempts to convert an ErrorEvent object to an Error object
110
+ * @param {ErrorEvent} errorEvent The error event
111
+ * @returns {Error|UncaughtError} The error event converted to an Error object
112
+ */
113
+ #castErrorEvent(errorEvent) {
114
+ if (errorEvent.error instanceof Error) {
115
+ return errorEvent.error;
125
116
  }
126
- }
127
- if (typeof reason === 'undefined') return new Error(prefix);
128
- try {
129
- return new Error(prefix + stringify(reason));
130
- } catch (err) {
131
- return new Error(prefix);
117
+
118
+ /**
119
+ * Older browsers do not contain the `error` property on the ErrorEvent instance.
120
+ * https://caniuse.com/mdn-api_errorevent_error
121
+ */
122
+ return new UncaughtError(errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno);
132
123
  }
133
124
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Represents an uncaught non Error type error. This class does
3
+ * not extend the Error class to prevent an invalid stack trace
4
+ * from being created. Use this class to cast thrown errors that
5
+ * do not use the Error class (strings, etc) to an object.
6
+ */
7
+ export class UncaughtError {
8
+ constructor(message, filename, lineno, colno) {
9
+ this.name = 'UncaughtError';
10
+ this.message = message;
11
+ this.sourceURL = filename;
12
+ this.line = lineno;
13
+ this.column = colno;
14
+ }
15
+ }
@@ -1,4 +1,4 @@
1
- import { isBrowserScope } from '../../../common/util/global-scope';
1
+ import { isBrowserScope } from '../../../common/constants/runtime';
2
2
  const FRAMEWORKS = {
3
3
  REACT: 'React',
4
4
  ANGULAR: 'Angular',
@@ -10,7 +10,7 @@ import { getRules, validateRules } from '../../../common/util/obfuscate';
10
10
  import { VERSION } from "../../../common/constants/env.npm";
11
11
  import { onDOMContentLoaded } from '../../../common/window/load';
12
12
  import { windowAddEventListener } from '../../../common/event-listener/event-listener-opts';
13
- import { isBrowserScope } from '../../../common/util/global-scope';
13
+ import { isBrowserScope } from '../../../common/constants/runtime';
14
14
  import { AggregateBase } from '../../utils/aggregate-base';
15
15
  import { stringify } from '../../../common/util/stringify';
16
16
  import { endpointMap } from './endpoint-map';
@@ -11,7 +11,7 @@ import { cleanURL } from '../../../common/url/clean-url';
11
11
  import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config';
12
12
  import { FEATURE_NAME } from '../constants';
13
13
  import { drain } from '../../../common/drain/drain';
14
- import { isBrowserScope } from '../../../common/util/global-scope';
14
+ import { isBrowserScope } from '../../../common/constants/runtime';
15
15
  import { AggregateBase } from '../../utils/aggregate-base';
16
16
  export class Aggregate extends AggregateBase {
17
17
  static featureName = FEATURE_NAME;
@@ -1,6 +1,6 @@
1
1
  import { handle } from '../../../common/event-emitter/handle';
2
2
  import { FEATURE_NAMES } from '../../../loaders/features/features';
3
- import { isiOS } from '../../../common/browser-version/ios-version';
3
+ import { isiOS, globalScope, isBrowserScope } from '../../../common/constants/runtime';
4
4
  import { onTTFB } from 'web-vitals';
5
5
  import { addPT, addPN } from '../../../common/timing/nav-timing';
6
6
  import { stringify } from '../../../common/util/stringify';
@@ -9,7 +9,6 @@ import { getConfigurationValue, getInfo, getRuntime } from '../../../common/conf
9
9
  import { Harvest } from '../../../common/harvest/harvest';
10
10
  import * as CONSTANTS from '../constants';
11
11
  import { getActivatedFeaturesFlags } from './initialized-features';
12
- import { globalScope, isBrowserScope } from '../../../common/util/global-scope';
13
12
  import { drain } from '../../../common/drain/drain';
14
13
  import { activateFeatures } from '../../../common/util/feature-flags';
15
14
  import { warn } from '../../../common/util/console';
@@ -1,4 +1,5 @@
1
1
  import { FEATURE_NAMES } from '../../../loaders/features/features';
2
+ import { gosNREUM } from '../../../common/window/nreum';
2
3
 
3
4
  /**
4
5
  * Get an array of flags required by downstream (NR UI) based on the features initialized in this agent
@@ -8,25 +9,28 @@ import { FEATURE_NAMES } from '../../../loaders/features/features';
8
9
  */
9
10
  export function getActivatedFeaturesFlags(agentId) {
10
11
  const flagArr = [];
11
- Object.keys(newrelic.initializedAgents[agentId].features).forEach(featName => {
12
- switch (featName) {
13
- case FEATURE_NAMES.ajax:
14
- flagArr.push('xhr');
15
- break;
16
- case FEATURE_NAMES.jserrors:
17
- flagArr.push('err');
18
- break;
19
- case FEATURE_NAMES.pageAction:
20
- flagArr.push('ins');
21
- break;
22
- case FEATURE_NAMES.sessionTrace:
23
- flagArr.push('stn');
24
- break;
25
- case FEATURE_NAMES.spa:
26
- flagArr.push('spa');
27
- break;
28
- }
29
- });
12
+ const newrelic = gosNREUM();
13
+ try {
14
+ Object.keys(newrelic.initializedAgents[agentId].features).forEach(featName => {
15
+ switch (featName) {
16
+ case FEATURE_NAMES.ajax:
17
+ flagArr.push('xhr');
18
+ break;
19
+ case FEATURE_NAMES.jserrors:
20
+ flagArr.push('err');
21
+ break;
22
+ case FEATURE_NAMES.pageAction:
23
+ flagArr.push('ins');
24
+ break;
25
+ case FEATURE_NAMES.sessionTrace:
26
+ flagArr.push('stn');
27
+ break;
28
+ case FEATURE_NAMES.spa:
29
+ flagArr.push('spa');
30
+ break;
31
+ }
32
+ });
33
+ } catch (e) {}
30
34
  return flagArr;
31
35
  }
32
36
 
@@ -1,5 +1,5 @@
1
1
  import { handle } from '../../../common/event-emitter/handle';
2
- import { isiOS } from '../../../common/browser-version/ios-version';
2
+ import { isiOS } from '../../../common/constants/runtime';
3
3
  import { InstrumentBase } from '../../utils/instrument-base';
4
4
  import * as CONSTANTS from '../constants';
5
5
  import { FEATURE_NAMES } from '../../../loaders/features/features';
@@ -6,7 +6,7 @@
6
6
  import { onFCP, onFID, onLCP, onCLS, onINP } from 'web-vitals';
7
7
  import { onFirstPaint } from '../first-paint';
8
8
  import { onLongTask } from '../long-tasks';
9
- import { iOS_below16 } from '../../../common/browser-version/ios-version';
9
+ import { iOS_below16 } from '../../../common/constants/runtime';
10
10
  import { nullable, numeric, getAddStringContext, addCustomAttributes } from '../../../common/serialize/bel-serializer';
11
11
  import { mapOwn } from '../../../common/util/map-own';
12
12
  import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
@@ -232,9 +232,7 @@ export class Aggregate extends AggregateBase {
232
232
  }
233
233
  onHarvestFinished(result) {
234
234
  if (result.retry && this.timingsSent.length > 0) {
235
- for (var i = 0; i < this.timingsSent.length; i++) {
236
- this.timings.push(this.timingsSent[i]);
237
- }
235
+ this.timings.unshift(...this.timingsSent);
238
236
  this.timingsSent = [];
239
237
  }
240
238
  }
@@ -9,7 +9,7 @@ import { windowAddEventListener } from '../../../common/event-listener/event-lis
9
9
  import { now } from '../../../common/timing/now';
10
10
  import { InstrumentBase } from '../../utils/instrument-base';
11
11
  import { FEATURE_NAME } from '../constants';
12
- import { isBrowserScope } from '../../../common/util/global-scope';
12
+ import { isBrowserScope } from '../../../common/constants/runtime';
13
13
  export class Instrument extends InstrumentBase {
14
14
  static featureName = FEATURE_NAME;
15
15
  constructor(agentIdentifier, aggregator) {
@@ -19,6 +19,7 @@ import { getConfigurationValue, getInfo, getRuntime } from '../../../common/conf
19
19
  import { SESSION_EVENTS, MODE } from '../../../common/session/session-entity';
20
20
  import { AggregateBase } from '../../utils/aggregate-base';
21
21
  import { sharedChannel } from '../../../common/constants/shared-channel';
22
+ import { obj as encodeObj } from '../../../common/url/encode';
22
23
 
23
24
  // would be better to get this dynamically in some way
24
25
  export const RRWEB_VERSION = '2.0.0-alpha.8';
@@ -29,8 +30,12 @@ let recorder, gzipper, u8;
29
30
  export const MAX_PAYLOAD_SIZE = 1000000;
30
31
  /** Unloading caps around 64kb */
31
32
  export const IDEAL_PAYLOAD_SIZE = 64000;
32
- /** Interval between forcing new full snapshots in "error" mode */
33
- const CHECKOUT_MS = 30000;
33
+ /** Interval between forcing new full snapshots -- 30 seconds in error mode, 5 minutes in full mode */
34
+ const CHECKOUT_MS = {
35
+ [MODE.ERROR]: 30000,
36
+ [MODE.FULL]: 300000,
37
+ [MODE.OFF]: 0
38
+ };
34
39
  export class Aggregate extends AggregateBase {
35
40
  static featureName = FEATURE_NAME;
36
41
  constructor(agentIdentifier, aggregator) {
@@ -62,6 +67,12 @@ export class Aggregate extends AggregateBase {
62
67
  /** Payload metadata -- Should indicate that the payload being sent contains an error. Used for query/filter purposes in UI */
63
68
  this.hasError = false;
64
69
 
70
+ /** Payload metadata -- Should indicate when a replay blob started recording. Resets each time a harvest occurs. */
71
+ this.timestamp = {
72
+ first: undefined,
73
+ last: undefined
74
+ };
75
+
65
76
  /** A value which increments with every new mutation node reported. Resets after a harvest is sent */
66
77
  this.payloadBytesEstimation = 0;
67
78
  const shouldSetup = getConfigurationValue(agentIdentifier, 'privacy.cookies_enabled') === true && getConfigurationValue(agentIdentifier, 'session_trace.enabled') === true;
@@ -85,7 +96,7 @@ export class Aggregate extends AggregateBase {
85
96
  });
86
97
 
87
98
  // Bespoke logic for new endpoint. This will change as downstream dependencies become solidified.
88
- this.scheduler = new HarvestScheduler('blob', {
99
+ this.scheduler = new HarvestScheduler('browser/blobs', {
89
100
  onFinished: this.onHarvestFinished.bind(this),
90
101
  retryDelay: this.harvestTimeSeconds,
91
102
  getPayload: this.prepareHarvest.bind(this),
@@ -105,10 +116,9 @@ export class Aggregate extends AggregateBase {
105
116
  this.stopRecording();
106
117
  this.startRecording();
107
118
  this.scheduler.startTimer(this.harvestTimeSeconds);
108
- const {
109
- session
110
- } = getRuntime(this.agentIdentifier);
111
- session.state.sessionReplay = this.mode;
119
+ this.syncWithSessionManager({
120
+ sessionReplay: this.mode
121
+ });
112
122
  }
113
123
  }
114
124
  }, this.featureName, this.ee);
@@ -181,17 +191,18 @@ export class Aggregate extends AggregateBase {
181
191
  }
182
192
  this.startRecording();
183
193
  this.isFirstChunk = !!session.isNew;
184
- session.state.sessionReplay = this.mode;
194
+ this.syncWithSessionManager({
195
+ sessionReplay: this.mode
196
+ });
185
197
  }
186
198
  prepareHarvest() {
187
- if (this.events.length === 0) return;
199
+ if (this.events.length === 0 || this.mode !== MODE.FULL && !this.blocked) return;
188
200
  const payload = this.getHarvestContents();
189
201
  if (this.shouldCompress) {
190
202
  payload.body = gzipper(u8(stringify(payload.body)));
191
203
  this.scheduler.opts.gzip = true;
192
204
  } else {
193
205
  this.scheduler.opts.gzip = false;
194
- delete payload.qs.content_encoding;
195
206
  }
196
207
  // TODO -- Gracefully handle the buffer for retries.
197
208
  this.clearBuffer();
@@ -202,25 +213,28 @@ export class Aggregate extends AggregateBase {
202
213
  const info = getInfo(this.agentIdentifier);
203
214
  return {
204
215
  qs: {
205
- protocol_version: '0',
206
- content_encoding: 'gzip',
207
- browser_monitoring_key: info.licenseKey
208
- },
209
- body: {
216
+ browser_monitoring_key: info.licenseKey,
210
217
  type: 'SessionReplay',
211
- appId: Number(info.applicationID),
212
- timestamp: Date.now(),
213
- blob: JSON.stringify(this.events),
214
- // this needs to be a stringified JSON array of rrweb nodes
215
- attributes: {
218
+ app_id: info.applicationID,
219
+ protocol_version: '0',
220
+ attributes: encodeObj({
221
+ ...(this.shouldCompress && {
222
+ content_encoding: 'gzip'
223
+ }),
224
+ 'replay.firstTimestamp': this.timestamp.first,
225
+ 'replay.lastTimestamp': this.timestamp.last,
226
+ 'replay.durationMs': this.timestamp.last - this.timestamp.first,
227
+ agentVersion: agentRuntime.version,
216
228
  session: agentRuntime.session.state.value,
217
229
  hasSnapshot: this.hasSnapshot,
218
230
  hasError: this.hasError,
219
- agentVersion: agentRuntime.version,
220
231
  isFirstChunk: this.isFirstChunk,
232
+ decompressedBytes: this.payloadBytesEstimation,
221
233
  'nr.rrweb.version': RRWEB_VERSION
222
- }
223
- }
234
+ }, MAX_PAYLOAD_SIZE - this.payloadBytesEstimation).substring(1) // remove the leading '&'
235
+ },
236
+
237
+ body: this.events
224
238
  };
225
239
  }
226
240
  onHarvestFinished(result) {
@@ -238,6 +252,7 @@ export class Aggregate extends AggregateBase {
238
252
  this.hasSnapshot = false;
239
253
  this.hasError = false;
240
254
  this.payloadBytesEstimation = 0;
255
+ this.clearTimestamps();
241
256
  }
242
257
 
243
258
  /** Begin recording using configured recording lib */
@@ -246,6 +261,7 @@ export class Aggregate extends AggregateBase {
246
261
  warn('Recording library was never imported');
247
262
  return this.abort();
248
263
  }
264
+ this.recording = true;
249
265
  const {
250
266
  blockClass,
251
267
  ignoreClass,
@@ -255,7 +271,6 @@ export class Aggregate extends AggregateBase {
255
271
  maskTextSelector,
256
272
  maskAllInputs
257
273
  } = getConfigurationValue(this.agentIdentifier, 'session_replay');
258
- this.hasSnapshot = true;
259
274
  // set up rrweb configurations for maximum privacy --
260
275
  // https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
261
276
  const stop = recorder({
@@ -267,11 +282,8 @@ export class Aggregate extends AggregateBase {
267
282
  maskInputOptions,
268
283
  maskTextSelector,
269
284
  maskAllInputs,
270
- ...(this.mode === MODE.ERROR && {
271
- checkoutEveryNms: CHECKOUT_MS
272
- })
285
+ checkoutEveryNms: CHECKOUT_MS[this.mode]
273
286
  });
274
- this.recording = true;
275
287
  this.stopRecording = () => {
276
288
  this.recording = false;
277
289
  stop();
@@ -296,12 +308,14 @@ export class Aggregate extends AggregateBase {
296
308
  // we are still waiting for an error to throw, so keep wiping the buffer over time
297
309
  this.clearBuffer();
298
310
  }
311
+ this.setTimestamps(event);
312
+ if (event.type === 2) this.hasSnapshot = true;
299
313
  this.events.push(event);
300
314
  this.payloadBytesEstimation += eventBytes;
301
315
 
302
316
  // We are making an effort to try to keep payloads manageable for unloading. If they reach the unload limit before their interval,
303
317
  // it will send immediately. This often happens on the first snapshot, which can be significantly larger than the other payloads.
304
- if (payloadSize > IDEAL_PAYLOAD_SIZE) {
318
+ if (payloadSize > IDEAL_PAYLOAD_SIZE && this.mode !== MODE.ERROR) {
305
319
  // if we've made it to the ideal size of ~64kb before the interval timer, we should send early.
306
320
  this.scheduler.runHarvest();
307
321
  }
@@ -311,7 +325,17 @@ export class Aggregate extends AggregateBase {
311
325
  takeFullSnapshot() {
312
326
  if (!recorder) return;
313
327
  recorder.takeFullSnapshot();
314
- this.hasSnapshot = true;
328
+ }
329
+ setTimestamps(rrwebEvent) {
330
+ if (!rrwebEvent) return;
331
+ if (!this.timestamp.first) this.timestamp.first = rrwebEvent.timestamp;
332
+ this.timestamp.last = rrwebEvent.timestamp;
333
+ }
334
+ clearTimestamps() {
335
+ this.timestamp = {
336
+ first: undefined,
337
+ last: undefined
338
+ };
315
339
  }
316
340
 
317
341
  /** Estimate the payload size */
@@ -326,11 +350,11 @@ export class Aggregate extends AggregateBase {
326
350
  this.blocked = true;
327
351
  this.mode = MODE.OFF;
328
352
  this.stopRecording();
353
+ this.syncWithSessionManager({
354
+ sessionReplay: this.mode
355
+ });
356
+ this.clearTimestamps();
329
357
  this.ee.emit('REPLAY_ABORTED');
330
- const {
331
- session
332
- } = getRuntime(this.agentIdentifier);
333
- session.state.sessionReplay = this.mode;
334
358
  }
335
359
 
336
360
  /** Extensive research has yielded about an 88% compression factor on these payloads.
@@ -341,4 +365,11 @@ export class Aggregate extends AggregateBase {
341
365
  if (this.shouldCompress) return data * AVG_COMPRESSION;
342
366
  return data;
343
367
  }
368
+ syncWithSessionManager() {
369
+ let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
370
+ const {
371
+ session
372
+ } = getRuntime(this.agentIdentifier);
373
+ session.write(state);
374
+ }
344
375
  }
@@ -15,8 +15,8 @@ export async function getSessionReplayMode(agentId) {
15
15
  const newrelic = gosNREUM();
16
16
  // Should be enabled by configuration and using an agent build that includes it (via checking that the instrument class was initialized).
17
17
  if (getConfigurationValue(agentId, 'session_replay.enabled') && typeof newrelic.initializedAgents[agentId].features.session_replay === 'object') {
18
- await newrelic.initializedAgents[agentId].features.session_replay.onAggregateImported; // if Replay could not initialize, this throws a (uncaught) rejection
19
- return await sharedChannel.sessionReplayInitialized; // wait for replay to determine which mode it's after running its sampling logic
18
+ const srInitialized = await newrelic.initializedAgents[agentId].features.session_replay.onAggregateImported;
19
+ if (srInitialized) return await sharedChannel.sessionReplayInitialized; // wait for replay to determine which mode it's after running its sampling logic
20
20
  }
21
21
  } catch (e) {/* exception ==> off */}
22
22
  return MODE.OFF; // at any step of the way s.t. SR cannot be on by implication or is explicitly off
@@ -109,8 +109,8 @@ export class Aggregate extends AggregateBase {
109
109
  sessionTraceMode: MODE.OFF
110
110
  });
111
111
  operationalGate.permanentlyDecide(false);
112
- this.#scheduler?.stopTimer(true);
113
112
  if (mostRecentModeKnown === MODE.FULL) this.#scheduler?.runHarvest(); // allow queued nodes (past opGate) to final harvest, unless they were buffered in other modes
113
+ this.#scheduler?.stopTimer(true); // the 'true' arg here will forcibly block any future call to runHarvest, so the last runHarvest above must be prior
114
114
  this.#scheduler = null;
115
115
  };
116
116
 
@@ -136,9 +136,8 @@ export class Aggregate extends AggregateBase {
136
136
  this.ee.on(SESSION_EVENTS.PAUSE, () => mostRecentModeKnown = sessionEntity.state.sessionTraceMode);
137
137
  if (!sessionEntity.isNew) {
138
138
  // inherit the same mode as existing session's Trace
139
- const existingTraceMode = mostRecentModeKnown = sessionEntity.state.sessionTraceMode;
140
- if (existingTraceMode === MODE.OFF) this.isStandalone = true;
141
- controlTraceOp(existingTraceMode);
139
+ if (sessionEntity.state.sessionReplay === MODE.OFF) this.isStandalone = true;
140
+ controlTraceOp(mostRecentModeKnown = sessionEntity.state.sessionTraceMode);
142
141
  } else {
143
142
  // for new sessions, see the truth table associated with NEWRELIC-8662 wrt the new Trace behavior under session management
144
143
  const replayMode = await getSessionReplayMode(agentIdentifier);
@@ -8,7 +8,7 @@ import { now } from '../../../common/timing/now';
8
8
  import { InstrumentBase } from '../../utils/instrument-base';
9
9
  import * as CONSTANTS from '../constants';
10
10
  import { FEATURE_NAMES } from '../../../loaders/features/features';
11
- import { isBrowserScope } from '../../../common/util/global-scope';
11
+ import { isBrowserScope } from '../../../common/constants/runtime';
12
12
  const {
13
13
  BST_RESOURCE,
14
14
  RESOURCE,
@@ -619,7 +619,7 @@ export class Aggregate extends AggregateBase {
619
619
  function onHarvestFinished(result) {
620
620
  if (result.sent && result.retry && state.interactionsSent.length > 0) {
621
621
  state.interactionsSent.forEach(function (interaction) {
622
- state.interactionsToHarvest.push(interaction);
622
+ state.interactionsToHarvest.unshift(interaction);
623
623
  });
624
624
  state.interactionsSent = [];
625
625
  }
@@ -8,7 +8,7 @@ import { InstrumentBase } from '../../utils/instrument-base';
8
8
  import { getRuntime } from '../../../common/config/config';
9
9
  import { now } from '../../../common/timing/now';
10
10
  import * as CONSTANTS from '../constants';
11
- import { isBrowserScope } from '../../../common/util/global-scope';
11
+ import { isBrowserScope } from '../../../common/constants/runtime';
12
12
  const {
13
13
  FEATURE_NAME,
14
14
  START,