@newrelic/browser-agent 0.0.9 → 0.1.229

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 (339) hide show
  1. package/README.md +84 -207
  2. package/dist/cjs/cdn/lite.js +14 -0
  3. package/dist/cjs/cdn/polyfills/lite.js +4 -0
  4. package/dist/cjs/cdn/polyfills/pro.js +4 -0
  5. package/dist/cjs/cdn/polyfills/spa.js +4 -0
  6. package/dist/cjs/cdn/polyfills.js +14 -0
  7. package/dist/cjs/cdn/pro.js +19 -0
  8. package/dist/cjs/cdn/spa.js +19 -0
  9. package/dist/cjs/cdn/worker.js +16 -0
  10. package/dist/cjs/common/aggregate/aggregator.js +168 -0
  11. package/dist/cjs/common/browser-version/firefox-version.js +17 -0
  12. package/dist/cjs/common/browser-version/ios-version.js +18 -0
  13. package/dist/cjs/common/config/config.js +76 -0
  14. package/dist/cjs/common/config/state/configurable.js +32 -0
  15. package/dist/cjs/common/config/state/info.js +50 -0
  16. package/dist/cjs/common/config/state/init.js +86 -0
  17. package/dist/cjs/common/config/state/loader-config.js +28 -0
  18. package/dist/cjs/common/config/state/originals.js +9 -0
  19. package/dist/cjs/common/config/state/runtime.js +50 -0
  20. package/dist/cjs/common/constants/environment-variables.js +20 -0
  21. package/dist/cjs/common/context/shared-context.js +25 -0
  22. package/dist/cjs/common/deny-list/deny-list.js +108 -0
  23. package/dist/cjs/common/drain/drain.js +126 -0
  24. package/dist/cjs/common/event-emitter/contextual-ee.js +149 -0
  25. package/dist/cjs/common/event-emitter/handle.js +24 -0
  26. package/dist/cjs/common/event-emitter/register-handler.js +24 -0
  27. package/dist/cjs/common/event-listener/event-listener-opts.js +46 -0
  28. package/dist/cjs/common/harvest/harvest-scheduler.js +111 -0
  29. package/dist/cjs/common/harvest/harvest.js +236 -0
  30. package/dist/cjs/common/ids/id.js +30 -0
  31. package/dist/cjs/common/ids/unique-id.js +84 -0
  32. package/dist/cjs/common/metrics/framework-detection.js +72 -0
  33. package/dist/cjs/common/metrics/paint-metrics.js +13 -0
  34. package/dist/cjs/common/serialize/bel-serializer.js +89 -0
  35. package/dist/cjs/common/timing/nav-timing.js +77 -0
  36. package/dist/cjs/common/timing/now.js +15 -0
  37. package/dist/cjs/common/unload/eol.js +69 -0
  38. package/dist/cjs/common/url/clean-url.js +16 -0
  39. package/dist/cjs/common/url/encode.js +79 -0
  40. package/dist/cjs/common/url/location.js +14 -0
  41. package/dist/cjs/common/url/parse-url.js +66 -0
  42. package/dist/cjs/common/url/protocol.js +25 -0
  43. package/dist/cjs/common/util/console.js +17 -0
  44. package/dist/cjs/common/util/data-size.js +25 -0
  45. package/dist/cjs/common/util/feature-flags.js +42 -0
  46. package/dist/cjs/common/util/get-or-set.js +39 -0
  47. package/dist/cjs/common/util/global-scope.js +56 -0
  48. package/dist/cjs/common/util/map-own.js +24 -0
  49. package/dist/cjs/common/util/obfuscate.js +76 -0
  50. package/dist/cjs/common/util/reduce.js +22 -0
  51. package/dist/cjs/common/util/s-hash.js +19 -0
  52. package/dist/cjs/common/util/single.js +23 -0
  53. package/dist/cjs/common/util/stringify.js +47 -0
  54. package/dist/cjs/common/util/submit-data.js +99 -0
  55. package/dist/cjs/common/util/traverse.js +41 -0
  56. package/dist/cjs/common/util/user-agent.js +57 -0
  57. package/dist/cjs/common/window/load.js +19 -0
  58. package/dist/cjs/common/window/nreum.js +107 -0
  59. package/dist/cjs/common/window/page-visibility.js +28 -0
  60. package/dist/cjs/common/window/session-storage.js +42 -0
  61. package/dist/cjs/common/window/supports-performance-observer.js +15 -0
  62. package/dist/cjs/common/window/top-level-callers.js +23 -0
  63. package/dist/cjs/common/wrap/index.js +68 -0
  64. package/dist/cjs/common/wrap/wrap-events.js +105 -0
  65. package/dist/cjs/common/wrap/wrap-fetch.js +114 -0
  66. package/dist/cjs/common/wrap/wrap-function.js +269 -0
  67. package/dist/cjs/common/wrap/wrap-history.js +56 -0
  68. package/dist/cjs/common/wrap/wrap-jsonp.js +129 -0
  69. package/dist/cjs/common/wrap/wrap-mutation.js +61 -0
  70. package/dist/cjs/common/wrap/wrap-promise.js +160 -0
  71. package/dist/cjs/common/wrap/wrap-raf.js +55 -0
  72. package/dist/cjs/common/wrap/wrap-timer.js +70 -0
  73. package/dist/cjs/common/wrap/wrap-xhr.js +206 -0
  74. package/dist/cjs/features/ajax/aggregate/index.js +226 -0
  75. package/dist/cjs/features/ajax/constants.js +9 -0
  76. package/dist/cjs/features/ajax/index.js +12 -0
  77. package/dist/cjs/features/ajax/instrument/distributed-tracing.js +145 -0
  78. package/dist/cjs/features/ajax/instrument/index.js +338 -0
  79. package/dist/cjs/features/ajax/instrument/response-size.js +26 -0
  80. package/dist/cjs/features/jserrors/aggregate/canonical-function-name.js +18 -0
  81. package/dist/cjs/features/jserrors/aggregate/canonical-function-name.test.js +30 -0
  82. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +216 -0
  83. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +257 -0
  84. package/dist/cjs/features/jserrors/aggregate/format-stack-trace.js +36 -0
  85. package/dist/cjs/features/jserrors/aggregate/format-stack-trace.test.js +39 -0
  86. package/dist/cjs/features/jserrors/aggregate/index.js +267 -0
  87. package/dist/cjs/features/jserrors/aggregate/string-hash-code.js +23 -0
  88. package/dist/cjs/features/jserrors/aggregate/string-hash-code.test.js +26 -0
  89. package/dist/cjs/features/jserrors/constants.js +11 -0
  90. package/dist/cjs/features/jserrors/index.js +12 -0
  91. package/dist/cjs/features/jserrors/instrument/debug.js +40 -0
  92. package/dist/cjs/features/jserrors/instrument/index.js +158 -0
  93. package/dist/cjs/features/metrics/aggregate/index.js +136 -0
  94. package/dist/cjs/features/metrics/constants.js +17 -0
  95. package/dist/cjs/features/metrics/index.js +12 -0
  96. package/dist/cjs/features/metrics/instrument/index.js +20 -0
  97. package/dist/cjs/features/metrics/instrument/workers-helper.js +121 -0
  98. package/dist/cjs/features/page_action/aggregate/index.js +112 -0
  99. package/dist/cjs/features/page_action/constants.js +9 -0
  100. package/dist/cjs/features/page_action/index.js +12 -0
  101. package/dist/cjs/features/page_action/instrument/index.js +21 -0
  102. package/dist/cjs/features/page_view_event/aggregate/index.js +133 -0
  103. package/dist/cjs/features/page_view_event/aggregate/initialized-features.js +39 -0
  104. package/dist/cjs/features/page_view_event/constants.js +15 -0
  105. package/dist/cjs/features/page_view_event/index.js +12 -0
  106. package/dist/cjs/features/page_view_event/instrument/index.js +38 -0
  107. package/dist/cjs/features/page_view_timing/aggregate/index.js +265 -0
  108. package/dist/cjs/features/page_view_timing/constants.js +9 -0
  109. package/dist/cjs/features/page_view_timing/first-paint.js +50 -0
  110. package/dist/cjs/features/page_view_timing/index.js +12 -0
  111. package/dist/cjs/features/page_view_timing/instrument/index.js +36 -0
  112. package/dist/cjs/features/page_view_timing/long-tasks.js +75 -0
  113. package/dist/cjs/features/session_trace/aggregate/index.js +375 -0
  114. package/dist/cjs/features/session_trace/constants.js +32 -0
  115. package/dist/cjs/features/session_trace/index.js +12 -0
  116. package/dist/cjs/features/session_trace/instrument/index.js +133 -0
  117. package/dist/cjs/features/spa/aggregate/index.js +684 -0
  118. package/dist/cjs/features/spa/aggregate/interaction-node.js +84 -0
  119. package/dist/cjs/features/spa/aggregate/interaction-node.test.js +16 -0
  120. package/dist/cjs/features/spa/aggregate/interaction.js +98 -0
  121. package/dist/cjs/features/spa/aggregate/serializer.js +147 -0
  122. package/dist/cjs/features/spa/constants.js +53 -0
  123. package/dist/cjs/features/spa/index.js +12 -0
  124. package/dist/cjs/features/spa/instrument/index.js +114 -0
  125. package/dist/cjs/features/utils/aggregate-base.js +13 -0
  126. package/dist/cjs/features/utils/feature-base.js +58 -0
  127. package/dist/cjs/features/utils/handler-cache.js +64 -0
  128. package/dist/cjs/features/utils/instrument-base.js +71 -0
  129. package/dist/cjs/features/utils/lazy-loader.js +44 -0
  130. package/dist/cjs/index.js +81 -58
  131. package/dist/cjs/loaders/agent.js +86 -0
  132. package/dist/cjs/loaders/api/api.js +109 -0
  133. package/dist/cjs/loaders/api/apiAsync.js +94 -0
  134. package/dist/cjs/loaders/browser-agent.js +29 -0
  135. package/dist/cjs/loaders/configure/configure.js +47 -0
  136. package/dist/cjs/loaders/features/enabled-features.js +19 -0
  137. package/dist/cjs/loaders/features/featureDependencies.js +32 -0
  138. package/dist/cjs/loaders/features/features.js +33 -0
  139. package/dist/cjs/loaders/micro-agent.js +93 -0
  140. package/dist/cjs/loaders/worker-agent.js +24 -0
  141. package/dist/esm/cdn/lite.js +12 -0
  142. package/dist/esm/cdn/polyfills/lite.js +7 -0
  143. package/dist/esm/cdn/polyfills/pro.js +7 -0
  144. package/dist/esm/cdn/polyfills/spa.js +7 -0
  145. package/dist/esm/cdn/polyfills.js +17 -0
  146. package/dist/esm/cdn/pro.js +17 -0
  147. package/dist/esm/cdn/spa.js +17 -0
  148. package/dist/esm/cdn/worker.js +14 -0
  149. package/dist/esm/common/aggregate/aggregator.js +161 -0
  150. package/dist/esm/common/browser-version/firefox-version.js +10 -0
  151. package/dist/esm/common/browser-version/ios-version.js +10 -0
  152. package/dist/esm/common/config/config.js +11 -0
  153. package/dist/esm/common/config/state/configurable.js +25 -0
  154. package/dist/esm/common/config/state/info.js +42 -0
  155. package/dist/esm/common/config/state/init.js +78 -0
  156. package/dist/esm/common/config/state/loader-config.js +21 -0
  157. package/dist/esm/common/config/state/originals.js +2 -0
  158. package/dist/esm/common/config/state/runtime.js +41 -0
  159. package/dist/esm/common/constants/environment-variables.js +11 -0
  160. package/dist/esm/common/context/shared-context.js +18 -0
  161. package/dist/esm/common/deny-list/deny-list.js +101 -0
  162. package/dist/esm/common/drain/drain.js +119 -0
  163. package/dist/esm/common/event-emitter/contextual-ee.js +142 -0
  164. package/dist/esm/common/event-emitter/handle.js +16 -0
  165. package/dist/esm/common/event-emitter/register-handler.js +19 -0
  166. package/dist/esm/common/event-listener/event-listener-opts.js +39 -0
  167. package/dist/esm/common/harvest/harvest-scheduler.js +105 -0
  168. package/dist/esm/common/harvest/harvest.js +228 -0
  169. package/dist/esm/common/ids/id.js +23 -0
  170. package/dist/esm/common/ids/unique-id.js +75 -0
  171. package/dist/esm/common/metrics/framework-detection.js +66 -0
  172. package/dist/esm/common/metrics/paint-metrics.js +6 -0
  173. package/dist/esm/common/serialize/bel-serializer.js +80 -0
  174. package/dist/esm/common/timing/nav-timing.js +67 -0
  175. package/dist/esm/common/timing/now.js +9 -0
  176. package/dist/esm/common/unload/eol.js +62 -0
  177. package/dist/esm/common/url/clean-url.js +10 -0
  178. package/dist/esm/common/url/encode.js +71 -0
  179. package/dist/esm/common/url/location.js +8 -0
  180. package/dist/esm/common/url/parse-url.js +60 -0
  181. package/dist/esm/common/url/protocol.js +17 -0
  182. package/dist/esm/common/util/console.js +11 -0
  183. package/dist/esm/common/util/data-size.js +19 -0
  184. package/dist/esm/common/util/feature-flags.js +33 -0
  185. package/dist/esm/common/util/get-or-set.js +33 -0
  186. package/dist/esm/common/util/global-scope.js +44 -0
  187. package/dist/esm/common/util/map-own.js +18 -0
  188. package/dist/esm/common/util/obfuscate.js +67 -0
  189. package/dist/esm/common/util/reduce.js +16 -0
  190. package/dist/esm/common/util/s-hash.js +13 -0
  191. package/dist/esm/common/util/single.js +16 -0
  192. package/dist/esm/common/util/stringify.js +42 -0
  193. package/dist/esm/common/util/submit-data.js +91 -0
  194. package/dist/esm/common/util/traverse.js +35 -0
  195. package/dist/esm/common/util/user-agent.js +48 -0
  196. package/dist/esm/common/window/load.js +12 -0
  197. package/dist/esm/common/window/nreum.js +91 -0
  198. package/dist/esm/common/window/page-visibility.js +23 -0
  199. package/dist/esm/common/window/session-storage.js +36 -0
  200. package/dist/esm/common/window/supports-performance-observer.js +9 -0
  201. package/dist/esm/common/window/top-level-callers.js +17 -0
  202. package/dist/esm/common/wrap/index.js +14 -0
  203. package/dist/esm/common/wrap/wrap-events.js +97 -0
  204. package/dist/esm/common/wrap/wrap-fetch.js +105 -0
  205. package/dist/esm/common/wrap/wrap-function.js +257 -0
  206. package/dist/esm/common/wrap/wrap-history.js +48 -0
  207. package/dist/esm/common/wrap/wrap-jsonp.js +122 -0
  208. package/dist/esm/common/wrap/wrap-mutation.js +54 -0
  209. package/dist/esm/common/wrap/wrap-promise.js +153 -0
  210. package/dist/esm/common/wrap/wrap-raf.js +48 -0
  211. package/dist/esm/common/wrap/wrap-timer.js +63 -0
  212. package/dist/esm/common/wrap/wrap-xhr.js +199 -0
  213. package/dist/esm/features/ajax/aggregate/index.js +218 -0
  214. package/dist/esm/features/ajax/constants.js +2 -0
  215. package/dist/esm/features/ajax/index.js +1 -0
  216. package/dist/esm/features/ajax/instrument/distributed-tracing.js +137 -0
  217. package/dist/esm/features/ajax/instrument/index.js +330 -0
  218. package/dist/esm/features/ajax/instrument/response-size.js +19 -0
  219. package/dist/esm/features/jserrors/aggregate/canonical-function-name.js +12 -0
  220. package/dist/esm/features/jserrors/aggregate/canonical-function-name.test.js +28 -0
  221. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +209 -0
  222. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +255 -0
  223. package/dist/esm/features/jserrors/aggregate/format-stack-trace.js +29 -0
  224. package/dist/esm/features/jserrors/aggregate/format-stack-trace.test.js +37 -0
  225. package/dist/esm/features/jserrors/aggregate/index.js +260 -0
  226. package/dist/esm/features/jserrors/aggregate/string-hash-code.js +17 -0
  227. package/dist/esm/features/jserrors/aggregate/string-hash-code.test.js +24 -0
  228. package/dist/esm/features/jserrors/constants.js +3 -0
  229. package/dist/esm/features/jserrors/index.js +1 -0
  230. package/dist/esm/features/jserrors/instrument/debug.js +38 -0
  231. package/dist/esm/features/jserrors/instrument/index.js +150 -0
  232. package/dist/esm/features/metrics/aggregate/index.js +129 -0
  233. package/dist/esm/features/metrics/constants.js +6 -0
  234. package/dist/esm/features/metrics/index.js +1 -0
  235. package/dist/esm/features/metrics/instrument/index.js +13 -0
  236. package/dist/esm/features/metrics/instrument/workers-helper.js +116 -0
  237. package/dist/esm/features/page_action/aggregate/index.js +105 -0
  238. package/dist/esm/features/page_action/constants.js +2 -0
  239. package/dist/esm/features/page_action/index.js +1 -0
  240. package/dist/esm/features/page_action/instrument/index.js +14 -0
  241. package/dist/esm/features/page_view_event/aggregate/index.js +124 -0
  242. package/dist/esm/features/page_view_event/aggregate/initialized-features.js +34 -0
  243. package/dist/esm/features/page_view_event/constants.js +5 -0
  244. package/dist/esm/features/page_view_event/index.js +1 -0
  245. package/dist/esm/features/page_view_event/instrument/index.js +29 -0
  246. package/dist/esm/features/page_view_timing/aggregate/index.js +258 -0
  247. package/dist/esm/features/page_view_timing/constants.js +2 -0
  248. package/dist/esm/features/page_view_timing/first-paint.js +43 -0
  249. package/dist/esm/features/page_view_timing/index.js +1 -0
  250. package/dist/esm/features/page_view_timing/instrument/index.js +28 -0
  251. package/dist/esm/features/page_view_timing/long-tasks.js +69 -0
  252. package/dist/esm/features/session_trace/aggregate/index.js +366 -0
  253. package/dist/esm/features/session_trace/constants.js +14 -0
  254. package/dist/esm/features/session_trace/index.js +1 -0
  255. package/dist/esm/features/session_trace/instrument/index.js +123 -0
  256. package/dist/esm/features/spa/aggregate/index.js +674 -0
  257. package/dist/esm/features/spa/aggregate/interaction-node.js +78 -0
  258. package/dist/esm/features/spa/aggregate/interaction-node.test.js +14 -0
  259. package/dist/esm/features/spa/aggregate/interaction.js +92 -0
  260. package/dist/esm/features/spa/aggregate/serializer.js +139 -0
  261. package/dist/esm/features/spa/constants.js +25 -0
  262. package/dist/esm/features/spa/index.js +1 -0
  263. package/dist/esm/features/spa/instrument/index.js +104 -0
  264. package/dist/esm/features/utils/aggregate-base.js +6 -0
  265. package/dist/esm/features/utils/feature-base.js +51 -0
  266. package/dist/esm/features/utils/handler-cache.js +57 -0
  267. package/dist/esm/features/utils/instrument-base.js +69 -0
  268. package/dist/esm/features/utils/lazy-loader.js +37 -0
  269. package/dist/esm/index.js +15 -0
  270. package/dist/esm/loaders/agent.js +77 -0
  271. package/dist/esm/loaders/api/api.js +104 -0
  272. package/dist/esm/loaders/api/apiAsync.js +88 -0
  273. package/dist/esm/loaders/browser-agent.js +23 -0
  274. package/dist/esm/loaders/configure/configure.js +41 -0
  275. package/dist/esm/loaders/features/enabled-features.js +13 -0
  276. package/dist/esm/loaders/features/featureDependencies.js +25 -0
  277. package/dist/esm/loaders/features/features.js +25 -0
  278. package/dist/esm/loaders/micro-agent.js +86 -0
  279. package/dist/esm/loaders/worker-agent.js +18 -0
  280. package/package.json +204 -71
  281. package/types.ts +221 -0
  282. package/dist/bundled/es5/index.js +0 -2
  283. package/dist/bundled/es5/index.js.map +0 -1
  284. package/dist/bundled/es6/index.js +0 -2
  285. package/dist/bundled/es6/index.js.map +0 -1
  286. package/dist/cjs/index.d.ts +0 -19
  287. package/dist/cjs/index.js.map +0 -1
  288. package/dist/cjs/types.d.ts +0 -94
  289. package/dist/cjs/types.js +0 -28
  290. package/dist/cjs/types.js.map +0 -1
  291. package/dist/cjs/utils/api/api.d.ts +0 -10
  292. package/dist/cjs/utils/api/api.js +0 -40
  293. package/dist/cjs/utils/api/api.js.map +0 -1
  294. package/dist/cjs/utils/config/build-configs.d.ts +0 -6
  295. package/dist/cjs/utils/config/build-configs.js +0 -68
  296. package/dist/cjs/utils/config/build-configs.js.map +0 -1
  297. package/dist/cjs/utils/features/features.d.ts +0 -5
  298. package/dist/cjs/utils/features/features.js +0 -14
  299. package/dist/cjs/utils/features/features.js.map +0 -1
  300. package/dist/cjs/utils/features/initialize.d.ts +0 -5
  301. package/dist/cjs/utils/features/initialize.js +0 -51
  302. package/dist/cjs/utils/features/initialize.js.map +0 -1
  303. package/dist/es/index.d.ts +0 -19
  304. package/dist/es/index.js +0 -55
  305. package/dist/es/index.js.map +0 -1
  306. package/dist/es/types.d.ts +0 -94
  307. package/dist/es/types.js +0 -24
  308. package/dist/es/types.js.map +0 -1
  309. package/dist/es/utils/api/api.d.ts +0 -10
  310. package/dist/es/utils/api/api.js +0 -36
  311. package/dist/es/utils/api/api.js.map +0 -1
  312. package/dist/es/utils/config/build-configs.d.ts +0 -6
  313. package/dist/es/utils/config/build-configs.js +0 -64
  314. package/dist/es/utils/config/build-configs.js.map +0 -1
  315. package/dist/es/utils/features/features.d.ts +0 -5
  316. package/dist/es/utils/features/features.js +0 -10
  317. package/dist/es/utils/features/features.js.map +0 -1
  318. package/dist/es/utils/features/initialize.d.ts +0 -5
  319. package/dist/es/utils/features/initialize.js +0 -24
  320. package/dist/es/utils/features/initialize.js.map +0 -1
  321. package/dist/umd/index.d.ts +0 -19
  322. package/dist/umd/index.js +0 -69
  323. package/dist/umd/index.js.map +0 -1
  324. package/dist/umd/types.d.ts +0 -94
  325. package/dist/umd/types.js +0 -38
  326. package/dist/umd/types.js.map +0 -1
  327. package/dist/umd/utils/api/api.d.ts +0 -10
  328. package/dist/umd/utils/api/api.js +0 -50
  329. package/dist/umd/utils/api/api.js.map +0 -1
  330. package/dist/umd/utils/config/build-configs.d.ts +0 -6
  331. package/dist/umd/utils/config/build-configs.js +0 -78
  332. package/dist/umd/utils/config/build-configs.js.map +0 -1
  333. package/dist/umd/utils/features/features.d.ts +0 -5
  334. package/dist/umd/utils/features/features.js +0 -24
  335. package/dist/umd/utils/features/features.js.map +0 -1
  336. package/dist/umd/utils/features/initialize.d.ts +0 -5
  337. package/dist/umd/utils/features/initialize.js +0 -63
  338. package/dist/umd/utils/features/initialize.js.map +0 -1
  339. package/dist/webpack-analysis.html +0 -38
