@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
@@ -40,6 +40,14 @@ const agentIdentifier = 'abcd'
40
40
  const info = { licenseKey: 1234, applicationID: 9876 }
41
41
  const init = { session_replay: { enabled: true, sampleRate: 1, errorSampleRate: 0 } }
42
42
 
43
+ const anyQuery = {
44
+ browser_monitoring_key: info.licenseKey,
45
+ type: 'SessionReplay',
46
+ app_id: Number(info.applicationID),
47
+ protocol_version: '0',
48
+ attributes: expect.any(String)
49
+ }
50
+
43
51
  describe('Session Replay', () => {
44
52
  beforeEach(async () => {
45
53
  primeSessionAndReplay()
@@ -221,28 +229,11 @@ describe('Session Replay', () => {
221
229
  await wait(1)
222
230
  const harvestContents = sr.getHarvestContents()
223
231
  // query attrs
224
- expect(harvestContents.qs).toMatchObject({
225
- protocol_version: '0',
226
- content_encoding: 'gzip',
227
- browser_monitoring_key: info.licenseKey
228
- })
232
+ expect(harvestContents.qs).toMatchObject(anyQuery)
229
233
 
230
- expect(harvestContents.body).toMatchObject({
231
- type: 'SessionReplay',
232
- appId: info.applicationID,
233
- timestamp: expect.any(Number),
234
- blob: expect.any(String),
235
- attributes: {
236
- session: session.state.value,
237
- hasSnapshot: expect.any(Boolean),
238
- hasError: expect.any(Boolean),
239
- agentVersion: expect.any(String),
240
- isFirstChunk: expect.any(Boolean),
241
- 'nr.rrweb.version': expect.any(String)
242
- }
243
- })
234
+ expect(harvestContents.body).toEqual(expect.any(Array))
244
235
 
245
- expect(JSON.parse(harvestContents.body.blob).length).toBeGreaterThan(0)
236
+ expect(harvestContents.body.length).toBeGreaterThan(0)
246
237
  })
247
238
  })
248
239
 
@@ -253,26 +244,10 @@ describe('Session Replay', () => {
253
244
  sr.ee.emit('rumresp-sr', [true])
254
245
  await wait(1)
255
246
  const [harvestContents] = sr.prepareHarvest()
256
- expect(harvestContents.qs).toMatchObject({
257
- protocol_version: '0',
258
- content_encoding: 'gzip',
259
- browser_monitoring_key: info.licenseKey
260
- })
247
+ expect(harvestContents.qs).toMatchObject(anyQuery)
248
+ expect(harvestContents.qs.attributes.includes('content_encoding=gzip')).toEqual(true)
261
249
  expect(harvestContents.body).toEqual(expect.any(Uint8Array))
262
- expect(JSON.parse(strFromU8(gunzipSync(harvestContents.body)))).toMatchObject({
263
- type: 'SessionReplay',
264
- appId: info.applicationID,
265
- timestamp: expect.any(Number),
266
- blob: expect.any(String),
267
- attributes: {
268
- session: session.state.value,
269
- hasSnapshot: expect.any(Boolean),
270
- hasError: expect.any(Boolean),
271
- agentVersion: expect.any(String),
272
- isFirstChunk: expect.any(Boolean),
273
- 'nr.rrweb.version': expect.any(String)
274
- }
275
- })
250
+ expect(JSON.parse(strFromU8(gunzipSync(harvestContents.body)))).toMatchObject(expect.any(Array))
276
251
  })
277
252
 
278
253
  test('Uncompressed payload is provided to harvester', async () => {
@@ -289,24 +264,10 @@ describe('Session Replay', () => {
289
264
  const [harvestContents] = sr.prepareHarvest()
290
265
  expect(harvestContents.qs).toMatchObject({
291
266
  protocol_version: '0',
292
- // content_encoding is omitted when the payload is not compressed
293
267
  browser_monitoring_key: info.licenseKey
294
268
  })
295
- expect(harvestContents.qs.content_encoding).toBeUndefined()
296
- expect(harvestContents.body).toMatchObject({
297
- type: 'SessionReplay',
298
- appId: info.applicationID,
299
- timestamp: expect.any(Number),
300
- blob: expect.any(String),
301
- attributes: {
302
- session: session.state.value,
303
- hasSnapshot: expect.any(Boolean),
304
- hasError: expect.any(Boolean),
305
- agentVersion: expect.any(String),
306
- isFirstChunk: expect.any(Boolean),
307
- 'nr.rrweb.version': expect.any(String)
308
- }
309
- })
269
+ expect(harvestContents.qs.attributes.includes('content_encoding')).toEqual(false)
270
+ expect(harvestContents.body).toEqual(expect.any(Array))
310
271
  })
311
272
 
312
273
  test('Clears the event buffer when staged for harvesting', async () => {
@@ -363,6 +324,6 @@ function wait (ms = 0) {
363
324
 
364
325
  function primeSessionAndReplay (sess = new SessionEntity({ agentIdentifier, key: 'SESSION', storage: new LocalMemory() })) {
365
326
  session = sess
366
- configure(agentIdentifier, { info, runtime: { session } }, 'test', true)
327
+ configure(agentIdentifier, { info, runtime: { session }, init: {} }, 'test', true)
367
328
  sr = new SessionReplayAgg(agentIdentifier, new Aggregator({}))
368
329
  }
@@ -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'
@@ -31,8 +32,8 @@ let recorder, gzipper, u8
31
32
  export const MAX_PAYLOAD_SIZE = 1000000
32
33
  /** Unloading caps around 64kb */
33
34
  export const IDEAL_PAYLOAD_SIZE = 64000
34
- /** Interval between forcing new full snapshots in "error" mode */
35
- const CHECKOUT_MS = 30000
35
+ /** Interval between forcing new full snapshots -- 30 seconds in error mode, 5 minutes in full mode */
36
+ const CHECKOUT_MS = { [MODE.ERROR]: 30000, [MODE.FULL]: 300000, [MODE.OFF]: 0 }
36
37
 
37
38
  export class Aggregate extends AggregateBase {
38
39
  static featureName = FEATURE_NAME
@@ -65,6 +66,9 @@ export class Aggregate extends AggregateBase {
65
66
  /** Payload metadata -- Should indicate that the payload being sent contains an error. Used for query/filter purposes in UI */
66
67
  this.hasError = false
67
68
 
69
+ /** Payload metadata -- Should indicate when a replay blob started recording. Resets each time a harvest occurs. */
70
+ this.timestamp = { first: undefined, last: undefined }
71
+
68
72
  /** A value which increments with every new mutation node reported. Resets after a harvest is sent */
69
73
  this.payloadBytesEstimation = 0
70
74
 
@@ -91,7 +95,7 @@ export class Aggregate extends AggregateBase {
91
95
  })
92
96
 
93
97
  // Bespoke logic for new endpoint. This will change as downstream dependencies become solidified.
94
- this.scheduler = new HarvestScheduler('blob', {
98
+ this.scheduler = new HarvestScheduler('browser/blobs', {
95
99
  onFinished: this.onHarvestFinished.bind(this),
96
100
  retryDelay: this.harvestTimeSeconds,
97
101
  getPayload: this.prepareHarvest.bind(this),
@@ -112,8 +116,7 @@ export class Aggregate extends AggregateBase {
112
116
  this.startRecording()
113
117
  this.scheduler.startTimer(this.harvestTimeSeconds)
114
118
 
115
- const { session } = getRuntime(this.agentIdentifier)
116
- session.state.sessionReplay = this.mode
119
+ this.syncWithSessionManager({ sessionReplay: this.mode })
117
120
  }
118
121
  }
119
122
  }, this.featureName, this.ee)
@@ -187,11 +190,11 @@ export class Aggregate extends AggregateBase {
187
190
 
188
191
  this.isFirstChunk = !!session.isNew
189
192
 
190
- session.state.sessionReplay = this.mode
193
+ this.syncWithSessionManager({ sessionReplay: this.mode })
191
194
  }
192
195
 
193
196
  prepareHarvest () {
194
- if (this.events.length === 0) return
197
+ if (this.events.length === 0 || (this.mode !== MODE.FULL && !this.blocked)) return
195
198
  const payload = this.getHarvestContents()
196
199
 
197
200
  if (this.shouldCompress) {
@@ -199,7 +202,6 @@ export class Aggregate extends AggregateBase {
199
202
  this.scheduler.opts.gzip = true
200
203
  } else {
201
204
  this.scheduler.opts.gzip = false
202
- delete payload.qs.content_encoding
203
205
  }
204
206
  // TODO -- Gracefully handle the buffer for retries.
205
207
  this.clearBuffer()
@@ -211,24 +213,25 @@ export class Aggregate extends AggregateBase {
211
213
  const info = getInfo(this.agentIdentifier)
212
214
  return {
213
215
  qs: {
214
- protocol_version: '0',
215
- content_encoding: 'gzip',
216
- browser_monitoring_key: info.licenseKey
217
- },
218
- body: {
216
+ browser_monitoring_key: info.licenseKey,
219
217
  type: 'SessionReplay',
220
- appId: Number(info.applicationID),
221
- timestamp: Date.now(),
222
- blob: JSON.stringify(this.events), // this needs to be a stringified JSON array of rrweb nodes
223
- attributes: {
218
+ app_id: info.applicationID,
219
+ protocol_version: '0',
220
+ attributes: encodeObj({
221
+ ...(this.shouldCompress && { content_encoding: 'gzip' }),
222
+ 'replay.firstTimestamp': this.timestamp.first,
223
+ 'replay.lastTimestamp': this.timestamp.last,
224
+ 'replay.durationMs': this.timestamp.last - this.timestamp.first,
225
+ agentVersion: agentRuntime.version,
224
226
  session: agentRuntime.session.state.value,
225
227
  hasSnapshot: this.hasSnapshot,
226
228
  hasError: this.hasError,
227
- agentVersion: agentRuntime.version,
228
229
  isFirstChunk: this.isFirstChunk,
230
+ decompressedBytes: this.payloadBytesEstimation,
229
231
  'nr.rrweb.version': RRWEB_VERSION
230
- }
231
- }
232
+ }, MAX_PAYLOAD_SIZE - this.payloadBytesEstimation).substring(1) // remove the leading '&'
233
+ },
234
+ body: this.events
232
235
  }
233
236
  }
234
237
 
@@ -248,6 +251,7 @@ export class Aggregate extends AggregateBase {
248
251
  this.hasSnapshot = false
249
252
  this.hasError = false
250
253
  this.payloadBytesEstimation = 0
254
+ this.clearTimestamps()
251
255
  }
252
256
 
253
257
  /** Begin recording using configured recording lib */
@@ -256,8 +260,8 @@ export class Aggregate extends AggregateBase {
256
260
  warn('Recording library was never imported')
257
261
  return this.abort()
258
262
  }
263
+ this.recording = true
259
264
  const { blockClass, ignoreClass, maskTextClass, blockSelector, maskInputOptions, maskTextSelector, maskAllInputs } = getConfigurationValue(this.agentIdentifier, 'session_replay')
260
- this.hasSnapshot = true
261
265
  // set up rrweb configurations for maximum privacy --
262
266
  // https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
263
267
  const stop = recorder({
@@ -269,11 +273,9 @@ export class Aggregate extends AggregateBase {
269
273
  maskInputOptions,
270
274
  maskTextSelector,
271
275
  maskAllInputs,
272
- ...(this.mode === MODE.ERROR && { checkoutEveryNms: CHECKOUT_MS })
276
+ checkoutEveryNms: CHECKOUT_MS[this.mode]
273
277
  })
274
278
 
275
- this.recording = true
276
-
277
279
  this.stopRecording = () => {
278
280
  this.recording = false
279
281
  stop()
@@ -299,12 +301,15 @@ export class Aggregate extends AggregateBase {
299
301
  this.clearBuffer()
300
302
  }
301
303
 
304
+ this.setTimestamps(event)
305
+ if (event.type === 2) this.hasSnapshot = true
306
+
302
307
  this.events.push(event)
303
308
  this.payloadBytesEstimation += eventBytes
304
309
 
305
310
  // We are making an effort to try to keep payloads manageable for unloading. If they reach the unload limit before their interval,
306
311
  // it will send immediately. This often happens on the first snapshot, which can be significantly larger than the other payloads.
307
- if (payloadSize > IDEAL_PAYLOAD_SIZE) {
312
+ if (payloadSize > IDEAL_PAYLOAD_SIZE && this.mode !== MODE.ERROR) {
308
313
  // if we've made it to the ideal size of ~64kb before the interval timer, we should send early.
309
314
  this.scheduler.runHarvest()
310
315
  }
@@ -314,7 +319,16 @@ export class Aggregate extends AggregateBase {
314
319
  takeFullSnapshot () {
315
320
  if (!recorder) return
316
321
  recorder.takeFullSnapshot()
317
- this.hasSnapshot = true
322
+ }
323
+
324
+ setTimestamps (rrwebEvent) {
325
+ if (!rrwebEvent) return
326
+ if (!this.timestamp.first) this.timestamp.first = rrwebEvent.timestamp
327
+ this.timestamp.last = rrwebEvent.timestamp
328
+ }
329
+
330
+ clearTimestamps () {
331
+ this.timestamp = { first: undefined, last: undefined }
318
332
  }
319
333
 
320
334
  /** Estimate the payload size */
@@ -328,9 +342,9 @@ export class Aggregate extends AggregateBase {
328
342
  this.blocked = true
329
343
  this.mode = MODE.OFF
330
344
  this.stopRecording()
345
+ this.syncWithSessionManager({ sessionReplay: this.mode })
346
+ this.clearTimestamps()
331
347
  this.ee.emit('REPLAY_ABORTED')
332
- const { session } = getRuntime(this.agentIdentifier)
333
- session.state.sessionReplay = this.mode
334
348
  }
335
349
 
336
350
  /** Extensive research has yielded about an 88% compression factor on these payloads.
@@ -341,4 +355,9 @@ export class Aggregate extends AggregateBase {
341
355
  if (this.shouldCompress) return data * AVG_COMPRESSION
342
356
  return data
343
357
  }
358
+
359
+ syncWithSessionManager (state = {}) {
360
+ const { session } = getRuntime(this.agentIdentifier)
361
+ session.write(state)
362
+ }
344
363
  }
@@ -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
@@ -97,8 +97,8 @@ export class Aggregate extends AggregateBase {
97
97
  const stopTracePerm = () => {
98
98
  if (sessionEntity.state.sessionTraceMode !== MODE.OFF) sessionEntity.write({ sessionTraceMode: MODE.OFF })
99
99
  operationalGate.permanentlyDecide(false)
100
- this.#scheduler?.stopTimer(true)
101
100
  if (mostRecentModeKnown === MODE.FULL) this.#scheduler?.runHarvest() // allow queued nodes (past opGate) to final harvest, unless they were buffered in other modes
101
+ this.#scheduler?.stopTimer(true) // the 'true' arg here will forcibly block any future call to runHarvest, so the last runHarvest above must be prior
102
102
  this.#scheduler = null
103
103
  }
104
104
 
@@ -122,9 +122,8 @@ export class Aggregate extends AggregateBase {
122
122
  this.ee.on(SESSION_EVENTS.PAUSE, () => mostRecentModeKnown = sessionEntity.state.sessionTraceMode)
123
123
 
124
124
  if (!sessionEntity.isNew) { // inherit the same mode as existing session's Trace
125
- const existingTraceMode = mostRecentModeKnown = sessionEntity.state.sessionTraceMode
126
- if (existingTraceMode === MODE.OFF) this.isStandalone = true
127
- controlTraceOp(existingTraceMode)
125
+ if (sessionEntity.state.sessionReplay === MODE.OFF) this.isStandalone = true
126
+ controlTraceOp(mostRecentModeKnown = sessionEntity.state.sessionTraceMode)
128
127
  } else { // for new sessions, see the truth table associated with NEWRELIC-8662 wrt the new Trace behavior under session management
129
128
  const replayMode = await getSessionReplayMode(agentIdentifier)
130
129
  if (replayMode === MODE.OFF) this.isStandalone = true // without SR, Traces are still subject to old harvest limits
@@ -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
 
13
13
  const {
14
14
  BST_RESOURCE, RESOURCE, START, END, FEATURE_NAME, FN_END, FN_START, PUSH_STATE
@@ -674,7 +674,7 @@ export class Aggregate extends AggregateBase {
674
674
  function onHarvestFinished (result) {
675
675
  if (result.sent && result.retry && state.interactionsSent.length > 0) {
676
676
  state.interactionsSent.forEach(function (interaction) {
677
- state.interactionsToHarvest.push(interaction)
677
+ state.interactionsToHarvest.unshift(interaction)
678
678
  })
679
679
  state.interactionsSent = []
680
680
  }
@@ -10,7 +10,7 @@ import { InstrumentBase } from '../../utils/instrument-base'
10
10
  import { getRuntime } from '../../../common/config/config'
11
11
  import { now } from '../../../common/timing/now'
12
12
  import * as CONSTANTS from '../constants'
13
- import { isBrowserScope } from '../../../common/util/global-scope'
13
+ import { isBrowserScope } from '../../../common/constants/runtime'
14
14
 
15
15
  const {
16
16
  FEATURE_NAME, START, END, BODY, CB_END, JS_TIME, FETCH, FN_START, CB_START, FN_END
@@ -35,7 +35,7 @@ beforeEach(() => {
35
35
  __esModule: true,
36
36
  registerHandler: jest.fn()
37
37
  }))
38
- jest.doMock('../../common/util/global-scope', () => ({
38
+ jest.doMock('../../common/constants/runtime', () => ({
39
39
  __esModule: true,
40
40
  isBrowserScope: true
41
41
  }))
@@ -161,7 +161,7 @@ test('should set custom session data', async () => {
161
161
  })
162
162
 
163
163
  test('should not set custom session data in worker scope', async () => {
164
- const globalScope = await import('../../common/util/global-scope')
164
+ const globalScope = await import('../../common/constants/runtime')
165
165
  jest.replaceProperty(globalScope, 'isBrowserScope', false)
166
166
 
167
167
  const { setInfo } = await import('../../common/config/config')
@@ -7,10 +7,10 @@
7
7
  import { drain, registerDrain } from '../../common/drain/drain'
8
8
  import { FeatureBase } from './feature-base'
9
9
  import { onWindowLoad } from '../../common/window/load'
10
- import { isBrowserScope } from '../../common/util/global-scope'
10
+ import { isBrowserScope } from '../../common/constants/runtime'
11
11
  import { warn } from '../../common/util/console'
12
12
  import { FEATURE_NAMES } from '../../loaders/features/features'
13
- import { getConfigurationValue } from '../../common/config/config'
13
+ import { getConfigurationValue, originals } from '../../common/config/config'
14
14
 
15
15
  /**
16
16
  * Base class for instrumenting a feature.
@@ -55,9 +55,9 @@ export class InstrumentBase extends FeatureBase {
55
55
  importAggregator (argsObjFromInstrument = {}) {
56
56
  if (this.featAggregate || !this.auto) return
57
57
  const enableSessionTracking = isBrowserScope && getConfigurationValue(this.agentIdentifier, 'privacy.cookies_enabled') === true
58
- let loadedSuccessfully, loadFailed
59
- this.onAggregateImported = new Promise((resolve, reject) => {
60
- loadedSuccessfully = resolve; loadFailed = reject
58
+ let loadedSuccessfully
59
+ this.onAggregateImported = new Promise(resolve => {
60
+ loadedSuccessfully = resolve
61
61
  })
62
62
 
63
63
  const importLater = async () => {
@@ -78,17 +78,18 @@ export class InstrumentBase extends FeatureBase {
78
78
  try {
79
79
  if (!this.shouldImportAgg(this.featureName, session)) {
80
80
  drain(this.agentIdentifier, this.featureName)
81
+ loadedSuccessfully(false) // aggregate module isn't loaded at all
81
82
  return
82
83
  }
83
84
  const { lazyFeatureLoader } = await import(/* webpackChunkName: "lazy-feature-loader" */ './lazy-feature-loader')
84
85
  const { Aggregate } = await lazyFeatureLoader(this.featureName, 'aggregate')
85
86
  this.featAggregate = new Aggregate(this.agentIdentifier, this.aggregator, argsObjFromInstrument)
86
- loadedSuccessfully()
87
+ loadedSuccessfully(true)
87
88
  } catch (e) {
88
89
  warn(`Downloading and initializing ${this.featureName} failed...`, e)
89
90
  this.abortHandler?.() // undo any important alterations made to the page
90
91
  // not supported yet but nice to do: "abort" this agent's EE for this feature specifically
91
- loadFailed()
92
+ loadedSuccessfully(false)
92
93
  }
93
94
  }
94
95
 
@@ -105,15 +106,11 @@ export class InstrumentBase extends FeatureBase {
105
106
  * @returns
106
107
  */
107
108
  shouldImportAgg (featureName, session) {
108
- // if this isnt the FIRST load of a session AND
109
- // we are not actively recording SR... DO NOT run the aggregator
110
- // session replay samples can only be decided on the first load of a session
111
- // session replays can continue if in progress
112
109
  if (featureName === FEATURE_NAMES.sessionReplay) {
113
- if (getConfigurationValue(this.agentIdentifier, 'session_trace.enabled') === false) return false
114
- return !!session?.isNew || !!session?.state.sessionReplay
110
+ if (!originals.MO) return false // Session Replay cannot work without Mutation Observer
111
+ if (getConfigurationValue(this.agentIdentifier, 'session_trace.enabled') === false) return false // Session Replay as of now is tightly coupled with Session Trace in the UI
112
+ return !!session?.isNew || !!session?.state.sessionReplay // Session Replay should only try to run if already running from a previous page, or at the beginning of a session
115
113
  }
116
- // todo -- add case like above for session trace
117
114
  return true
118
115
  }
119
116
  }
@@ -7,7 +7,7 @@ import { lazyFeatureLoader } from './lazy-feature-loader'
7
7
  import { getConfigurationValue } from '../../common/config/config'
8
8
  import { setupAgentSession } from './agent-session'
9
9
  import { warn } from '../../common/util/console'
10
- import * as globalScopeModule from '../../common/util/global-scope'
10
+ import * as globalScopeModule from '../../common/constants/runtime'
11
11
  import { FEATURE_NAMES } from '../../loaders/features/features'
12
12
 
13
13
  jest.enableAutomock()
@@ -22,7 +22,7 @@ jest.mock('../../common/window/load', () => ({
22
22
  __esModule: true,
23
23
  onWindowLoad: jest.fn()
24
24
  }))
25
- jest.mock('../../common/util/global-scope', () => ({
25
+ jest.mock('../../common/constants/runtime', () => ({
26
26
  __esModule: true,
27
27
  isBrowserScope: undefined,
28
28
  isWorkerScope: undefined
@@ -31,6 +31,13 @@ jest.mock('../../common/config/config', () => ({
31
31
  __esModule: true,
32
32
  getConfigurationValue: jest.fn()
33
33
  }))
34
+ jest.mock('../../common/config/config', () => ({
35
+ __esModule: true,
36
+ getConfigurationValue: jest.fn(),
37
+ originals: {
38
+ MO: jest.fn()
39
+ }
40
+ }))
34
41
  jest.mock('./feature-base', () => ({
35
42
  __esModule: true,
36
43
  FeatureBase: jest.fn(function (...args) {
@@ -57,7 +64,7 @@ beforeEach(() => {
57
64
  aggregator = {}
58
65
  featureName = faker.datatype.uuid()
59
66
 
60
- mockAggregate = jest.fn(() => { /* noop */ })
67
+ mockAggregate = jest.fn()
61
68
  jest.mocked(lazyFeatureLoader).mockResolvedValue({ Aggregate: mockAggregate })
62
69
  })
63
70
 
@@ -187,4 +194,23 @@ test('feature still imports by default even when setupAgentSession throws an err
187
194
  expect(warn).toHaveBeenCalledWith(expect.stringContaining('A problem occurred when starting up session manager'), expect.any(Error))
188
195
  expect(lazyFeatureLoader).toHaveBeenCalled()
189
196
  expect(mockAggregate).toHaveBeenCalled()
197
+ await expect(instrument.onAggregateImported).resolves.toBe(true)
198
+ })
199
+
200
+ test('no uncaught async exception is thrown when an import fails', async () => {
201
+ jest.mocked(lazyFeatureLoader).mockRejectedValue(new Error('ChunkLoadError')) // () => { throw new Error('ChunkLoadError: loading chunk xxx failed.') })
202
+ const mockOnError = jest.fn()
203
+ global.onerror = mockOnError
204
+
205
+ const instrument = new InstrumentBase(agentIdentifier, aggregator, featureName)
206
+ instrument.abortHandler = jest.fn()
207
+ instrument.importAggregator()
208
+
209
+ const windowLoadCallback = jest.mocked(onWindowLoad).mock.calls[0][0]
210
+ await windowLoadCallback()
211
+
212
+ expect(warn).toHaveBeenNthCalledWith(2, expect.stringContaining(`Downloading and initializing ${featureName} failed`), expect.any(Error))
213
+ expect(instrument.abortHandler).toHaveBeenCalled()
214
+ await expect(instrument.onAggregateImported).resolves.toBe(false)
215
+ expect(mockOnError).not.toHaveBeenCalled()
190
216
  })
package/src/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  export { Agent } from './loaders/agent'
2
2
  export { BrowserAgent } from './loaders/browser-agent'
3
3
  export { WorkerAgent } from './loaders/worker-agent'
4
-
5
- /** IN-PROGRESS -- DOES NOT CURRENTLY WORK CORRECTLY */
6
- // export { MicroAgent } from './loaders/micro-agent'
4
+ export { MicroAgent } from './loaders/micro-agent'
7
5
 
8
6
  export { Ajax } from './features/ajax'
9
7
  export { JSErrors } from './features/jserrors'
@@ -0,0 +1,81 @@
1
+ import { warn } from '../common/util/console'
2
+
3
+ export class AgentBase {
4
+ /**
5
+ * Reports a browser PageAction event along with a name and optional attributes.
6
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addpageaction/}
7
+ * @param {string} name Name or category of the action. Reported as the actionName attribute.
8
+ * @param {object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}. The key is reported as its own PageAction attribute with the specified values.
9
+ */
10
+ addPageAction (name, attributes) {
11
+ warn('Call to agent api addPageAction failed. The session trace feature is not currently initialized.')
12
+ }
13
+
14
+ /**
15
+ * Groups page views to help URL structure or to capture the URL's routing information.
16
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setpageviewname/}
17
+ * @param {string} name The page name you want to use. Use alphanumeric characters.
18
+ * @param {string} [host] Default is http://custom.transaction. Typically set host to your site's domain URI.
19
+ */
20
+ setPageViewName (name, host) {
21
+ warn('Call to agent api setPageViewName failed. The page view feature is not currently initialized.')
22
+ }
23
+
24
+ /**
25
+ * Adds a user-defined attribute name and value to subsequent events on the page.
26
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setcustomattribute/}
27
+ * @param {string} name Name of the attribute. Appears as column in the PageView event. It will also appear as a column in the PageAction event if you are using it.
28
+ * @param {string|number|null} value Value of the attribute. Appears as the value in the named attribute column in the PageView event. It will appear as a column in the PageAction event if you are using it. Custom attribute values cannot be complex objects, only simple types such as Strings and Integers.
29
+ * @param {boolean} [persist] Default false. f set to true, the name-value pair will also be set into the browser's storage API. Then on the following instrumented pages that load within the same session, the pair will be re-applied as a custom attribute.
30
+ */
31
+ setCustomAttribute (name, value, persist) {
32
+ warn('Call to agent api setCustomAttribute failed. The js errors feature is not currently initialized.')
33
+ }
34
+
35
+ /**
36
+ * Identifies a browser error without disrupting your app's operations.
37
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/noticeerror/}
38
+ * @param {Error|string} error Provide a meaningful error message that you can use when analyzing data on browser's JavaScript errors page.
39
+ * @param {object} [customAttributes] An object containing name/value pairs representing custom attributes.
40
+ */
41
+ noticeError (error, customAttributes) {
42
+ warn('Call to agent api noticeError failed. The js errors feature is not currently initialized.')
43
+ }
44
+
45
+ /**
46
+ * Adds a user-defined identifier string to subsequent events on the page.
47
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setuserid/}
48
+ * @param {string|null} value A string identifier for the end-user, useful for tying all browser events to specific users. The value parameter does not have to be unique. If IDs should be unique, the caller is responsible for that validation. Passing a null value unsets any existing user ID.
49
+ */
50
+ setUserId (value) {
51
+ warn('Call to agent api setUserId failed. The js errors feature is not currently initialized.')
52
+ }
53
+
54
+ /**
55
+ * Allows selective ignoring and grouping of known errors that the browser agent captures.
56
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/seterrorhandler/}
57
+ * @param {(error: Error|string) => boolean | { group: string }} callback When an error occurs, the callback is called with the error object as a parameter. The callback will be called with each error, so it is not specific to one error.
58
+ */
59
+ setErrorHandler (callback) {
60
+ warn('Call to agent api setErrorHandler failed. The js errors feature is not currently initialized.')
61
+ }
62
+
63
+ /**
64
+ * Records an additional time point as "finished" in a session trace, and sends the event to New Relic.
65
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/finished/}
66
+ * @param {number} [timeStamp] Defaults to the current time of the call. If used, this marks the time that the page is "finished" according to your own criteria.
67
+ */
68
+ finished (timeStamp) {
69
+ warn('Call to agent api finished failed. The page action feature is not currently initialized.')
70
+ }
71
+
72
+ /**
73
+ * Adds a unique name and ID to identify releases with multiple JavaScript bundles on the same page.
74
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addrelease/}
75
+ * @param {string} name A short description of the component; for example, the name of a project, application, file, or library.
76
+ * @param {string} id The ID or version of this release; for example, a version number, build number from your CI environment, GitHub SHA, GUID, or a hash of the contents.
77
+ */
78
+ addRelease (name, id) {
79
+ warn('Call to agent api addRelease failed. The agent is not currently initialized.')
80
+ }
81
+ }