@newrelic/browser-agent 1.235.0 → 1.236.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 (332) hide show
  1. package/README.md +41 -1
  2. package/dist/cjs/common/config/state/init.js +3 -0
  3. package/dist/cjs/common/config/state/runtime.js +4 -4
  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/event-listener/event-listener-opts.js +3 -3
  8. package/dist/cjs/common/harvest/harvest-scheduler.js +22 -19
  9. package/dist/cjs/common/harvest/harvest.js +163 -144
  10. package/dist/cjs/common/harvest/types.js +54 -0
  11. package/dist/cjs/common/ids/id.js +2 -2
  12. package/dist/cjs/common/ids/unique-id.js +3 -3
  13. package/dist/cjs/common/session/session-entity.js +2 -2
  14. package/dist/cjs/common/timer/interaction-timer.js +2 -2
  15. package/dist/cjs/common/unload/eol.js +10 -11
  16. package/dist/cjs/common/url/canonicalize-url.js +2 -2
  17. package/dist/cjs/common/url/parse-url.js +3 -3
  18. package/dist/cjs/common/url/protocol.js +2 -2
  19. package/dist/cjs/common/util/submit-data.js +58 -76
  20. package/dist/cjs/common/window/nreum.js +14 -14
  21. package/dist/cjs/common/wrap/wrap-events.js +3 -3
  22. package/dist/cjs/common/wrap/wrap-fetch.js +5 -5
  23. package/dist/cjs/common/wrap/wrap-history.js +2 -2
  24. package/dist/cjs/common/wrap/wrap-jsonp.js +2 -2
  25. package/dist/cjs/common/wrap/wrap-mutation.js +2 -2
  26. package/dist/cjs/common/wrap/wrap-promise.js +2 -2
  27. package/dist/cjs/common/wrap/wrap-raf.js +2 -2
  28. package/dist/cjs/common/wrap/wrap-timer.js +4 -4
  29. package/dist/cjs/common/wrap/wrap-xhr.js +3 -3
  30. package/dist/cjs/features/ajax/aggregate/index.js +1 -1
  31. package/dist/cjs/features/ajax/instrument/distributed-tracing.js +2 -2
  32. package/dist/cjs/features/ajax/instrument/index.js +6 -7
  33. package/dist/cjs/features/jserrors/aggregate/index.js +7 -4
  34. package/dist/cjs/features/jserrors/instrument/index.js +4 -4
  35. package/dist/cjs/features/metrics/aggregate/framework-detection.js +2 -2
  36. package/dist/cjs/features/metrics/aggregate/index.js +3 -3
  37. package/dist/cjs/features/page_action/aggregate/index.js +3 -3
  38. package/dist/cjs/features/page_view_event/aggregate/index.js +10 -11
  39. package/dist/cjs/features/page_view_event/instrument/index.js +2 -2
  40. package/dist/cjs/features/page_view_timing/aggregate/index.js +3 -5
  41. package/dist/cjs/features/page_view_timing/instrument/index.js +2 -2
  42. package/dist/cjs/features/session_replay/replay-mode.js +2 -2
  43. package/dist/cjs/features/session_trace/instrument/index.js +2 -2
  44. package/dist/cjs/features/spa/aggregate/index.js +1 -1
  45. package/dist/cjs/features/spa/instrument/index.js +2 -2
  46. package/dist/cjs/features/utils/instrument-base.js +6 -7
  47. package/dist/cjs/index.js +7 -0
  48. package/dist/cjs/loaders/agent.js +7 -0
  49. package/dist/cjs/loaders/api/api.js +2 -2
  50. package/dist/cjs/loaders/api/apiAsync.js +6 -4
  51. package/dist/cjs/loaders/configure/configure.js +2 -2
  52. package/dist/cjs/loaders/micro-agent.js +29 -38
  53. package/dist/esm/common/config/state/init.js +3 -0
  54. package/dist/esm/common/config/state/runtime.js +1 -1
  55. package/dist/esm/common/constants/env.cdn.js +2 -2
  56. package/dist/esm/common/constants/env.npm.js +1 -1
  57. package/dist/esm/common/constants/runtime.js +38 -0
  58. package/dist/esm/common/event-listener/event-listener-opts.js +1 -1
  59. package/dist/esm/common/harvest/harvest-scheduler.js +21 -20
  60. package/dist/esm/common/harvest/harvest.js +160 -142
  61. package/dist/esm/common/harvest/types.js +47 -0
  62. package/dist/esm/common/ids/id.js +1 -1
  63. package/dist/esm/common/ids/unique-id.js +1 -1
  64. package/dist/esm/common/session/session-entity.js +1 -1
  65. package/dist/esm/common/timer/interaction-timer.js +1 -1
  66. package/dist/esm/common/unload/eol.js +1 -2
  67. package/dist/esm/common/url/canonicalize-url.js +1 -1
  68. package/dist/esm/common/url/parse-url.js +1 -1
  69. package/dist/esm/common/url/protocol.js +1 -1
  70. package/dist/esm/common/util/submit-data.js +55 -73
  71. package/dist/esm/common/window/nreum.js +1 -1
  72. package/dist/esm/common/wrap/wrap-events.js +1 -1
  73. package/dist/esm/common/wrap/wrap-fetch.js +1 -1
  74. package/dist/esm/common/wrap/wrap-history.js +1 -1
  75. package/dist/esm/common/wrap/wrap-jsonp.js +1 -1
  76. package/dist/esm/common/wrap/wrap-mutation.js +1 -1
  77. package/dist/esm/common/wrap/wrap-promise.js +1 -1
  78. package/dist/esm/common/wrap/wrap-raf.js +1 -1
  79. package/dist/esm/common/wrap/wrap-timer.js +1 -1
  80. package/dist/esm/common/wrap/wrap-xhr.js +1 -1
  81. package/dist/esm/features/ajax/aggregate/index.js +1 -1
  82. package/dist/esm/features/ajax/instrument/distributed-tracing.js +1 -1
  83. package/dist/esm/features/ajax/instrument/index.js +1 -2
  84. package/dist/esm/features/jserrors/aggregate/index.js +6 -3
  85. package/dist/esm/features/jserrors/instrument/index.js +1 -1
  86. package/dist/esm/features/metrics/aggregate/framework-detection.js +1 -1
  87. package/dist/esm/features/metrics/aggregate/index.js +1 -1
  88. package/dist/esm/features/page_action/aggregate/index.js +1 -1
  89. package/dist/esm/features/page_view_event/aggregate/index.js +1 -2
  90. package/dist/esm/features/page_view_event/instrument/index.js +1 -1
  91. package/dist/esm/features/page_view_timing/aggregate/index.js +2 -4
  92. package/dist/esm/features/page_view_timing/instrument/index.js +1 -1
  93. package/dist/esm/features/session_replay/replay-mode.js +2 -2
  94. package/dist/esm/features/session_trace/instrument/index.js +1 -1
  95. package/dist/esm/features/spa/aggregate/index.js +1 -1
  96. package/dist/esm/features/spa/instrument/index.js +1 -1
  97. package/dist/esm/features/utils/instrument-base.js +4 -5
  98. package/dist/esm/index.js +1 -4
  99. package/dist/esm/loaders/agent.js +7 -0
  100. package/dist/esm/loaders/api/api.js +1 -1
  101. package/dist/esm/loaders/api/apiAsync.js +3 -3
  102. package/dist/esm/loaders/configure/configure.js +1 -1
  103. package/dist/esm/loaders/micro-agent.js +29 -38
  104. package/dist/types/common/config/state/init.d.ts.map +1 -1
  105. package/dist/types/common/constants/runtime.d.ts +29 -0
  106. package/dist/types/common/constants/runtime.d.ts.map +1 -0
  107. package/dist/types/common/harvest/harvest-scheduler.d.ts +1 -1
  108. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  109. package/dist/types/common/harvest/harvest.d.ts +49 -38
  110. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  111. package/dist/types/common/harvest/types.d.ts +100 -0
  112. package/dist/types/common/harvest/types.d.ts.map +1 -0
  113. package/dist/types/common/unload/eol.d.ts.map +1 -1
  114. package/dist/types/common/util/submit-data.d.ts +62 -64
  115. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  116. package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
  117. package/dist/types/features/jserrors/aggregate/index.d.ts +1 -1
  118. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  119. package/dist/types/features/jserrors/instrument/index.d.ts +1 -1
  120. package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
  121. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  122. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  123. package/dist/types/index.d.ts +1 -0
  124. package/dist/types/loaders/agent.d.ts +4 -4
  125. package/dist/types/loaders/agent.d.ts.map +1 -1
  126. package/dist/types/loaders/micro-agent.d.ts +3 -4
  127. package/dist/types/loaders/micro-agent.d.ts.map +1 -1
  128. package/package.json +6 -1
  129. package/src/common/config/__mocks__/config.js +11 -0
  130. package/src/common/config/state/init.js +1 -0
  131. package/src/common/config/state/runtime.js +1 -1
  132. package/src/common/constants/__mocks__/env.js +3 -0
  133. package/src/common/constants/__mocks__/runtime.js +8 -0
  134. package/src/common/constants/env.cdn.test.js +7 -0
  135. package/src/common/constants/env.npm.test.js +7 -0
  136. package/src/common/constants/env.test.js +7 -0
  137. package/src/common/constants/runtime.js +71 -0
  138. package/src/common/constants/runtime.test.js +168 -0
  139. package/src/common/context/__mocks__/shared-context.js +8 -0
  140. package/src/common/event-listener/__mocks__/event-listener-opts.js +7 -0
  141. package/src/common/event-listener/event-listener-opts.js +1 -1
  142. package/src/common/harvest/__mocks__/harvest.js +13 -0
  143. package/src/common/harvest/harvest-scheduler.js +21 -20
  144. package/src/common/harvest/harvest-scheduler.test.js +496 -0
  145. package/src/common/harvest/harvest.js +147 -130
  146. package/src/common/harvest/harvest.test.js +818 -0
  147. package/src/common/harvest/types.js +47 -0
  148. package/src/common/ids/id.js +1 -1
  149. package/src/common/ids/unique-id.js +1 -1
  150. package/src/common/session/__mocks__/session-entity.js +25 -0
  151. package/src/common/session/session-entity.component-test.js +1 -1
  152. package/src/common/session/session-entity.js +1 -1
  153. package/src/common/timer/interaction-timer.js +1 -1
  154. package/src/common/timing/__mocks__/now.js +1 -0
  155. package/src/common/unload/__mocks__/eol.js +1 -0
  156. package/src/common/unload/eol.js +1 -2
  157. package/src/common/url/__mocks__/clean-url.js +1 -0
  158. package/src/common/url/__mocks__/encode.js +7 -0
  159. package/src/common/url/__mocks__/location.js +1 -0
  160. package/src/common/url/canonicalize-url.js +1 -1
  161. package/src/common/url/canonicalize-url.test.js +2 -2
  162. package/src/common/url/parse-url.js +1 -1
  163. package/src/common/url/parse-url.test.js +3 -3
  164. package/src/common/url/protocol.js +1 -1
  165. package/src/common/util/__mocks__/obfuscate.js +10 -0
  166. package/src/common/util/__mocks__/stringify.js +1 -0
  167. package/src/common/util/__mocks__/submit-data.js +6 -0
  168. package/src/common/util/__mocks__/traverse.js +1 -0
  169. package/src/common/util/submit-data.js +39 -53
  170. package/src/common/util/submit-data.test.js +81 -68
  171. package/src/common/window/nreum.js +1 -1
  172. package/src/common/wrap/wrap-events.js +1 -1
  173. package/src/common/wrap/wrap-fetch.js +1 -1
  174. package/src/common/wrap/wrap-history.js +1 -1
  175. package/src/common/wrap/wrap-jsonp.js +1 -1
  176. package/src/common/wrap/wrap-mutation.js +1 -1
  177. package/src/common/wrap/wrap-promise.js +1 -1
  178. package/src/common/wrap/wrap-promise.test.js +2 -2
  179. package/src/common/wrap/wrap-raf.js +1 -1
  180. package/src/common/wrap/wrap-timer.js +1 -1
  181. package/src/common/wrap/wrap-xhr.js +1 -1
  182. package/src/features/ajax/aggregate/index.js +1 -1
  183. package/src/features/ajax/instrument/distributed-tracing.js +1 -1
  184. package/src/features/ajax/instrument/index.js +1 -2
  185. package/src/features/jserrors/aggregate/compute-stack-trace.test.js +1 -1
  186. package/src/features/jserrors/aggregate/index.js +7 -3
  187. package/src/features/jserrors/instrument/index.js +1 -1
  188. package/src/features/metrics/aggregate/framework-detection.js +1 -1
  189. package/src/features/metrics/aggregate/framework-detection.test.js +2 -2
  190. package/src/features/metrics/aggregate/index.js +1 -1
  191. package/src/features/page_action/aggregate/index.js +1 -1
  192. package/src/features/page_view_event/aggregate/index.js +1 -2
  193. package/src/features/page_view_event/instrument/index.js +1 -1
  194. package/src/features/page_view_timing/aggregate/index.js +2 -4
  195. package/src/features/page_view_timing/instrument/index.js +1 -1
  196. package/src/features/session_replay/replay-mode.js +2 -2
  197. package/src/features/session_trace/instrument/index.js +1 -1
  198. package/src/features/spa/aggregate/index.js +1 -1
  199. package/src/features/spa/instrument/index.js +1 -1
  200. package/src/features/utils/agent-session.test.js +2 -2
  201. package/src/features/utils/instrument-base.js +5 -5
  202. package/src/features/utils/instrument-base.test.js +22 -3
  203. package/src/index.js +1 -3
  204. package/src/loaders/agent.js +8 -0
  205. package/src/loaders/api/api.js +1 -1
  206. package/src/loaders/api/apiAsync.js +3 -3
  207. package/src/loaders/configure/configure.js +1 -1
  208. package/src/loaders/micro-agent.js +26 -30
  209. package/dist/cjs/common/browser-version/firefox-version.js +0 -17
  210. package/dist/cjs/common/browser-version/ios-version.js +0 -19
  211. package/dist/cjs/common/event-emitter/contextual-ee.test.js +0 -282
  212. package/dist/cjs/common/event-emitter/handle.test.js +0 -58
  213. package/dist/cjs/common/event-emitter/register-handler.test.js +0 -55
  214. package/dist/cjs/common/harvest/harvest-scheduler.component-test.js +0 -39
  215. package/dist/cjs/common/harvest/harvest.component-test.js +0 -224
  216. package/dist/cjs/common/ids/id.test.js +0 -85
  217. package/dist/cjs/common/ids/unique-id.test.js +0 -49
  218. package/dist/cjs/common/session/session-entity.component-test.js +0 -497
  219. package/dist/cjs/common/storage/local-storage.test.js +0 -14
  220. package/dist/cjs/common/timer/interaction-timer.component-test.js +0 -216
  221. package/dist/cjs/common/timer/timer.test.js +0 -105
  222. package/dist/cjs/common/timing/nav-timing.test.js +0 -192
  223. package/dist/cjs/common/url/canonicalize-url.test.js +0 -38
  224. package/dist/cjs/common/url/clean-url.test.js +0 -9
  225. package/dist/cjs/common/url/encode.component-test.js +0 -74
  226. package/dist/cjs/common/url/location.test.js +0 -13
  227. package/dist/cjs/common/url/parse-url.test.js +0 -111
  228. package/dist/cjs/common/url/protocol.component-test.js +0 -15
  229. package/dist/cjs/common/util/console.test.js +0 -30
  230. package/dist/cjs/common/util/data-size.test.js +0 -64
  231. package/dist/cjs/common/util/feature-flags.test.js +0 -84
  232. package/dist/cjs/common/util/get-or-set.test.js +0 -47
  233. package/dist/cjs/common/util/global-scope.js +0 -27
  234. package/dist/cjs/common/util/global-scope.test.js +0 -72
  235. package/dist/cjs/common/util/invoke.test.js +0 -49
  236. package/dist/cjs/common/util/map-own.test.js +0 -49
  237. package/dist/cjs/common/util/obfuscate.component-test.js +0 -129
  238. package/dist/cjs/common/util/stringify.test.js +0 -48
  239. package/dist/cjs/common/util/submit-data.test.js +0 -245
  240. package/dist/cjs/common/util/traverse.test.js +0 -44
  241. package/dist/cjs/common/wrap/wrap-promise.test.js +0 -119
  242. package/dist/cjs/features/jserrors/aggregate/canonical-function-name.test.js +0 -31
  243. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +0 -383
  244. package/dist/cjs/features/jserrors/aggregate/format-stack-trace.test.js +0 -40
  245. package/dist/cjs/features/jserrors/aggregate/string-hash-code.test.js +0 -27
  246. package/dist/cjs/features/metrics/aggregate/framework-detection.test.js +0 -137
  247. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.test.js +0 -17
  248. package/dist/cjs/features/metrics/aggregate/polyfill-detection.test.js +0 -165
  249. package/dist/cjs/features/session_replay/aggregate/index.component-test.js +0 -457
  250. package/dist/cjs/features/spa/aggregate/interaction-node.test.js +0 -16
  251. package/dist/cjs/features/utils/agent-session.test.js +0 -211
  252. package/dist/cjs/features/utils/aggregate-base.test.js +0 -110
  253. package/dist/cjs/features/utils/feature-base.test.js +0 -42
  254. package/dist/cjs/features/utils/handler-cache.test.js +0 -53
  255. package/dist/cjs/features/utils/instrument-base.test.js +0 -179
  256. package/dist/cjs/features/utils/lazy-feature-loader.test.js +0 -30
  257. package/dist/esm/common/browser-version/firefox-version.js +0 -10
  258. package/dist/esm/common/browser-version/ios-version.js +0 -11
  259. package/dist/esm/common/event-emitter/contextual-ee.test.js +0 -278
  260. package/dist/esm/common/event-emitter/handle.test.js +0 -54
  261. package/dist/esm/common/event-emitter/register-handler.test.js +0 -51
  262. package/dist/esm/common/harvest/harvest-scheduler.component-test.js +0 -37
  263. package/dist/esm/common/harvest/harvest.component-test.js +0 -222
  264. package/dist/esm/common/ids/id.test.js +0 -81
  265. package/dist/esm/common/ids/unique-id.test.js +0 -44
  266. package/dist/esm/common/session/session-entity.component-test.js +0 -495
  267. package/dist/esm/common/storage/local-storage.test.js +0 -12
  268. package/dist/esm/common/timer/interaction-timer.component-test.js +0 -214
  269. package/dist/esm/common/timer/timer.test.js +0 -103
  270. package/dist/esm/common/timing/nav-timing.test.js +0 -190
  271. package/dist/esm/common/url/canonicalize-url.test.js +0 -34
  272. package/dist/esm/common/url/clean-url.test.js +0 -7
  273. package/dist/esm/common/url/encode.component-test.js +0 -70
  274. package/dist/esm/common/url/location.test.js +0 -11
  275. package/dist/esm/common/url/parse-url.test.js +0 -107
  276. package/dist/esm/common/url/protocol.component-test.js +0 -13
  277. package/dist/esm/common/util/console.test.js +0 -28
  278. package/dist/esm/common/util/data-size.test.js +0 -60
  279. package/dist/esm/common/util/feature-flags.test.js +0 -80
  280. package/dist/esm/common/util/get-or-set.test.js +0 -45
  281. package/dist/esm/common/util/global-scope.js +0 -17
  282. package/dist/esm/common/util/global-scope.test.js +0 -70
  283. package/dist/esm/common/util/invoke.test.js +0 -47
  284. package/dist/esm/common/util/map-own.test.js +0 -47
  285. package/dist/esm/common/util/obfuscate.component-test.js +0 -125
  286. package/dist/esm/common/util/stringify.test.js +0 -46
  287. package/dist/esm/common/util/submit-data.test.js +0 -241
  288. package/dist/esm/common/util/traverse.test.js +0 -42
  289. package/dist/esm/common/wrap/wrap-promise.test.js +0 -115
  290. package/dist/esm/features/jserrors/aggregate/canonical-function-name.test.js +0 -29
  291. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +0 -379
  292. package/dist/esm/features/jserrors/aggregate/format-stack-trace.test.js +0 -38
  293. package/dist/esm/features/jserrors/aggregate/string-hash-code.test.js +0 -25
  294. package/dist/esm/features/metrics/aggregate/framework-detection.test.js +0 -133
  295. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.test.js +0 -15
  296. package/dist/esm/features/metrics/aggregate/polyfill-detection.test.js +0 -163
  297. package/dist/esm/features/session_replay/aggregate/index.component-test.js +0 -453
  298. package/dist/esm/features/spa/aggregate/interaction-node.test.js +0 -14
  299. package/dist/esm/features/utils/agent-session.test.js +0 -207
  300. package/dist/esm/features/utils/aggregate-base.test.js +0 -108
  301. package/dist/esm/features/utils/feature-base.test.js +0 -40
  302. package/dist/esm/features/utils/handler-cache.test.js +0 -51
  303. package/dist/esm/features/utils/instrument-base.test.js +0 -175
  304. package/dist/esm/features/utils/lazy-feature-loader.test.js +0 -29
  305. package/dist/types/common/browser-version/firefox-version.d.ts +0 -2
  306. package/dist/types/common/browser-version/firefox-version.d.ts.map +0 -1
  307. package/dist/types/common/browser-version/ios-version.d.ts +0 -3
  308. package/dist/types/common/browser-version/ios-version.d.ts.map +0 -1
  309. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts +0 -2
  310. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts.map +0 -1
  311. package/dist/types/common/harvest/harvest.component-test.d.ts +0 -2
  312. package/dist/types/common/harvest/harvest.component-test.d.ts.map +0 -1
  313. package/dist/types/common/session/session-entity.component-test.d.ts +0 -2
  314. package/dist/types/common/session/session-entity.component-test.d.ts.map +0 -1
  315. package/dist/types/common/timer/interaction-timer.component-test.d.ts +0 -2
  316. package/dist/types/common/timer/interaction-timer.component-test.d.ts.map +0 -1
  317. package/dist/types/common/url/encode.component-test.d.ts +0 -2
  318. package/dist/types/common/url/encode.component-test.d.ts.map +0 -1
  319. package/dist/types/common/url/protocol.component-test.d.ts +0 -2
  320. package/dist/types/common/url/protocol.component-test.d.ts.map +0 -1
  321. package/dist/types/common/util/global-scope.d.ts +0 -5
  322. package/dist/types/common/util/global-scope.d.ts.map +0 -1
  323. package/dist/types/common/util/obfuscate.component-test.d.ts +0 -2
  324. package/dist/types/common/util/obfuscate.component-test.d.ts.map +0 -1
  325. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts +0 -2
  326. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts.map +0 -1
  327. package/src/common/browser-version/firefox-version.js +0 -10
  328. package/src/common/browser-version/ios-version.js +0 -11
  329. package/src/common/harvest/harvest-scheduler.component-test.js +0 -25
  330. package/src/common/harvest/harvest.component-test.js +0 -169
  331. package/src/common/util/global-scope.js +0 -23
  332. package/src/common/util/global-scope.test.js +0 -87