@@ -0,0 +1,150 @@
1
+ /*
2
+ * Copyright 2020 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import { handle } from '../../../common/event-emitter/handle';
7
+ import { now } from '../../../common/timing/now';
8
+ import { getOrSet } from '../../../common/util/get-or-set';
9
+ import { wrapRaf, wrapTimer, wrapEvents, wrapXhr } from '../../../common/wrap';
10
+ import slice from 'lodash._slice';
11
+ import './debug';
12
+ import { InstrumentBase } from '../../utils/instrument-base';
13
+ import { FEATURE_NAME, NR_ERR_PROP } from '../constants';
14
+ import { FEATURE_NAMES } from '../../../loaders/features/features';
15
+ import { globalScope } from '../../../common/util/global-scope';
16
+ import { eventListenerOpts } from '../../../common/event-listener/event-listener-opts';
17
+ import { getRuntime } from '../../../common/config/config';
18
+ import { stringify } from '../../../common/util/stringify';
19
+ export class Instrument extends InstrumentBase {
20
+ static featureName = FEATURE_NAME;
21
+ constructor(agentIdentifier, aggregator, auto = true) {
22
+ super(agentIdentifier, aggregator, FEATURE_NAME, auto);
23
+ // skipNext counter to keep track of uncaught
24
+ // errors that will be the same as caught errors.
25
+ this.skipNext = 0;
26
+ this.origOnerror = globalScope.onerror;
27
+ try {
28
+ this.removeOnAbort = new AbortController();
29
+ } // this try-catch can be removed when IE11 is completely unsupported & gone
30
+ catch (e) {}
31
+ const thisInstrument = this;
32
+ thisInstrument.ee.on('fn-start', function (args, obj, methodName) {
33
+ if (thisInstrument.abortHandler) thisInstrument.skipNext += 1;
34
+ });
35
+ thisInstrument.ee.on('fn-err', function (args, obj, err) {
36
+ if (thisInstrument.abortHandler && !err[NR_ERR_PROP]) {
37
+ getOrSet(err, NR_ERR_PROP, function getVal() {
38
+ return true;
39
+ });
40
+ this.thrown = true;
41
+ notice(err, undefined, thisInstrument.ee);
42
+ }
43
+ });
44
+ thisInstrument.ee.on('fn-end', function () {
45
+ if (!thisInstrument.abortHandler) return;
46
+ if (!this.thrown && thisInstrument.skipNext > 0) thisInstrument.skipNext -= 1;
47
+ });
48
+ thisInstrument.ee.on('internal-error', function (e) {
49
+ handle('ierr', [e, now(), true], undefined, FEATURE_NAMES.jserrors, thisInstrument.ee);
50
+ });
51
+
52
+ // Tack on our error handler onto the existing global one.
53
+ globalScope.onerror = (...args) => {
54
+ if (this.origOnerror) this.origOnerror(...args);
55
+ this.onerrorHandler(...args);
56
+ return false;
57
+ };
58
+ globalScope.addEventListener('unhandledrejection', e => {
59
+ /** rejections can contain data of any type -- this is an effort to keep the message human readable */
60
+ const err = castReasonToError(e.reason);
61
+ handle('err', [err, now(), false, {
62
+ unhandledPromiseRejection: 1
63
+ }], undefined, FEATURE_NAMES.jserrors, this.ee);
64
+ }, eventListenerOpts(false, this.removeOnAbort?.signal));
65
+ wrapRaf(this.ee);
66
+ wrapTimer(this.ee);
67
+ wrapEvents(this.ee);
68
+ if (getRuntime(agentIdentifier).xhrWrappable) wrapXhr(this.ee);
69
+ this.abortHandler = this.#abort; // we also use this as a flag to denote that the feature is active or on and handling errors
70
+ this.importAggregator();
71
+ }
72
+
73
+ /** Restoration and resource release tasks to be done if JS error loader is being aborted. Unwind changes to globals. */
74
+ #abort() {
75
+ this.removeOnAbort?.abort();
76
+ this.abortHandler = undefined; // weakly allow this abort op to run only once
77
+ }
78
+
79
+ /**
80
+ * FF and Android browsers do not provide error info to the 'error' event callback,
81
+ * so we must use window.onerror
82
+ * @param {string} message
83
+ * @param {string} filename
84
+ * @param {number} lineno
85
+ * @param {number} column
86
+ * @param {Error | *} errorObj
87
+ * @returns
88
+ */
89
+ onerrorHandler(message, filename, lineno, column, errorObj) {
90
+ try {
91
+ if (this.skipNext) this.skipNext -= 1;else notice(errorObj || new UncaughtException(message, filename, lineno), true, this.ee);
92
+ } catch (e) {
93
+ try {
94
+ handle('ierr', [e, now(), true], undefined, FEATURE_NAMES.jserrors, this.ee);
95
+ } catch (err) {
96
+ // do nothing
97
+ }
98
+ }
99
+ if (typeof this.origOnerror === 'function') return this.origOnerror.apply(this, slice(arguments));
100
+ return false;
101
+ }
102
+ }
103
+
104
+ /**
105
+ *
106
+ * @param {string} message
107
+ * @param {string} filename
108
+ * @param {number} lineno
109
+ */
110
+ function UncaughtException(message, filename, lineno) {
111
+ this.message = message || 'Uncaught error with no additional information';
112
+ this.sourceURL = filename;
113
+ this.line = lineno;
114
+ }
115
+
116
+ /**
117
+ * Adds a timestamp and emits the 'err' event, which the error aggregator listens for
118
+ * @param {Error} err
119
+ * @param {boolean} doNotStamp
120
+ * @param {ContextualEE} ee
121
+ */
122
+ function notice(err, doNotStamp, ee) {
123
+ // by default add timestamp, unless specifically told not to
124
+ // this is to preserve existing behavior
125
+ var time = !doNotStamp ? now() : null;
126
+ handle('err', [err, time], undefined, FEATURE_NAMES.jserrors, ee);
127
+ }
128
+
129
+ /**
130
+ * Attempts to cast an unhandledPromiseRejection reason (reject(...)) to an Error object
131
+ * @param {*} reason - The reason property from an unhandled promise rejection
132
+ * @returns {Error} - An Error object with the message as the casted reason
133
+ */
134
+ function castReasonToError(reason) {
135
+ let prefix = 'Unhandled Promise Rejection: ';
136
+ if (reason instanceof Error) {
137
+ try {
138
+ reason.message = prefix + reason.message;
139
+ return reason;
140
+ } catch (e) {
141
+ return reason;
142
+ }
143
+ }
144
+ if (typeof reason === 'undefined') return new Error(prefix);
145
+ try {
146
+ return new Error(prefix + stringify(reason));
147
+ } catch (err) {
148
+ return new Error(prefix);
149
+ }
150
+ }
@@ -0,0 +1,129 @@
1
+ import { getRuntime } from '../../../common/config/config';
2
+ import { registerHandler } from '../../../common/event-emitter/register-handler';
3
+ import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
4
+ import { AggregateBase } from '../../utils/aggregate-base';
5
+ import { FEATURE_NAME, SUPPORTABILITY_METRIC, CUSTOM_METRIC, SUPPORTABILITY_METRIC_CHANNEL, CUSTOM_METRIC_CHANNEL } from '../constants';
6
+ import { drain } from '../../../common/drain/drain';
7
+ import { getFrameworks } from '../../../common/metrics/framework-detection';
8
+ import { protocol } from '../../../common/url/protocol';
9
+ import { getRules, validateRules } from '../../../common/util/obfuscate';
10
+ import { VERSION } from '../../../common/constants/environment-variables';
11
+ import { onDOMContentLoaded } from '../../../common/window/load';
12
+ import { windowAddEventListener } from '../../../common/event-listener/event-listener-opts';
13
+ import { isBrowserScope } from '../../../common/util/global-scope';
14
+ export class Aggregate extends AggregateBase {
15
+ static featureName = FEATURE_NAME;
16
+ constructor(agentIdentifier, aggregator) {
17
+ super(agentIdentifier, aggregator, FEATURE_NAME);
18
+ let scheduler;
19
+
20
+ // If RUM-call's response determines that customer lacks entitlements for the /jserror ingest endpoint, don't harvest at all.
21
+ registerHandler('block-err', () => {
22
+ this.blocked = true;
23
+ if (scheduler) scheduler.aborted = true; // RUM response may or may not have happened already before scheduler initialization below
24
+ }, this.featureName, this.ee);
25
+
26
+ // Allow features external to the metrics feature to capture SMs and CMs through the event emitter
27
+ registerHandler(SUPPORTABILITY_METRIC_CHANNEL, this.storeSupportabilityMetrics.bind(this), this.featureName, this.ee);
28
+ registerHandler(CUSTOM_METRIC_CHANNEL, this.storeEventMetrics.bind(this), this.featureName, this.ee);
29
+ this.singleChecks(); // checks that are run only one time, at script load
30
+ this.eachSessionChecks(); // the start of every time user engages with page
31
+
32
+ // *cli, Mar 23 - Per NR-94597, this feature should only harvest ONCE at the (potential) EoL time of the page.
33
+ scheduler = new HarvestScheduler('jserrors', {
34
+ onUnload: () => this.unload()
35
+ }, this);
36
+ scheduler.harvest.on('jserrors', () => ({
37
+ body: this.aggregator.take(['cm', 'sm'])
38
+ }));
39
+ drain(this.agentIdentifier, this.featureName); // regardless if this is blocked or not, drain is needed to unblock other features from harvesting (counteract registerDrain)
40
+ }
41
+
42
+ storeSupportabilityMetrics(name, value) {
43
+ if (this.blocked) return;
44
+ const type = SUPPORTABILITY_METRIC;
45
+ const params = {
46
+ name
47
+ };
48
+ this.aggregator.storeMetric(type, name, params, value);
49
+ }
50
+ storeEventMetrics(name, metrics) {
51
+ if (this.blocked) return;
52
+ const type = CUSTOM_METRIC;
53
+ const params = {
54
+ name
55
+ };
56
+ this.aggregator.store(type, name, params, metrics);
57
+ }
58
+ singleChecks() {
59
+ // report generic info about the agent itself
60
+ // note the browser agent version
61
+ this.storeSupportabilityMetrics(`Generic/Version/${VERSION}/Detected`);
62
+ // report loaderType
63
+ const {
64
+ distMethod,
65
+ loaderType
66
+ } = getRuntime(this.agentIdentifier);
67
+ if (loaderType) this.storeSupportabilityMetrics(`Generic/LoaderType/${loaderType}/Detected`);
68
+ if (distMethod) this.storeSupportabilityMetrics(`Generic/DistMethod/${distMethod}/Detected`);
69
+
70
+ // frameworks on page
71
+ if (isBrowserScope) {
72
+ onDOMContentLoaded(() => {
73
+ getFrameworks().forEach(framework => {
74
+ this.storeSupportabilityMetrics('Framework/' + framework + '/Detected');
75
+ });
76
+ });
77
+ }
78
+
79
+ // file protocol detection
80
+ if (protocol.isFileProtocol()) {
81
+ this.storeSupportabilityMetrics('Generic/FileProtocol/Detected');
82
+ protocol.supportabilityMetricSent = true;
83
+ }
84
+
85
+ // obfuscation rules detection
86
+ const rules = getRules(this.agentIdentifier);
87
+ if (rules.length > 0) this.storeSupportabilityMetrics('Generic/Obfuscate/Detected');
88
+ if (rules.length > 0 && !validateRules(rules)) this.storeSupportabilityMetrics('Generic/Obfuscate/Invalid');
89
+ }
90
+ eachSessionChecks() {
91
+ if (!isBrowserScope) return;
92
+
93
+ // [Temporary] Report restores from BFCache to NR1 while feature flag is in place in lieu of sending pageshow events.
94
+ windowAddEventListener('pageshow', evt => {
95
+ if (evt.persisted) {
96
+ this.storeSupportabilityMetrics('Generic/BFCache/PageRestored');
97
+ }
98
+ return;
99
+ });
100
+ }
101
+ unload() {
102
+ // Page Resources detection for estimations with resources feature work
103
+ // TODO - these SMs are to be removed when we implement the actual resources feature
104
+ try {
105
+ if (this.resourcesSent) return;
106
+ // make sure this only gets sent once
107
+ this.resourcesSent = true;
108
+ // differentiate between internal+external and ajax+non-ajax
109
+ const ajaxResources = ['beacon', 'fetch', 'xmlhttprequest'];
110
+ const internalUrls = ['nr-data.net', 'newrelic.com', 'nr-local.net', 'localhost'];
111
+ function isInternal(x) {
112
+ return internalUrls.some(y => x.name.indexOf(y) >= 0);
113
+ }
114
+ function isAjax(x) {
115
+ return ajaxResources.includes(x.initiatorType);
116
+ }
117
+ const allResources = performance?.getEntriesByType('resource') || [];
118
+ allResources.forEach(entry => {
119
+ if (isInternal(entry)) {
120
+ if (isAjax(entry)) this.storeSupportabilityMetrics('Generic/Resources/Ajax/Internal');else this.storeSupportabilityMetrics('Generic/Resources/Non-Ajax/Internal');
121
+ } else {
122
+ if (isAjax(entry)) this.storeSupportabilityMetrics('Generic/Resources/Ajax/External');else this.storeSupportabilityMetrics('Generic/Resources/Non-Ajax/External');
123
+ }
124
+ });
125
+ } catch (e) {
126
+ // do nothing
127
+ }
128
+ }
129
+ }
@@ -0,0 +1,6 @@
1
+ import { FEATURE_NAMES } from '../../loaders/features/features';
2
+ export const FEATURE_NAME = FEATURE_NAMES.metrics;
3
+ export const SUPPORTABILITY_METRIC = 'sm';
4
+ export const CUSTOM_METRIC = 'cm';
5
+ export const SUPPORTABILITY_METRIC_CHANNEL = 'storeSupportabilityMetrics';
6
+ export const CUSTOM_METRIC_CHANNEL = 'storeEventMetrics';
@@ -0,0 +1 @@
1
+ export { Instrument as Metrics } from './instrument/index';
@@ -0,0 +1,13 @@
1
+ import { InstrumentBase } from '../../utils/instrument-base';
2
+ import { insertSupportMetrics } from './workers-helper';
3
+ import { FEATURE_NAME, SUPPORTABILITY_METRIC_CHANNEL } from '../constants';
4
+ import { handle } from '../../../common/event-emitter/handle';
5
+ import { FEATURE_NAMES } from '../../../loaders/features/features';
6
+ export class Instrument extends InstrumentBase {
7
+ static featureName = FEATURE_NAME;
8
+ constructor(agentIdentifier, aggregator, auto = true) {
9
+ super(agentIdentifier, aggregator, FEATURE_NAME, auto);
10
+ insertSupportMetrics(tag => handle(SUPPORTABILITY_METRIC_CHANNEL, [tag], undefined, FEATURE_NAMES.metrics, this.ee));
11
+ this.importAggregator();
12
+ }
13
+ }
@@ -0,0 +1,116 @@
1
+ import { globalScope, isWorkerScope } from '../../../common/util/global-scope';
2
+ import { warn } from '../../../common/util/console';
3
+
4
+ /**
5
+ * True for each Worker type supported in browser's execution context. Not all browser versions may support certain Workers or options however.
6
+ * - Warning: service workers are not available on unsecured HTTP sites
7
+ */
8
+ const workersApiIsSupported = {
9
+ dedicated: Boolean(globalScope?.Worker),
10
+ shared: Boolean(globalScope?.SharedWorker),
11
+ service: Boolean(globalScope?.navigator?.serviceWorker)
12
+ };
13
+ let origWorker, origSharedWorker, origServiceWorkerCreate;
14
+ /**
15
+ * Un-instrument support metrics for Workers.
16
+ * @returns void
17
+ */
18
+ function resetSupportability() {
19
+ if (origWorker) globalScope.Worker = origWorker; // Worker was changed by this module
20
+ if (origSharedWorker) globalScope.SharedWorker = origSharedWorker;
21
+ if (origServiceWorkerCreate) globalScope.navigator.serviceWorker.register = origServiceWorkerCreate;
22
+ origWorker = origSharedWorker = origServiceWorkerCreate = undefined;
23
+ }
24
+
25
+ /**
26
+ * Injects code to report Web Workers supportability and usage as metrics, replacing the native API in global scope as a side effect.
27
+ * @param {Function} report - a cb used to report data
28
+ * @returns void
29
+ */
30
+ export function insertSupportMetrics(report) {
31
+ // Of the 3, the normal worker is the most widely supported, so we can be sure metric was already inserted w/o checking other 2.
32
+ if (origWorker) return;
33
+ if (!workersApiIsSupported.dedicated) {
34
+ reportUnavailable('All');
35
+ return; // similarly, if dedicated is n/a, none of them are supported so quit
36
+ } else {
37
+ origWorker = Worker;
38
+ try {
39
+ globalScope.Worker = extendWorkerConstructor(origWorker, 'Dedicated');
40
+ } catch (e) {
41
+ handleInsertionError(e, 'Dedicated');
42
+ }
43
+ }
44
+ if (!workersApiIsSupported.shared) {
45
+ reportUnavailable('Shared');
46
+ } else {
47
+ origSharedWorker = SharedWorker;
48
+ try {
49
+ globalScope.SharedWorker = extendWorkerConstructor(origSharedWorker, 'Shared');
50
+ } catch (e) {
51
+ handleInsertionError(e, 'Shared');
52
+ }
53
+ }
54
+ if (!workersApiIsSupported.service) {
55
+ reportUnavailable('Service');
56
+ } else {
57
+ origServiceWorkerCreate = navigator.serviceWorker.register;
58
+ try {
59
+ globalScope.navigator.serviceWorker.register = extendServiceCreation(origServiceWorkerCreate);
60
+ } catch (e) {
61
+ handleInsertionError(e, 'Service');
62
+ }
63
+ }
64
+ return;
65
+
66
+ // Internal helpers - Core
67
+ /**
68
+ * Report each time a Worker or SharedWorker is created in page execution. Note the current trap is set for only "new" and Reflect.construct operations.
69
+ * @param {func obj} origClass - Worker() or SharedWorker()
70
+ * @param {string} workerType - 'Dedicated' or 'Shared'
71
+ * @returns Proxy worker that intercepts the original constructor
72
+ */
73
+ function extendWorkerConstructor(origClass, workerType) {
74
+ if (typeof Proxy === 'undefined') {
75
+ return origClass;
76
+ }
77
+ const newHandler = {
78
+ construct(oConstructor, args) {
79
+ reportWorkerCreationAttempt(workerType, args[1]?.type);
80
+ return new oConstructor(...args);
81
+ }
82
+ };
83
+ // eslint-disable-next-line
84
+ return new Proxy(origClass, newHandler);
85
+ }
86
+ /**
87
+ * Report each time a ServiceWorkerRegistration is created or updated in page execution.
88
+ * @param {func} origFunc - method responsible for creating a ServiceWorker
89
+ * @returns Refer to ServiceWorkerContainer.register()
90
+ */
91
+ function extendServiceCreation(origFunc) {
92
+ return (...args) => {
93
+ reportWorkerCreationAttempt('Service', args[1]?.type);
94
+ return origFunc.apply(navigator.serviceWorker, args); // register() has to be rebound to the ServiceWorkerContainer object
95
+ };
96
+ }
97
+
98
+ // Internal helpers - Reporting & logging
99
+ function reportUnavailable(workerType) {
100
+ if (isWorkerScope) return; // assume that the main browser window has already reported unsupported worker APIs (once per page life);
101
+ // on top of that, not all workers are available inside a certain worker per se--e.g. no sharedWorker() inside Worker
102
+ report(`Workers/${workerType}/Unavailable`);
103
+ }
104
+ function reportWorkerCreationAttempt(workerType, optionType) {
105
+ if (optionType === 'module') {
106
+ report(`Workers/${workerType}/Module`);
107
+ } else {
108
+ report(`Workers/${workerType}/Classic`);
109
+ }
110
+ }
111
+ function handleInsertionError(e, workerType) {
112
+ // indicates the browser version doesn't support how code is injected, such as Proxy API
113
+ report(`Workers/${workerType}/SM/Unsupported`); // expected to be niche & for older borderline-ES6 browser versions
114
+ warn(`NR Agent: Unable to capture ${workerType} workers.`, e);
115
+ }
116
+ }
@@ -0,0 +1,105 @@
1
+ /*
2
+ * Copyright 2020 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import { mapOwn } from '../../../common/util/map-own';
7
+ import { stringify } from '../../../common/util/stringify';
8
+ import { registerHandler as register } from '../../../common/event-emitter/register-handler';
9
+ import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
10
+ import { cleanURL } from '../../../common/url/clean-url';
11
+ import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config';
12
+ import { AggregateBase } from '../../utils/aggregate-base';
13
+ import { FEATURE_NAME } from '../constants';
14
+ import { drain } from '../../../common/drain/drain';
15
+ import { isBrowserScope } from '../../../common/util/global-scope';
16
+ export class Aggregate extends AggregateBase {
17
+ static featureName = FEATURE_NAME;
18
+ constructor(agentIdentifier, aggregator) {
19
+ super(agentIdentifier, aggregator, FEATURE_NAME);
20
+ this.eventsPerMinute = 240;
21
+ this.harvestTimeSeconds = getConfigurationValue(this.agentIdentifier, 'page_action.harvestTimeSeconds') || getConfigurationValue(this.agentIdentifier, 'ins.harvestTimeSeconds') || 30;
22
+ this.eventsPerHarvest = this.eventsPerMinute * this.harvestTimeSeconds / 60;
23
+ this.referrerUrl;
24
+ this.currentEvents;
25
+ this.events = [];
26
+ this.att = getInfo(this.agentIdentifier).jsAttributes; // per-agent, aggregators-shared info context
27
+
28
+ if (isBrowserScope && document.referrer) this.referrerUrl = cleanURL(document.referrer);
29
+ register('api-addPageAction', (...args) => this.addPageAction(...args), this.featureName, this.ee);
30
+ var scheduler = new HarvestScheduler('ins', {
31
+ onFinished: (...args) => this.onHarvestFinished(...args)
32
+ }, this);
33
+ scheduler.harvest.on('ins', (...args) => this.onHarvestStarted(...args));
34
+ this.ee.on(`drain-${this.featureName}`, () => {
35
+ if (!this.blocked) scheduler.startTimer(this.harvestTimeSeconds, 0);
36
+ });
37
+
38
+ // if rum response determines that customer lacks entitlements for ins endpoint, block it
39
+ register('block-ins', () => {
40
+ this.blocked = true;
41
+ scheduler.stopTimer(true);
42
+ }, this.featureName, this.ee);
43
+ drain(this.agentIdentifier, this.featureName);
44
+ }
45
+ onHarvestStarted(options) {
46
+ const {
47
+ userAttributes,
48
+ atts
49
+ } = getInfo(this.agentIdentifier);
50
+ var payload = {
51
+ qs: {
52
+ ua: userAttributes,
53
+ at: atts
54
+ },
55
+ body: {
56
+ ins: this.events
57
+ }
58
+ };
59
+ if (options.retry) {
60
+ this.currentEvents = this.events;
61
+ }
62
+ this.events = [];
63
+ return payload;
64
+ }
65
+ onHarvestFinished(result) {
66
+ if (result && result.sent && result.retry && this.currentEvents) {
67
+ this.events = this.events.concat(this.currentEvents);
68
+ this.currentEvents = null;
69
+ }
70
+ }
71
+
72
+ // WARNING: Insights times are in seconds. EXCEPT timestamp, which is in ms.
73
+ addPageAction(t, name, attributes) {
74
+ if (this.events.length >= this.eventsPerHarvest || this.blocked) return;
75
+ var width;
76
+ var height;
77
+ var eventAttributes = {};
78
+ if (isBrowserScope && window.document.documentElement) {
79
+ // Doesn't include the nav bar when it disappears in mobile safari
80
+ // https://github.com/jquery/jquery/blob/10399ddcf8a239acc27bdec9231b996b178224d3/src/dimensions.js#L23
81
+ width = window.document.documentElement.clientWidth;
82
+ height = window.document.documentElement.clientHeight;
83
+ }
84
+ var defaults = {
85
+ timestamp: t + getRuntime(this.agentIdentifier).offset,
86
+ timeSinceLoad: t / 1000,
87
+ browserWidth: width,
88
+ browserHeight: height,
89
+ referrerUrl: this.referrerUrl,
90
+ currentUrl: cleanURL('' + location),
91
+ pageUrl: cleanURL(getRuntime(this.agentIdentifier).origin),
92
+ eventType: 'PageAction'
93
+ };
94
+ mapOwn(defaults, set);
95
+ mapOwn(getInfo(this.agentIdentifier).jsAttributes, set);
96
+ if (attributes && typeof attributes === 'object') {
97
+ mapOwn(attributes, set);
98
+ }
99
+ eventAttributes.actionName = name || '';
100
+ this.events.push(eventAttributes);
101
+ function set(key, val) {
102
+ eventAttributes[key] = val && typeof val === 'object' ? stringify(val) : val;
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,2 @@
1
+ import { FEATURE_NAMES } from '../../loaders/features/features';
2
+ export const FEATURE_NAME = FEATURE_NAMES.pageAction;
@@ -0,0 +1 @@
1
+ export { Instrument as PageAction } from './instrument/index';
@@ -0,0 +1,14 @@
1
+ /*
2
+ * Copyright 2020 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import { InstrumentBase } from '../../utils/instrument-base';
7
+ import { FEATURE_NAME } from '../constants';
8
+ export class Instrument extends InstrumentBase {
9
+ static featureName = FEATURE_NAME;
10
+ constructor(agentIdentifier, aggregator, auto = true) {
11
+ super(agentIdentifier, aggregator, FEATURE_NAME, auto);
12
+ this.importAggregator();
13
+ }
14
+ }
@@ -0,0 +1,124 @@
1
+ import { handle } from '../../../common/event-emitter/handle';
2
+ import { FEATURE_NAMES } from '../../../loaders/features/features';
3
+ import { isiOS } from '../../../common/browser-version/ios-version';
4
+ import { onTTFB } from 'web-vitals';
5
+ import { mapOwn } from '../../../common/util/map-own';
6
+ import { param, fromArray } from '../../../common/url/encode';
7
+ import { addPT, addPN } from '../../../common/timing/nav-timing';
8
+ import { stringify } from '../../../common/util/stringify';
9
+ import { paintMetrics } from '../../../common/metrics/paint-metrics';
10
+ import { submitData } from '../../../common/util/submit-data';
11
+ import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config';
12
+ import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
13
+ import { AggregateBase } from '../../utils/aggregate-base';
14
+ import * as CONSTANTS from '../constants';
15
+ import { getActivatedFeaturesFlags } from './initialized-features';
16
+ import { globalScope, isBrowserScope } from '../../../common/util/global-scope';
17
+ import { drain } from '../../../common/drain/drain';
18
+ const jsonp = 'NREUM.setToken';
19
+ export class Aggregate extends AggregateBase {
20
+ static featureName = CONSTANTS.FEATURE_NAME;
21
+ constructor(agentIdentifier, aggregator) {
22
+ super(agentIdentifier, aggregator, CONSTANTS.FEATURE_NAME);
23
+ if (typeof PerformanceNavigationTiming !== 'undefined' && !isiOS) {
24
+ this.alreadySent = false; // we don't support timings on BFCache restores
25
+ const agentRuntime = getRuntime(agentIdentifier); // we'll store timing values on the runtime obj to be read by the aggregate module
26
+
27
+ /* Time To First Byte
28
+ This listener must record these values *before* PVE's aggregate sends RUM. */
29
+ onTTFB(({
30
+ value,
31
+ entries
32
+ }) => {
33
+ if (this.alreadySent) return;
34
+ this.alreadySent = true;
35
+ agentRuntime[CONSTANTS.TTFB] = Math.round(value); // this is our "backend" duration; web-vitals will ensure it's lower bounded at 0
36
+
37
+ // Similar to what vitals does for ttfb, we have to factor in activation-start when calculating relative timings:
38
+ const navEntry = entries[0];
39
+ const respOrActivStart = Math.max(navEntry.responseStart, navEntry.activationStart || 0);
40
+ agentRuntime[CONSTANTS.FBTWL] = Math.max(Math.round(navEntry.loadEventEnd - respOrActivStart), 0); // our "frontend" duration
41
+ handle('timing', ['load', Math.round(navEntry.loadEventEnd)], undefined, FEATURE_NAMES.pageViewTiming, this.ee);
42
+ agentRuntime[CONSTANTS.FBTDC] = Math.max(Math.round(navEntry.domContentLoadedEventEnd - respOrActivStart), 0); // our "dom processing" duration
43
+
44
+ this.sendRum();
45
+ });
46
+ } else {
47
+ this.sendRum(); // timings either already in runtime from instrument or is meant to get 0'd.
48
+ }
49
+ }
50
+
51
+ getScheme() {
52
+ return getConfigurationValue(this.agentIdentifier, 'ssl') === false ? 'http' : 'https';
53
+ }
54
+ sendRum() {
55
+ const info = getInfo(this.agentIdentifier);
56
+ if (!info.beacon) return;
57
+ if (info.queueTime) this.aggregator.store('measures', 'qt', {
58
+ value: info.queueTime
59
+ });
60
+ if (info.applicationTime) this.aggregator.store('measures', 'ap', {
61
+ value: info.applicationTime
62
+ });
63
+ const agentRuntime = getRuntime(this.agentIdentifier);
64
+
65
+ // These 3 values should've been recorded after load and before this func runs. They are part of the minimum required for PageView events to be created.
66
+ // Following PR #428, which demands that all agents send RUM call, these need to be sent even outside of the main window context where PerformanceTiming
67
+ // or PerformanceNavigationTiming do not exists. Hence, they'll be filled in by 0s instead in, for example, worker threads that still init the PVE module.
68
+ this.aggregator.store('measures', 'be', {
69
+ value: isBrowserScope ? agentRuntime[CONSTANTS.TTFB] : 0
70
+ });
71
+ this.aggregator.store('measures', 'fe', {
72
+ value: isBrowserScope ? agentRuntime[CONSTANTS.FBTWL] : 0
73
+ });
74
+ this.aggregator.store('measures', 'dc', {
75
+ value: isBrowserScope ? agentRuntime[CONSTANTS.FBTDC] : 0
76
+ });
77
+ var measuresMetrics = this.aggregator.get('measures');
78
+ var measuresQueryString = mapOwn(measuresMetrics, function (metricName, measure) {
79
+ return '&' + metricName + '=' + measure.params.value;
80
+ }).join('');
81
+
82
+ // currently we only have one version of our protocol
83
+ // in the future we may add more
84
+ var protocol = '1';
85
+ var scheduler = new HarvestScheduler('page_view_event', {}, this);
86
+ var chunksForQueryString = [scheduler.harvest.baseQueryString()];
87
+ chunksForQueryString.push(measuresQueryString);
88
+ chunksForQueryString.push(param('tt', info.ttGuid));
89
+ chunksForQueryString.push(param('us', info.user));
90
+ chunksForQueryString.push(param('ac', info.account));
91
+ chunksForQueryString.push(param('pr', info.product));
92
+ chunksForQueryString.push(param('af', getActivatedFeaturesFlags(this.agentIdentifier).join(',')));
93
+ if (globalScope.performance && typeof globalScope.performance.timing !== 'undefined') {
94
+ var navTimingApiData = {
95
+ timing: addPT(agentRuntime.offset, globalScope.performance.timing, {}),
96
+ navigation: addPN(globalScope.performance.navigation, {})
97
+ };
98
+ chunksForQueryString.push(param('perf', stringify(navTimingApiData)));
99
+ }
100
+ try {
101
+ // PVTiming sends these too, albeit using web-vitals and slightly different; it's unknown why they're duplicated, but PVT should be the truth
102
+ var entries = globalScope.performance.getEntriesByType('paint');
103
+ entries.forEach(function (entry) {
104
+ if (!entry.startTime || entry.startTime <= 0) return;
105
+ if (entry.name === 'first-paint') {
106
+ chunksForQueryString.push(param('fp', String(Math.floor(entry.startTime))));
107
+ } else if (entry.name === 'first-contentful-paint') {
108
+ chunksForQueryString.push(param('fcp', String(Math.floor(entry.startTime))));
109
+ }
110
+ paintMetrics[entry.name] = Math.floor(entry.startTime); // this is consumed by Spa module
111
+ });
112
+ } catch (e) {}
113
+ chunksForQueryString.push(param('xx', info.extra));
114
+ chunksForQueryString.push(param('ua', info.userAttributes));
115
+ chunksForQueryString.push(param('at', info.atts));
116
+ var customJsAttributes = stringify(info.jsAttributes);
117
+ chunksForQueryString.push(param('ja', customJsAttributes === '{}' ? null : customJsAttributes));
118
+ var queryString = fromArray(chunksForQueryString, agentRuntime.maxBytes);
119
+ const isValidJsonp = submitData.jsonp(this.getScheme() + '://' + info.beacon + '/' + protocol + '/' + info.licenseKey + queryString, jsonp);
120
+ // Usually `drain` is invoked automatically after processing feature flags contained in the JSONP callback from
121
+ // ingest (see `activateFeatures`), so when JSONP cannot execute (as with module workers), we drain manually.
122
+ if (!isValidJsonp) drain(this.agentIdentifier, CONSTANTS.FEATURE_NAME);
123
+ }
124
+ }