@newrelic/browser-agent 1.232.0 → 1.233.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/dist/cjs/cdn/polyfills.js +5 -2
  2. package/dist/cjs/common/config/state/configurable.js +15 -26
  3. package/dist/cjs/common/config/state/info.js +1 -1
  4. package/dist/cjs/common/config/state/init.js +101 -56
  5. package/dist/cjs/common/config/state/loader-config.js +1 -1
  6. package/dist/cjs/common/config/state/runtime.js +1 -5
  7. package/dist/cjs/common/constants/env.cdn.js +1 -1
  8. package/dist/cjs/common/constants/env.npm.js +1 -1
  9. package/dist/cjs/common/drain/drain.js +1 -1
  10. package/dist/cjs/common/harvest/harvest-scheduler.js +30 -10
  11. package/dist/cjs/common/harvest/harvest.js +119 -55
  12. package/dist/cjs/common/session/session-entity.js +35 -22
  13. package/dist/cjs/common/session/session-entity.test.js +73 -49
  14. package/dist/cjs/common/timer/interaction-timer.js +9 -12
  15. package/dist/cjs/common/url/canonicalize-url.js +32 -0
  16. package/dist/cjs/common/url/canonicalize-url.test.js +42 -0
  17. package/dist/cjs/common/url/clean-url.js +10 -3
  18. package/dist/cjs/common/url/protocol.test.js +0 -1
  19. package/dist/cjs/common/util/feature-flags.js +2 -1
  20. package/dist/cjs/common/util/global-scope.js +4 -2
  21. package/dist/cjs/common/util/submit-data.js +57 -18
  22. package/dist/cjs/common/wrap/wrap-fetch.js +1 -3
  23. package/dist/cjs/common/wrap/wrap-function.js +1 -3
  24. package/dist/cjs/common/wrap/wrap-promise.js +1 -1
  25. package/dist/cjs/features/ajax/aggregate/index.js +2 -2
  26. package/dist/cjs/features/ajax/instrument/index.js +1 -1
  27. package/dist/cjs/features/jserrors/aggregate/canonical-function-name.js +12 -4
  28. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +93 -10
  29. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +164 -38
  30. package/dist/cjs/features/jserrors/aggregate/index.js +29 -48
  31. package/dist/cjs/features/jserrors/instrument/index.js +0 -2
  32. package/dist/cjs/features/metrics/aggregate/framework-detection.js +67 -0
  33. package/dist/cjs/features/metrics/aggregate/framework-detection.test.js +137 -0
  34. package/dist/cjs/features/metrics/aggregate/index.js +7 -3
  35. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.js +14 -0
  36. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.test.js +17 -0
  37. package/dist/cjs/features/metrics/aggregate/polyfill-detection.js +53 -0
  38. package/dist/cjs/features/metrics/aggregate/polyfill-detection.test.js +165 -0
  39. package/dist/cjs/features/page_action/aggregate/index.js +2 -2
  40. package/dist/cjs/features/page_view_event/aggregate/index.js +6 -3
  41. package/dist/cjs/features/page_view_timing/aggregate/index.js +2 -2
  42. package/dist/cjs/features/session_replay/aggregate/index.js +333 -0
  43. package/dist/cjs/features/session_replay/constants.js +9 -0
  44. package/dist/cjs/features/session_replay/index.js +12 -0
  45. package/dist/cjs/features/session_replay/instrument/index.js +29 -0
  46. package/dist/cjs/features/session_trace/aggregate/index.js +163 -164
  47. package/dist/cjs/features/session_trace/constants.js +2 -9
  48. package/dist/cjs/features/session_trace/instrument/index.js +24 -66
  49. package/dist/cjs/features/spa/aggregate/index.js +2 -2
  50. package/dist/cjs/features/utils/agent-session.js +1 -2
  51. package/dist/cjs/features/utils/aggregate-base.js +64 -0
  52. package/dist/cjs/features/utils/feature-base.js +0 -31
  53. package/dist/cjs/features/utils/handler-cache.js +3 -4
  54. package/dist/cjs/features/utils/instrument-base.js +42 -10
  55. package/dist/cjs/features/utils/{lazy-loader.js → lazy-feature-loader.js} +4 -2
  56. package/dist/cjs/loaders/agent.js +1 -1
  57. package/dist/cjs/loaders/api/apiAsync.js +3 -1
  58. package/dist/cjs/loaders/configure/configure.js +3 -3
  59. package/dist/cjs/loaders/features/featureDependencies.js +0 -12
  60. package/dist/cjs/loaders/features/features.js +3 -1
  61. package/dist/cjs/loaders/micro-agent.js +6 -6
  62. package/dist/esm/cdn/polyfills.js +5 -2
  63. package/dist/esm/common/config/state/configurable.js +14 -24
  64. package/dist/esm/common/config/state/info.js +2 -2
  65. package/dist/esm/common/config/state/init.js +102 -57
  66. package/dist/esm/common/config/state/loader-config.js +2 -2
  67. package/dist/esm/common/config/state/runtime.js +2 -4
  68. package/dist/esm/common/constants/env.cdn.js +1 -1
  69. package/dist/esm/common/constants/env.npm.js +1 -1
  70. package/dist/esm/common/drain/drain.js +1 -1
  71. package/dist/esm/common/harvest/harvest-scheduler.js +30 -10
  72. package/dist/esm/common/harvest/harvest.js +121 -56
  73. package/dist/esm/common/session/session-entity.js +35 -22
  74. package/dist/esm/common/session/session-entity.test.js +73 -49
  75. package/dist/esm/common/timer/interaction-timer.js +9 -12
  76. package/dist/esm/common/url/canonicalize-url.js +27 -0
  77. package/dist/esm/common/url/canonicalize-url.test.js +38 -0
  78. package/dist/esm/common/url/clean-url.js +10 -3
  79. package/dist/esm/common/url/protocol.test.js +0 -1
  80. package/dist/esm/common/util/feature-flags.js +2 -1
  81. package/dist/esm/common/util/global-scope.js +1 -0
  82. package/dist/esm/common/util/submit-data.js +57 -18
  83. package/dist/esm/common/wrap/wrap-fetch.js +1 -2
  84. package/dist/esm/common/wrap/wrap-function.js +1 -2
  85. package/dist/esm/common/wrap/wrap-promise.js +1 -1
  86. package/dist/esm/features/ajax/aggregate/index.js +2 -2
  87. package/dist/esm/features/ajax/instrument/index.js +1 -1
  88. package/dist/esm/features/jserrors/aggregate/canonical-function-name.js +12 -4
  89. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +93 -10
  90. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +149 -25
  91. package/dist/esm/features/jserrors/aggregate/index.js +30 -48
  92. package/dist/esm/features/jserrors/instrument/index.js +0 -1
  93. package/dist/esm/features/metrics/aggregate/framework-detection.js +61 -0
  94. package/dist/esm/features/metrics/aggregate/framework-detection.test.js +133 -0
  95. package/dist/esm/features/metrics/aggregate/index.js +7 -3
  96. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.js +8 -0
  97. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.test.js +15 -0
  98. package/dist/esm/features/metrics/aggregate/polyfill-detection.js +47 -0
  99. package/dist/esm/features/metrics/aggregate/polyfill-detection.test.js +163 -0
  100. package/dist/esm/features/page_action/aggregate/index.js +2 -2
  101. package/dist/esm/features/page_view_event/aggregate/index.js +6 -3
  102. package/dist/esm/features/page_view_timing/aggregate/index.js +2 -2
  103. package/dist/esm/features/session_replay/aggregate/index.js +327 -0
  104. package/dist/esm/features/session_replay/constants.js +2 -0
  105. package/dist/esm/features/session_replay/index.js +12 -0
  106. package/dist/esm/features/session_replay/instrument/index.js +21 -0
  107. package/dist/esm/features/session_trace/aggregate/index.js +163 -163
  108. package/dist/esm/features/session_trace/constants.js +1 -5
  109. package/dist/esm/features/session_trace/instrument/index.js +24 -66
  110. package/dist/esm/features/spa/aggregate/index.js +2 -2
  111. package/dist/esm/features/utils/agent-session.js +1 -2
  112. package/dist/esm/features/utils/aggregate-base.js +57 -0
  113. package/dist/esm/features/utils/feature-base.js +1 -32
  114. package/dist/esm/features/utils/handler-cache.js +3 -4
  115. package/dist/esm/features/utils/instrument-base.js +42 -10
  116. package/dist/esm/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
  117. package/dist/esm/loaders/agent.js +1 -1
  118. package/dist/esm/loaders/api/apiAsync.js +3 -1
  119. package/dist/esm/loaders/configure/configure.js +3 -3
  120. package/dist/esm/loaders/features/featureDependencies.js +0 -11
  121. package/dist/esm/loaders/features/features.js +3 -1
  122. package/dist/esm/loaders/micro-agent.js +6 -6
  123. package/dist/types/common/config/state/configurable.d.ts +1 -3
  124. package/dist/types/common/config/state/configurable.d.ts.map +1 -1
  125. package/dist/types/common/config/state/init.d.ts.map +1 -1
  126. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  127. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  128. package/dist/types/common/harvest/harvest.d.ts +37 -34
  129. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  130. package/dist/types/common/session/session-entity.d.ts +6 -3
  131. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  132. package/dist/types/common/timer/interaction-timer.d.ts +2 -1
  133. package/dist/types/common/timer/interaction-timer.d.ts.map +1 -1
  134. package/dist/types/common/url/canonicalize-url.d.ts +9 -0
  135. package/dist/types/common/url/canonicalize-url.d.ts.map +1 -0
  136. package/dist/types/common/url/clean-url.d.ts +7 -1
  137. package/dist/types/common/url/clean-url.d.ts.map +1 -1
  138. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  139. package/dist/types/common/util/global-scope.d.ts +1 -0
  140. package/dist/types/common/util/global-scope.d.ts.map +1 -1
  141. package/dist/types/common/util/submit-data.d.ts +40 -14
  142. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  143. package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
  144. package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
  145. package/dist/types/features/ajax/aggregate/index.d.ts +2 -2
  146. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  147. package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts +8 -1
  148. package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts.map +1 -1
  149. package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts +48 -19
  150. package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts.map +1 -1
  151. package/dist/types/features/jserrors/aggregate/index.d.ts +14 -5
  152. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  153. package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
  154. package/dist/types/features/metrics/aggregate/framework-detection.d.ts.map +1 -0
  155. package/dist/types/features/metrics/aggregate/index.d.ts +2 -2
  156. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  157. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts +6 -0
  158. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts.map +1 -0
  159. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts +7 -0
  160. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -0
  161. package/dist/types/features/page_action/aggregate/index.d.ts +3 -3
  162. package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
  163. package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -2
  164. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  165. package/dist/types/features/page_view_timing/aggregate/index.d.ts +2 -2
  166. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  167. package/dist/types/features/session_replay/aggregate/index.d.ts +96 -0
  168. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -0
  169. package/dist/types/features/session_replay/constants.d.ts +2 -0
  170. package/dist/types/features/session_replay/constants.d.ts.map +1 -0
  171. package/dist/types/features/session_replay/index.d.ts +2 -0
  172. package/dist/types/features/session_replay/index.d.ts.map +1 -0
  173. package/dist/types/features/session_replay/instrument/index.d.ts +6 -0
  174. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -0
  175. package/dist/types/features/session_trace/aggregate/index.d.ts +8 -57
  176. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  177. package/dist/types/features/session_trace/constants.d.ts +0 -3
  178. package/dist/types/features/session_trace/constants.d.ts.map +1 -1
  179. package/dist/types/features/session_trace/instrument/index.d.ts +1 -3
  180. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  181. package/dist/types/features/spa/aggregate/index.d.ts +2 -2
  182. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  183. package/dist/types/features/utils/agent-session.d.ts.map +1 -1
  184. package/dist/types/features/utils/aggregate-base.d.ts +11 -0
  185. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -0
  186. package/dist/types/features/utils/feature-base.d.ts +0 -5
  187. package/dist/types/features/utils/feature-base.d.ts.map +1 -1
  188. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  189. package/dist/types/features/utils/instrument-base.d.ts +3 -1
  190. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  191. package/dist/types/features/utils/{lazy-loader.d.ts → lazy-feature-loader.d.ts} +2 -2
  192. package/dist/types/features/utils/lazy-feature-loader.d.ts.map +1 -0
  193. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  194. package/dist/types/loaders/features/featureDependencies.d.ts +0 -1
  195. package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
  196. package/dist/types/loaders/features/features.d.ts +1 -0
  197. package/dist/types/loaders/features/features.d.ts.map +1 -1
  198. package/package.json +31 -22
  199. package/src/cdn/polyfills.js +4 -1
  200. package/src/common/config/state/configurable.js +18 -24
  201. package/src/common/config/state/info.js +2 -2
  202. package/src/common/config/state/init.js +62 -28
  203. package/src/common/config/state/loader-config.js +2 -2
  204. package/src/common/config/state/runtime.js +2 -4
  205. package/src/common/drain/drain.js +1 -1
  206. package/src/common/harvest/harvest-scheduler.js +35 -10
  207. package/src/common/harvest/harvest.js +73 -50
  208. package/src/common/session/session-entity.js +34 -23
  209. package/src/common/session/session-entity.test.js +57 -51
  210. package/src/common/timer/interaction-timer.js +9 -12
  211. package/src/common/url/canonicalize-url.js +28 -0
  212. package/src/common/url/canonicalize-url.test.js +34 -0
  213. package/src/common/url/clean-url.js +10 -3
  214. package/src/common/url/protocol.test.js +0 -1
  215. package/src/common/util/feature-flags.js +2 -2
  216. package/src/common/util/global-scope.js +2 -0
  217. package/src/common/util/submit-data.js +28 -17
  218. package/src/common/wrap/wrap-fetch.js +1 -2
  219. package/src/common/wrap/wrap-function.js +1 -2
  220. package/src/common/wrap/wrap-promise.js +1 -1
  221. package/src/features/ajax/aggregate/index.js +2 -2
  222. package/src/features/ajax/instrument/index.js +1 -1
  223. package/src/features/jserrors/aggregate/canonical-function-name.js +12 -4
  224. package/src/features/jserrors/aggregate/compute-stack-trace.js +85 -11
  225. package/src/features/jserrors/aggregate/compute-stack-trace.test.js +141 -24
  226. package/src/features/jserrors/aggregate/index.js +28 -52
  227. package/src/features/jserrors/instrument/index.js +0 -1
  228. package/src/features/metrics/aggregate/framework-detection.js +73 -0
  229. package/src/features/metrics/aggregate/framework-detection.test.js +201 -0
  230. package/src/features/metrics/aggregate/index.js +8 -3
  231. package/src/features/metrics/aggregate/polyfill-detection.es5.js +9 -0
  232. package/src/features/metrics/aggregate/polyfill-detection.es5.test.js +16 -0
  233. package/src/features/metrics/aggregate/polyfill-detection.js +48 -0
  234. package/src/features/metrics/aggregate/polyfill-detection.test.js +163 -0
  235. package/src/features/page_action/aggregate/index.js +2 -2
  236. package/src/features/page_view_event/aggregate/index.js +5 -5
  237. package/src/features/page_view_timing/aggregate/index.js +2 -2
  238. package/src/features/session_replay/aggregate/index.js +314 -0
  239. package/src/features/session_replay/constants.js +3 -0
  240. package/src/features/session_replay/index.js +12 -0
  241. package/src/features/session_replay/instrument/index.js +22 -0
  242. package/src/features/session_trace/aggregate/index.js +148 -188
  243. package/src/features/session_trace/constants.js +0 -4
  244. package/src/features/session_trace/instrument/index.js +17 -69
  245. package/src/features/spa/aggregate/index.js +2 -2
  246. package/src/features/utils/agent-session.js +1 -2
  247. package/src/features/utils/aggregate-base.js +51 -0
  248. package/src/features/utils/feature-base.js +1 -31
  249. package/src/features/utils/handler-cache.js +3 -4
  250. package/src/features/utils/instrument-base.js +40 -8
  251. package/src/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
  252. package/src/loaders/agent.js +1 -1
  253. package/src/loaders/api/apiAsync.js +1 -1
  254. package/src/loaders/configure/configure.js +4 -3
  255. package/src/loaders/features/featureDependencies.js +0 -12
  256. package/src/loaders/features/features.js +3 -1
  257. package/src/loaders/micro-agent.js +4 -4
  258. package/dist/cjs/common/metrics/framework-detection.js +0 -72
  259. package/dist/cjs/common/util/user-agent.js +0 -57
  260. package/dist/cjs/common/window/supports-performance-observer.js +0 -15
  261. package/dist/esm/common/metrics/framework-detection.js +0 -66
  262. package/dist/esm/common/util/user-agent.js +0 -48
  263. package/dist/esm/common/window/supports-performance-observer.js +0 -9
  264. package/dist/types/common/metrics/framework-detection.d.ts.map +0 -1
  265. package/dist/types/common/util/user-agent.d.ts +0 -5
  266. package/dist/types/common/util/user-agent.d.ts.map +0 -1
  267. package/dist/types/common/window/supports-performance-observer.d.ts +0 -2
  268. package/dist/types/common/window/supports-performance-observer.d.ts.map +0 -1
  269. package/dist/types/features/utils/lazy-loader.d.ts.map +0 -1
  270. package/src/common/metrics/framework-detection.js +0 -71
  271. package/src/common/util/user-agent.js +0 -56
  272. package/src/common/window/supports-performance-observer.js +0 -10
  273. /package/dist/types/{common/metrics → features/metrics/aggregate}/framework-detection.d.ts +0 -0
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.RRWEB_VERSION = exports.Aggregate = void 0;
7
+ var _drain = require("../../../common/drain/drain");
8
+ var _registerHandler = require("../../../common/event-emitter/register-handler");
9
+ var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
10
+ var _constants = require("../constants");
11
+ var _stringify = require("../../../common/util/stringify");
12
+ var _config = require("../../../common/config/config");
13
+ var _sessionEntity = require("../../../common/session/session-entity");
14
+ var _aggregateBase = require("../../utils/aggregate-base");
15
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
16
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /*
17
+ * Copyright 2023 New Relic Corporation. All rights reserved.
18
+ * SPDX-License-Identifier: Apache-2.0
19
+ */ /**
20
+ * @file Records, aggregates, and harvests session replay data.
21
+ *
22
+ * NOTE: This code is under development and dormant. It will not download to instrumented pages or record any data.
23
+ * It is not production ready, and is not intended to be imported or implemented in any build of the browser agent until
24
+ * functionality is validated and a full user experience is curated.
25
+ */
26
+ // would be better to get this dynamically in some way
27
+ const RRWEB_VERSION = '2.0.0-alpha.8';
28
+ exports.RRWEB_VERSION = RRWEB_VERSION;
29
+ let recorder, gzipper, u8;
30
+
31
+ /** The "mode" with which the session replay is recording */
32
+ const MODE = {
33
+ OFF: 0,
34
+ FULL: 1,
35
+ ERROR: 2
36
+ };
37
+ /** Vortex caps payload sizes at 1MB */
38
+ const MAX_PAYLOAD_SIZE = 1000000;
39
+ /** Unloading caps around 64kb */
40
+ const IDEAL_PAYLOAD_SIZE = 64000;
41
+ /** Interval between forcing new full snapshots in "error" mode */
42
+ const CHECKOUT_MS = 30000;
43
+ class Aggregate extends _aggregateBase.AggregateBase {
44
+ static featureName = _constants.FEATURE_NAME;
45
+ constructor(agentIdentifier, aggregator) {
46
+ super(agentIdentifier, aggregator, _constants.FEATURE_NAME);
47
+
48
+ /** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
49
+ this.events = [];
50
+ /** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
51
+ this.harvestTimeSeconds = (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay.harvestTimeSeconds') || 60;
52
+ /** Set once the recorder has fully initialized after flag checks and sampling */
53
+ this.initialized = false;
54
+ /** Set once an error has been detected on the page. */
55
+ this.errorNoticed = false;
56
+ /** The "mode" to record in. Defaults to "OFF" until flags and sampling are checked. See "MODE" constant. */
57
+ this.mode = MODE.OFF;
58
+ /** Set once the feature has been "aborted" to prevent other side-effects from continuing */
59
+ this.blocked = false;
60
+
61
+ /** Payload metadata -- Should indicate that the payload being sent is the first of a session */
62
+ this.isFirstChunk = false;
63
+ /** Payload metadata -- Should indicate that the payload being sent has a full DOM snapshot. This can happen
64
+ * -- When the recording library begins recording, it starts by taking a DOM snapshot
65
+ * -- When visibility changes from "hidden" -> "visible", it must capture a full snapshot for the replay to work correctly across tabs
66
+ */
67
+ this.hasSnapshot = false;
68
+ /** Payload metadata -- Should indicate that the payload being sent contains an error. Used for query/filter purposes in UI */
69
+ this.hasError = false;
70
+
71
+ /** A value which increments with every new mutation node reported. Resets after a harvest is sent */
72
+ this.payloadBytesEstimation = 0;
73
+
74
+ /** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
75
+ this.stopRecording = () => {/* no-op until set by rrweb initializer */};
76
+
77
+ // The SessionEntity class can emit a message indicating the session was cleared and reset (expiry, inactivity). This feature must abort and never resume if that occurs.
78
+ this.ee.on('session-reset', () => {
79
+ this.abort();
80
+ });
81
+
82
+ // The SessionEntity class can emit a message indicating the session was paused (visibility change). This feature must stop recording if that occurs.
83
+ this.ee.on(_sessionEntity.SESSION_EVENTS.PAUSE, () => {
84
+ this.stopRecording();
85
+ });
86
+ // The SessionEntity class can emit a message indicating the session was resumed (visibility change). This feature must start running again (if already running) if that occurs.
87
+ this.ee.on(_sessionEntity.SESSION_EVENTS.RESUME, () => {
88
+ if (!this.initialized || this.mode === MODE.OFF) return;
89
+ this.startRecording();
90
+ this.takeFullSnapshot();
91
+ });
92
+
93
+ // Bespoke logic for new endpoint. This will change as downstream dependencies become solidified.
94
+ this.scheduler = new _harvestScheduler.HarvestScheduler('blob', {
95
+ onFinished: this.onHarvestFinished.bind(this),
96
+ retryDelay: this.harvestTimeSeconds,
97
+ getPayload: this.prepareHarvest.bind(this),
98
+ // TODO -- this stuff needs a better way to be handled
99
+ includeBaseParams: false,
100
+ customUrl: 'https://vortex-alb.stg-single-tooth.cell.us.nr-data.net/blob',
101
+ raw: true,
102
+ gzip: true
103
+ }, this);
104
+
105
+ // Wait for an error to be reported. This currently is wrapped around the "Error" feature. This is a feature-feature dependency.
106
+ // This was to ensure that all errors, including those on the page before load and those handled with "noticeError" are accounted for. Needs evalulation
107
+ (0, _registerHandler.registerHandler)('errorAgg', e => {
108
+ this.hasError = true;
109
+ // run once
110
+ if (this.mode === MODE.ERROR) {
111
+ this.mode = MODE.FULL;
112
+ // if the error was noticed AFTER the recorder was already imported....
113
+ if (recorder && this.initialized) {
114
+ this.stopRecording();
115
+ this.startRecording();
116
+ this.scheduler.startTimer(this.harvestTimeSeconds);
117
+ const {
118
+ session
119
+ } = (0, _config.getRuntime)(this.agentIdentifier);
120
+ session.state.sessionReplay = this.mode;
121
+ }
122
+ }
123
+ }, this.featureName, this.ee);
124
+
125
+ // new handler for waiting for multiple flags. will be useful if/when backend designs multiple flags, or for evaluating multiple feature flags simultaneously (stn vs sr)
126
+ this.waitForFlags(['sr']).then(_ref => {
127
+ let [{
128
+ value
129
+ }] = _ref;
130
+ this.initializeRecording(value, Math.random() < (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay.errorSampleRate'), Math.random() < (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay.sampleRate'));
131
+ });
132
+ (0, _drain.drain)(this.agentIdentifier, this.featureName);
133
+ }
134
+
135
+ /**
136
+ * Evaluate entitlements and sampling before starting feature mechanics, importing and configuring recording library, and setting storage state
137
+ * @param {boolean} entitlements - the true/false state of the "sr" flag from RUM response
138
+ * @param {boolean} errorSample - the true/false state of the error sampling decision
139
+ * @param {boolean} fullSample - the true/false state of the full sampling decision
140
+ * @returns {void}
141
+ */
142
+ async initializeRecording(entitlements, errorSample, fullSample) {
143
+ this.initialized = true;
144
+ if (!entitlements) return;
145
+ const {
146
+ session
147
+ } = (0, _config.getRuntime)(this.agentIdentifier);
148
+ // if theres an existing session replay in progress, there's no need to sample, just check the entitlements response
149
+ // if not, these sample flags need to be checked
150
+ // if this isnt the FIRST load of a session AND
151
+ // we are not actively recording SR... DO NOT import or run the recording library
152
+ // session replay samples can only be decided on the first load of a session
153
+ // session replays can continue if already in progress
154
+ if (!session.isNew) {
155
+ // inherit the mode of the existing session
156
+ this.mode = session.state.sessionReplay;
157
+ } else {
158
+ // The session is new... determine the mode the new session should start in
159
+ if (fullSample) this.mode = MODE.FULL; // full mode has precedence over error mode
160
+ else if (errorSample) this.mode = MODE.ERROR;
161
+ // If neither are selected, then don't record (early return)
162
+ return;
163
+ }
164
+
165
+ // FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
166
+ // ERROR mode will do this until an error is thrown, and then switch into FULL mode.
167
+ // If an error happened in ERROR mode before we've gotten to this stage, it will have already set the mode to FULL
168
+ if (this.mode === MODE.FULL) {
169
+ // We only report (harvest) in FULL mode
170
+ this.scheduler.startTimer(this.harvestTimeSeconds);
171
+ }
172
+ // We record in FULL or ERROR mode
173
+
174
+ recorder = (await Promise.resolve().then(() => _interopRequireWildcard(require( /* webpackChunkName: "recorder" */'rrweb')))).record;
175
+ this.startRecording();
176
+ const {
177
+ gzipSync,
178
+ strToU8
179
+ } = await Promise.resolve().then(() => _interopRequireWildcard(require( /* webpackChunkName: "compressor" */'fflate')));
180
+ gzipper = gzipSync;
181
+ u8 = strToU8;
182
+ this.isFirstChunk = !!session.isNew;
183
+ session.state.sessionReplay = this.mode;
184
+ }
185
+ prepareHarvest(options) {
186
+ if (this.events.length === 0) return;
187
+ const payload = this.getHarvestContents();
188
+ try {
189
+ payload.body = gzipper(u8((0, _stringify.stringify)(payload.body)));
190
+ this.scheduler.opts.gzip = true;
191
+ } catch (err) {
192
+ // failed to gzip
193
+ this.scheduler.opts.gzip = false;
194
+ }
195
+ // TODO -- Gracefully handle the buffer for retries.
196
+ this.clearBuffer();
197
+ return [payload];
198
+ }
199
+ getHarvestContents() {
200
+ const agentRuntime = (0, _config.getRuntime)(this.agentIdentifier);
201
+ const info = (0, _config.getInfo)(this.agentIdentifier);
202
+ return {
203
+ qs: {
204
+ protocol_version: '0'
205
+ },
206
+ body: {
207
+ type: 'SessionReplay',
208
+ appId: Number(info.applicationID),
209
+ timestamp: Date.now(),
210
+ blob: JSON.stringify(this.events),
211
+ // this needs to be a stringified JSON array of rrweb nodes
212
+ attributes: {
213
+ session: agentRuntime.session.state.value,
214
+ hasSnapshot: this.hasSnapshot,
215
+ hasError: this.hasError,
216
+ agentVersion: agentRuntime.version,
217
+ isFirstChunk: this.isFirstChunk,
218
+ 'nr.rrweb.version': RRWEB_VERSION
219
+ }
220
+ }
221
+ };
222
+ }
223
+ onHarvestFinished(result) {
224
+ // The mutual decision for now is to stop recording and clear buffers if ingest is experiencing 429 rate limiting
225
+ if (result.status === 429) {
226
+ this.abort();
227
+ }
228
+ if (this.blocked) this.scheduler.stopTimer(true);
229
+ }
230
+
231
+ /** Clears the buffer (this.events), and resets all payload metadata properties */
232
+ clearBuffer() {
233
+ this.events = [];
234
+ this.isFirstChunk = false;
235
+ this.hasSnapshot = false;
236
+ this.hasError = false;
237
+ this.payloadBytesEstimation = 0;
238
+ }
239
+
240
+ /** Begin recording using configured recording lib */
241
+ startRecording() {
242
+ if (!recorder) {
243
+ warn('Recording library was never imported');
244
+ return this.abort();
245
+ }
246
+ const {
247
+ blockClass,
248
+ ignoreClass,
249
+ maskTextClass,
250
+ blockSelector,
251
+ maskInputOptions,
252
+ maskTextSelector,
253
+ maskAllInputs
254
+ } = (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay');
255
+ this.hasSnapshot = true;
256
+ // set up rrweb configurations for maximum privacy --
257
+ // https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
258
+ this.stopRecording = recorder({
259
+ emit: this.store.bind(this),
260
+ blockClass,
261
+ ignoreClass,
262
+ maskTextClass,
263
+ blockSelector,
264
+ maskInputOptions,
265
+ maskTextSelector,
266
+ maskAllInputs,
267
+ ...(this.mode === MODE.ERROR && {
268
+ checkoutEveryNms: CHECKOUT_MS
269
+ })
270
+ });
271
+ }
272
+
273
+ /** Store a payload in the buffer (this.events). This should be the callback to the recording lib noticing a mutation */
274
+ store(event, isCheckout) {
275
+ if (this.blocked) return;
276
+ const eventBytes = (0, _stringify.stringify)(event).length;
277
+ /** The estimated size of the payload after compression */
278
+ const payloadSize = this.getPayloadSize(eventBytes);
279
+ // Vortex will block payloads at a certain size, we might as well not send.
280
+ if (payloadSize > MAX_PAYLOAD_SIZE) {
281
+ return this.abort();
282
+ }
283
+ // Checkout events are flags by the recording lib that indicate a fullsnapshot was taken every n ms. These are important
284
+ // to help reconstruct the replay later and must be included. While waiting and buffering for errors to come through,
285
+ // each time we see a new checkout, we can drop the old data.
286
+ if (this.mode === MODE.ERROR && isCheckout) {
287
+ // we are still waiting for an error to throw, so keep wiping the buffer over time
288
+ this.clearBuffer();
289
+ }
290
+ this.events.push(event);
291
+ this.payloadBytesEstimation += eventBytes;
292
+
293
+ // We are making an effort to try to keep payloads manageable for unloading. If they reach the unload limit before their interval,
294
+ // it will send immediately. This often happens on the first snapshot, which can be significantly larger than the other payloads.
295
+ if (payloadSize > IDEAL_PAYLOAD_SIZE) {
296
+ // if we've made it to the ideal size of ~64kb before the interval timer, we should send early.
297
+ this.scheduler.runHarvest();
298
+ }
299
+ }
300
+
301
+ /** force the recording lib to take a full DOM snapshot. This needs to occur in certain cases, like visibility changes */
302
+ takeFullSnapshot() {
303
+ if (!recorder) return;
304
+ recorder.takeFullSnapshot();
305
+ this.hasSnapshot = true;
306
+ }
307
+
308
+ /** Estimate the payload size */
309
+ getPayloadSize() {
310
+ let newBytes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
311
+ // the 1KB gives us some padding for the other metadata
312
+ return this.estimateCompression(this.payloadBytesEstimation + newBytes) + 1000;
313
+ }
314
+
315
+ /** Abort the feature, once aborted it will not resume */
316
+ abort() {
317
+ this.blocked = true;
318
+ this.stopRecording();
319
+ const {
320
+ session
321
+ } = (0, _config.getRuntime)(this.agentIdentifier);
322
+ session.state.sessionReplay = this.mode;
323
+ }
324
+
325
+ /** Extensive research has yielded about an 88% compression factor on these payloads.
326
+ * This is an estimation using that factor as to not cause performance issues while evaluating
327
+ * https://staging.onenr.io/037jbJWxbjy
328
+ * */
329
+ estimateCompression(data) {
330
+ return data * 0.12;
331
+ }
332
+ }
333
+ exports.Aggregate = Aggregate;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.FEATURE_NAME = void 0;
7
+ var _features = require("../../loaders/features/features");
8
+ const FEATURE_NAME = _features.FEATURE_NAMES.sessionReplay;
9
+ exports.FEATURE_NAME = FEATURE_NAME;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "SessionReplay", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _index.Instrument;
10
+ }
11
+ });
12
+ var _index = require("./instrument/index");
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Instrument = void 0;
7
+ var _instrumentBase = require("../../utils/instrument-base");
8
+ var _constants = require("../constants");
9
+ /*
10
+ * Copyright 2023 New Relic Corporation. All rights reserved.
11
+ * SPDX-License-Identifier: Apache-2.0
12
+ */
13
+ /**
14
+ * @file Primes the Session Replay feature for lazy loading.
15
+ *
16
+ * NOTE: This code is under development and dormant. It will not download to instrumented pages or record any data.
17
+ * It is not production ready, and is not intended to be imported or implemented in any build of the browser agent until
18
+ * functionality is validated and a full user experience is curated.
19
+ */
20
+
21
+ class Instrument extends _instrumentBase.InstrumentBase {
22
+ static featureName = _constants.FEATURE_NAME;
23
+ constructor(agentIdentifier, aggregator) {
24
+ let auto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
25
+ super(agentIdentifier, aggregator, _constants.FEATURE_NAME, auto);
26
+ this.importAggregator();
27
+ }
28
+ }
29
+ exports.Instrument = Instrument;