@@ -3,10 +3,9 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
 
6
- import { mapOwn } from '../util/map-own'
7
6
  import { obj as encodeObj, param as encodeParam } from '../url/encode'
8
7
  import { stringify } from '../util/stringify'
9
- import { submitData } from '../util/submit-data'
8
+ import * as submitData from '../util/submit-data'
10
9
  import { getLocation } from '../url/location'
11
10
  import { getInfo, getConfigurationValue, getRuntime } from '../config/config'
12
11
  import { cleanURL } from '../url/clean-url'
@@ -16,27 +15,16 @@ import { Obfuscator } from '../util/obfuscate'
16
15
  import { applyFnToProps } from '../util/traverse'
17
16
  import { SharedContext } from '../context/shared-context'
18
17
  import { VERSION } from '../constants/env'
19
- import { isBrowserScope, isWorkerScope } from '../util/global-scope'
18
+ import { isWorkerScope, isIE } from '../constants/runtime'
20
19
 
21
20
  /**
22
- * @typedef {object} NetworkSendSpec
23
- * @param {string} endpoint The endpoint to use (jserrors, events, resources etc.)
24
- * @param {object} payload Object representing payload.
25
- * @param {object} payload.qs Map of values that should be sent as part of the request query string.
26
- * @param {string} payload.body String that should be sent as the body of the request.
27
- * @param {string} payload.body.e Special case of body used for browser interactions.
28
- * @param {object} opts Additional options for sending data
29
- * @param {boolean} opts.needResponse Specify whether the caller expects a response data.
30
- * @param {boolean} opts.unload Specify whether the call is a final harvest during page unload.
31
- * @param {boolean} opts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
32
- * @param {function} submitMethod The submit method to use {@link ../util/submit-data}
33
- * @param {string} customUrl Override the beacon url the data is sent to; must include protocol if defined
34
- * @param {boolean} gzip Enabled gzip compression on the body of the request before it is sent
35
- * @param {boolean} includeBaseParams Enables the use of base query parameters in the beacon url {@see Harvest.baseQueryString}
21
+ * @typedef {import('./types.js').NetworkSendSpec} NetworkSendSpec
22
+ * @typedef {import('./types.js').HarvestEndpointIdentifier} HarvestEndpointIdentifier
23
+ * @typedef {import('./types.js').HarvestPayload} HarvestPayload
24
+ * @typedef {import('./types.js').FeatureHarvestCallback} FeatureHarvestCallback
25
+ * @typedef {import('./types.js').FeatureHarvestCallbackOptions} FeatureHarvestCallbackOptions
36
26
  */
37
27
 
38
- const haveSendBeacon = !!navigator.sendBeacon // only the web window obj has sendBeacon at this time, so 'false' for other envs
39
-
40
28
  export class Harvest extends SharedContext {
41
29
  constructor (parent) {
42
30
  super(parent) // gets any allowed properties from the parent and stores them in `sharedContext`
@@ -51,17 +39,16 @@ export class Harvest extends SharedContext {
51
39
  /**
52
40
  * Initiate a harvest from multiple sources. An event that corresponds to the endpoint
53
41
  * name is emitted, which gives any listeners the opportunity to provide payload data.
42
+ * Note: Used by page_action
54
43
  * @param {NetworkSendSpec} spec Specification for sending data
55
44
  */
56
- sendX (spec) {
57
- const { endpoint, opts } = spec
58
- var submitMethod = getSubmitMethod(endpoint, opts)
59
- if (!submitMethod) return false
60
- var options = {
61
- retry: submitMethod.method === submitData.xhr
45
+ sendX (spec = {}) {
46
+ const submitMethod = submitData.getSubmitMethod({ isFinalHarvest: spec.opts?.unload })
47
+ const options = {
48
+ retry: !spec.opts?.unload && submitMethod === submitData.xhr
62
49
  }
63
- const payload = this.createPayload(endpoint, options)
64
- var caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this)
50
+ const payload = this.createPayload(spec.endpoint, options)
51
+ const caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this)
65
52
  return caller({ ...spec, payload, submitMethod })
66
53
  }
67
54
 
@@ -69,69 +56,71 @@ export class Harvest extends SharedContext {
69
56
  * Initiate a harvest call.
70
57
  * @param {NetworkSendSpec} spec Specification for sending data
71
58
  */
72
- send (spec) {
73
- const { payload = {} } = spec
74
- var makeBody = createAccumulator()
75
- var makeQueryString = createAccumulator()
76
- if (payload.body) mapOwn(payload.body, makeBody)
77
- if (payload.qs) mapOwn(payload.qs, makeQueryString)
78
-
79
- var newPayload = { body: makeBody(), qs: makeQueryString() }
80
- var caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this)
59
+ send (spec = {}) {
60
+ const caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this)
81
61
 
82
- return caller({ ...spec, payload: newPayload })
62
+ return caller(spec)
83
63
  }
84
64
 
85
65
  /**
86
66
  * Apply obfuscation rules to the payload and then initial the harvest network call.
87
67
  * @param {NetworkSendSpec} spec Specification for sending data
88
68
  */
89
- obfuscateAndSend (spec) {
69
+ obfuscateAndSend (spec = {}) {
90
70
  const { payload = {} } = spec
91
71
  applyFnToProps(payload, (...args) => this.obfuscator.obfuscateString(...args), 'string', ['e'])
92
72
  return this._send({ ...spec, payload })
93
73
  }
94
74
 
75
+ /**
76
+ * Initiate a harvest call. Typically used by `sendX` and `send` methods or called directly
77
+ * for raw network calls.
78
+ * @param {NetworkSendSpec} param0 Specification for sending data
79
+ * @returns {boolean} True if the network call succeeded. For final harvest calls, the return
80
+ * value should not be relied upon because network calls will be made asynchronously.
81
+ */
95
82
  _send ({ endpoint, payload = {}, opts = {}, submitMethod, cbFinished, customUrl, raw, includeBaseParams = true }) {
96
- var info = getInfo(this.sharedContext.agentIdentifier)
83
+ const info = getInfo(this.sharedContext.agentIdentifier)
97
84
  if (!info.errorBeacon) return false
98
85
 
99
- var agentRuntime = getRuntime(this.sharedContext.agentIdentifier)
86
+ const agentRuntime = getRuntime(this.sharedContext.agentIdentifier)
87
+ let { body, qs } = this.cleanPayload(payload)
100
88
 
101
- if (!payload.body && !opts?.sendEmptyBody) { // no payload body? nothing to send, just run onfinish stuff and return
89
+ if (Object.keys(body).length === 0 && !opts?.sendEmptyBody) { // no payload body? nothing to send, just run onfinish stuff and return
102
90
  if (cbFinished) {
103
91
  cbFinished({ sent: false })
104
92
  }
105
93
  return false
106
94
  }
107
95
 
108
- let url = ''
96
+ let url = `${this.getScheme()}://${info.errorBeacon}${endpoint !== 'rum' ? `/${endpoint}` : ''}/1/${info.licenseKey}`
109
97
  if (customUrl) url = customUrl
110
- else if (raw) url = `${this.getScheme()}://${info.errorBeacon}/${endpoint}`
111
- else url = `${this.getScheme()}://${info.errorBeacon}${endpoint !== 'rum' ? `/${endpoint}` : ''}/1/${info.licenseKey}`
98
+ if (raw) url = `${this.getScheme()}://${info.errorBeacon}/${endpoint}`
112
99
 
113
- var baseParams = !raw && includeBaseParams ? this.baseQueryString() : ''
114
- var payloadParams = payload.qs ? encodeObj(payload.qs, agentRuntime.maxBytes) : ''
100
+ const baseParams = !raw && includeBaseParams ? this.baseQueryString() : ''
101
+ let payloadParams = encodeObj(qs, agentRuntime.maxBytes)
115
102
  if (!submitMethod) {
116
- submitMethod = getSubmitMethod(endpoint, opts)
103
+ submitMethod = submitData.getSubmitMethod({ isFinalHarvest: opts.unload })
104
+ }
105
+ if (baseParams === '' && payloadParams.startsWith('&')) {
106
+ payloadParams = payloadParams.substring(1)
117
107
  }
118
- var method = submitMethod.method
119
- var useBody = submitMethod.useBody
120
-
121
- var body
122
- var fullUrl = `${url}?${baseParams}${payloadParams}`
123
108
 
124
- const gzip = payload?.qs?.content_encoding === 'gzip'
109
+ const fullUrl = `${url}?${baseParams}${payloadParams}`
110
+ const gzip = qs.content_encoding === 'gzip'
125
111
 
126
112
  if (!gzip) {
127
- if (useBody && endpoint === 'events') {
128
- body = payload.body.e
129
- } else if (useBody) {
130
- body = stringify(payload.body)
113
+ if (endpoint === 'events') {
114
+ body = body.e
131
115
  } else {
132
- fullUrl = fullUrl + encodeObj(payload.body, agentRuntime.maxBytes)
116
+ body = stringify(body)
133
117
  }
134
- } else body = payload.body
118
+ }
119
+
120
+ if (!body || body.length === 0 || body === '{}' || body === '[]') {
121
+ // If body is null, undefined, or an empty object or array, send an empty string instead
122
+ body = ''
123
+ }
135
124
 
136
125
  // Get bytes harvested per endpoint as a supportability metric. See metrics aggregator (on unload).
137
126
  agentRuntime.bytesSent[endpoint] = (agentRuntime.bytesSent[endpoint] || 0) + body?.length || 0
@@ -142,34 +131,42 @@ export class Harvest extends SharedContext {
142
131
 
143
132
  headers.push({ key: 'content-type', value: 'text/plain' })
144
133
 
145
- /* Since workers don't support sendBeacon right now, or Image(), they can only use XHR method.
134
+ /* Since workers don't support sendBeacon right now, they can only use XHR method.
146
135
  Because they still do permit synch XHR, the idea is that at final harvest time (worker is closing),
147
- we just make a BLOCKING request--trivial impact--with the remaining data as a temp fill-in for sendBeacon. */
148
-
149
- var result = method({ url: fullUrl, body, sync: opts.unload && isWorkerScope, headers })
150
-
151
- if (cbFinished && method === submitData.xhr) {
152
- var xhr = result
153
- xhr.addEventListener('load', function () {
154
- var result = { sent: true, status: this.status }
136
+ we just make a BLOCKING request--trivial impact--with the remaining data as a temp fill-in for sendBeacon.
137
+ Following the removal of img-element method, IE will also use sync XHR on page dismissal to ensure final analytics are sent. */
138
+ let result = submitMethod({ url: fullUrl, body, sync: opts.unload && (isWorkerScope || isIE), headers })
139
+
140
+ if (!opts.unload && cbFinished && submitMethod === submitData.xhr) {
141
+ const harvestScope = this
142
+ result.addEventListener('load', function () {
143
+ // `this` refers to the XHR object in this scope, do not change this to a fat arrow
144
+ const cbResult = { sent: true, status: this.status }
155
145
  if (this.status === 429) {
156
- result.retry = true
157
- result.delay = this.tooManyRequestsDelay
146
+ cbResult.retry = true
147
+ cbResult.delay = harvestScope.tooManyRequestsDelay
158
148
  } else if (this.status === 408 || this.status === 500 || this.status === 503) {
159
- result.retry = true
149
+ cbResult.retry = true
160
150
  }
161
151
 
162
152
  if (opts.needResponse) {
163
- result.responseText = this.responseText
153
+ cbResult.responseText = this.responseText
164
154
  }
165
- cbFinished(result)
155
+ cbFinished(cbResult)
166
156
  }, eventListenerOpts(false))
167
157
  }
168
158
 
169
159
  // if beacon request failed, retry with an alternative method -- will not happen for workers
170
- if (!result && method === submitData.beacon) {
171
- method = submitData.img
172
- result = method({ url: fullUrl + encodeObj(payload.body, agentRuntime.maxBytes) })
160
+ if (!result && submitMethod === submitData.beacon) {
161
+ // browsers that support sendBeacon also support fetch with keepalive - IE will not retry unload calls
162
+ submitMethod = submitData.fetchKeepAlive
163
+ try {
164
+ submitMethod({ url: fullUrl, body, headers })
165
+ } catch (e) {
166
+ // Ignore error in final harvest
167
+ } finally {
168
+ result = true
169
+ }
173
170
  }
174
171
 
175
172
  return result
@@ -177,11 +174,11 @@ export class Harvest extends SharedContext {
177
174
 
178
175
  // The stuff that gets sent every time.
179
176
  baseQueryString () {
180
- var runtime = getRuntime(this.sharedContext.agentIdentifier)
181
- var info = getInfo(this.sharedContext.agentIdentifier)
177
+ const runtime = getRuntime(this.sharedContext.agentIdentifier)
178
+ const info = getInfo(this.sharedContext.agentIdentifier)
182
179
 
183
- var location = cleanURL(getLocation())
184
- var ref = this.obfuscator.shouldObfuscate() ? this.obfuscator.obfuscateString(location) : location
180
+ const location = cleanURL(getLocation())
181
+ const ref = this.obfuscator.shouldObfuscate() ? this.obfuscator.obfuscateString(location) : location
185
182
 
186
183
  return ([
187
184
  'a=' + info.applicationID,
@@ -197,51 +194,85 @@ export class Harvest extends SharedContext {
197
194
  ].join(''))
198
195
  }
199
196
 
200
- createPayload (type, options) {
201
- var makeBody = createAccumulator()
202
- var makeQueryString = createAccumulator()
203
- var listeners = ((this._events[type] && this._events[type]) || [])
197
+ /**
198
+ * Calls and accumulates data from registered harvesting functions based on
199
+ * the endpoint being harvested.
200
+ * @param {HarvestEndpointIdentifier} endpoint BAM endpoint identifier.
201
+ * @param {FeatureHarvestCallbackOptions} options Options to be passed to the
202
+ * feature harvest listener callback.
203
+ * @returns {HarvestPayload} Payload object to transmit to the bam endpoint.
204
+ */
205
+ createPayload (endpoint, options) {
206
+ const listeners = this._events[endpoint]
207
+ const payload = {
208
+ body: {},
209
+ qs: {}
210
+ }
204
211
 
205
- for (var i = 0; i < listeners.length; i++) {
206
- var singlePayload = listeners[i](options)
207
- if (!singlePayload) continue
208
- if (singlePayload.body) mapOwn(singlePayload.body, makeBody)
209
- if (singlePayload.qs) mapOwn(singlePayload.qs, makeQueryString)
212
+ if (Array.isArray(listeners) && listeners.length > 0) {
213
+ for (let i = 0; i < listeners.length; i++) {
214
+ const singlePayload = listeners[i](options)
215
+
216
+ if (singlePayload) {
217
+ payload.body = {
218
+ ...payload.body,
219
+ ...(singlePayload.body || {})
220
+ }
221
+ payload.qs = {
222
+ ...payload.qs,
223
+ ...(singlePayload.qs || {})
224
+ }
225
+ }
226
+ }
210
227
  }
211
228
 
212
- return { body: makeBody(), qs: makeQueryString() }
229
+ return payload
213
230
  }
214
231
 
215
- on (type, listener) {
216
- var listeners = (this._events[type] || (this._events[type] = []))
217
- listeners.push(listener)
218
- }
232
+ /**
233
+ * Cleans and returns a payload object containing a body and qs
234
+ * object with key/value pairs. KV pairs where the value is null,
235
+ * undefined, or an empty string are removed to save on transmission
236
+ * size.
237
+ * @param {HarvestPayload} payload Payload to be sent to the endpoint.
238
+ * @returns {HarvestPayload} Cleaned payload payload to be sent to the endpoint.
239
+ */
240
+ cleanPayload (payload = {}) {
241
+ const clean = (input) => {
242
+ if (typeof Uint8Array !== 'undefined' && input instanceof Uint8Array) {
243
+ return input.length > 0 ? input : null
244
+ }
245
+ return Object.entries(input || {})
246
+ .reduce((accumulator, [key, value]) => {
247
+ if ((typeof value === 'number') ||
248
+ (typeof value === 'string' && value.length > 0) ||
249
+ (typeof value === 'object' && Object.keys(value || {}).length > 0)
250
+ ) {
251
+ accumulator[key] = value
252
+ }
253
+
254
+ return accumulator
255
+ }, {})
256
+ }
219
257
 
220
- resetListeners () {
221
- mapOwn(this._events, (key) => {
222
- this._events[key] = []
223
- })
258
+ return {
259
+ body: clean(payload.body),
260
+ qs: clean(payload.qs)
261
+ }
224
262
  }
225
- }
226
263
 
227
- export function getSubmitMethod (endpoint, opts) {
228
- opts = opts || {}
229
- var method
230
- var useBody
231
-
232
- if (opts.unload && isBrowserScope) { // all the features' final harvest; neither methods work outside window context
233
- useBody = haveSendBeacon
234
- method = haveSendBeacon ? submitData.beacon : submitData.img // really only IE doesn't have Beacon API for web browsers
235
- } else {
236
- // `submitData.beacon` was removed, there is an upper limit to the
237
- // number of data allowed before it starts failing, so we save it only for page unloading
238
- useBody = true
239
- method = submitData.xhr
240
- }
264
+ /**
265
+ * Registers a function to be called when harvesting is triggered for a specific
266
+ * endpoint.
267
+ * @param {HarvestEndpointIdentifier} endpoint
268
+ * @param {FeatureHarvestCallback} listener
269
+ */
270
+ on (endpoint, listener) {
271
+ if (!Array.isArray(this._events[endpoint])) {
272
+ this._events[endpoint] = []
273
+ }
241
274
 
242
- return {
243
- method: method,
244
- useBody: useBody
275
+ this._events[endpoint].push(listener)
245
276
  }
246
277
  }
247
278
 
@@ -252,17 +283,3 @@ function transactionNameParam (info) {
252
283
  if (info.transactionName) return encodeParam('to', info.transactionName)
253
284
  return encodeParam('t', info.tNamePlain || 'Unnamed Transaction')
254
285
  }
255
-
256
- // returns a function that can be called to accumulate values to a single object
257
- // when the function is called without parameters, then the accumulator is returned
258
- function createAccumulator () {
259
- var accumulator = {}
260
- var hasData = false
261
- return function (key, val) {
262
- if (val !== null && val !== undefined && val.toString()?.length) {
263
- accumulator[key] = val
264
- hasData = true
265
- }
266
- if (hasData) return accumulator
267
- }
268
- }