@newrelic/browser-agent 1.233.1 → 1.235.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/README.md +1 -1
  2. package/dist/cjs/common/constants/env.cdn.js +1 -1
  3. package/dist/cjs/common/constants/env.npm.js +1 -1
  4. package/dist/cjs/common/constants/shared-channel.js +19 -0
  5. package/dist/cjs/common/event-emitter/contextual-ee.test.js +10 -10
  6. package/dist/cjs/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
  7. package/dist/cjs/common/harvest/harvest-scheduler.js +21 -5
  8. package/dist/cjs/common/harvest/harvest.component-test.js +224 -0
  9. package/dist/cjs/common/harvest/harvest.js +4 -11
  10. package/dist/cjs/common/session/{session-entity.test.js → session-entity.component-test.js} +79 -42
  11. package/dist/cjs/common/session/session-entity.js +19 -11
  12. package/dist/cjs/common/timer/interaction-timer.js +1 -1
  13. package/dist/cjs/common/url/canonicalize-url.test.js +26 -30
  14. package/dist/cjs/common/url/encode.js +2 -2
  15. package/dist/cjs/common/util/console.test.js +30 -0
  16. package/dist/cjs/common/util/data-size.test.js +37 -20
  17. package/dist/cjs/common/util/feature-flags.js +23 -12
  18. package/dist/cjs/common/util/feature-flags.test.js +84 -0
  19. package/dist/cjs/common/util/get-or-set.js +8 -1
  20. package/dist/cjs/common/util/get-or-set.test.js +47 -0
  21. package/dist/cjs/common/util/global-scope.js +1 -32
  22. package/dist/cjs/common/util/global-scope.test.js +72 -0
  23. package/dist/cjs/common/util/obfuscate.component-test.js +129 -0
  24. package/dist/cjs/common/util/obfuscate.js +2 -2
  25. package/dist/cjs/common/util/stringify.test.js +48 -0
  26. package/dist/cjs/common/util/submit-data.js +18 -18
  27. package/dist/cjs/common/util/submit-data.test.js +245 -0
  28. package/dist/cjs/common/util/traverse.js +19 -27
  29. package/dist/cjs/common/util/traverse.test.js +44 -0
  30. package/dist/cjs/common/wrap/wrap-raf.js +1 -1
  31. package/dist/cjs/common/wrap/wrap-timer.js +1 -1
  32. package/dist/cjs/features/jserrors/aggregate/index.js +4 -0
  33. package/dist/cjs/features/jserrors/instrument/index.js +2 -15
  34. package/dist/cjs/features/metrics/aggregate/endpoint-map.js +14 -0
  35. package/dist/cjs/features/metrics/aggregate/index.js +3 -2
  36. package/dist/cjs/features/metrics/instrument/index.js +0 -2
  37. package/dist/cjs/features/page_view_event/aggregate/index.js +58 -44
  38. package/dist/cjs/features/session_replay/aggregate/index.component-test.js +457 -0
  39. package/dist/cjs/features/session_replay/aggregate/index.js +99 -82
  40. package/dist/cjs/features/session_replay/replay-mode.js +28 -0
  41. package/dist/cjs/features/session_trace/aggregate/index.js +222 -99
  42. package/dist/cjs/features/session_trace/constants.js +1 -3
  43. package/dist/cjs/features/session_trace/instrument/index.js +0 -16
  44. package/dist/cjs/features/spa/constants.js +0 -1
  45. package/dist/cjs/features/utils/agent-session.js +20 -36
  46. package/dist/cjs/features/utils/agent-session.test.js +211 -0
  47. package/dist/cjs/features/utils/aggregate-base.js +7 -12
  48. package/dist/cjs/features/utils/aggregate-base.test.js +110 -0
  49. package/dist/cjs/features/utils/feature-base.test.js +42 -0
  50. package/dist/cjs/features/utils/handler-cache.js +28 -23
  51. package/dist/cjs/features/utils/handler-cache.test.js +53 -0
  52. package/dist/cjs/features/utils/instrument-base.js +58 -39
  53. package/dist/cjs/features/utils/instrument-base.test.js +179 -0
  54. package/dist/cjs/features/utils/lazy-feature-loader.test.js +30 -0
  55. package/dist/cjs/loaders/agent.js +0 -1
  56. package/dist/cjs/loaders/api/api.js +1 -1
  57. package/dist/cjs/loaders/configure/configure.js +0 -1
  58. package/dist/cjs/loaders/features/featureDependencies.js +2 -0
  59. package/dist/esm/common/constants/env.cdn.js +1 -1
  60. package/dist/esm/common/constants/env.npm.js +1 -1
  61. package/dist/esm/common/constants/shared-channel.js +12 -0
  62. package/dist/esm/common/event-emitter/contextual-ee.test.js +10 -10
  63. package/dist/esm/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
  64. package/dist/esm/common/harvest/harvest-scheduler.js +21 -5
  65. package/dist/esm/common/harvest/harvest.component-test.js +222 -0
  66. package/dist/esm/common/harvest/harvest.js +4 -11
  67. package/dist/esm/common/session/{session-entity.test.js → session-entity.component-test.js} +77 -40
  68. package/dist/esm/common/session/session-entity.js +17 -11
  69. package/dist/esm/common/timer/interaction-timer.js +1 -1
  70. package/dist/esm/common/url/canonicalize-url.test.js +25 -29
  71. package/dist/esm/common/url/encode.js +2 -2
  72. package/dist/esm/common/util/console.test.js +28 -0
  73. package/dist/esm/common/util/data-size.test.js +35 -20
  74. package/dist/esm/common/util/feature-flags.js +23 -12
  75. package/dist/esm/common/util/feature-flags.test.js +80 -0
  76. package/dist/esm/common/util/get-or-set.js +8 -1
  77. package/dist/esm/common/util/get-or-set.test.js +45 -0
  78. package/dist/esm/common/util/global-scope.js +1 -29
  79. package/dist/esm/common/util/global-scope.test.js +70 -0
  80. package/dist/esm/common/util/obfuscate.component-test.js +125 -0
  81. package/dist/esm/common/util/obfuscate.js +2 -2
  82. package/dist/esm/common/util/stringify.test.js +46 -0
  83. package/dist/esm/common/util/submit-data.js +18 -18
  84. package/dist/esm/common/util/submit-data.test.js +241 -0
  85. package/dist/esm/common/util/traverse.js +19 -27
  86. package/dist/esm/common/util/traverse.test.js +42 -0
  87. package/dist/esm/common/wrap/wrap-raf.js +1 -1
  88. package/dist/esm/common/wrap/wrap-timer.js +1 -1
  89. package/dist/esm/features/jserrors/aggregate/index.js +4 -0
  90. package/dist/esm/features/jserrors/instrument/index.js +2 -15
  91. package/dist/esm/features/metrics/aggregate/endpoint-map.js +7 -0
  92. package/dist/esm/features/metrics/aggregate/index.js +3 -2
  93. package/dist/esm/features/metrics/instrument/index.js +0 -2
  94. package/dist/esm/features/page_view_event/aggregate/index.js +58 -44
  95. package/dist/esm/features/session_replay/aggregate/index.component-test.js +453 -0
  96. package/dist/esm/features/session_replay/aggregate/index.js +92 -78
  97. package/dist/esm/features/session_replay/replay-mode.js +23 -0
  98. package/dist/esm/features/session_trace/aggregate/index.js +223 -100
  99. package/dist/esm/features/session_trace/constants.js +0 -1
  100. package/dist/esm/features/session_trace/instrument/index.js +1 -17
  101. package/dist/esm/features/spa/constants.js +0 -1
  102. package/dist/esm/features/utils/agent-session.js +21 -37
  103. package/dist/esm/features/utils/agent-session.test.js +207 -0
  104. package/dist/esm/features/utils/aggregate-base.js +7 -12
  105. package/dist/esm/features/utils/aggregate-base.test.js +108 -0
  106. package/dist/esm/features/utils/feature-base.test.js +40 -0
  107. package/dist/esm/features/utils/handler-cache.js +28 -23
  108. package/dist/esm/features/utils/handler-cache.test.js +51 -0
  109. package/dist/esm/features/utils/instrument-base.js +58 -39
  110. package/dist/esm/features/utils/instrument-base.test.js +175 -0
  111. package/dist/esm/features/utils/lazy-feature-loader.test.js +29 -0
  112. package/dist/esm/loaders/agent.js +0 -1
  113. package/dist/esm/loaders/api/api.js +2 -2
  114. package/dist/esm/loaders/configure/configure.js +0 -1
  115. package/dist/esm/loaders/features/featureDependencies.js +2 -0
  116. package/dist/types/common/config/state/init.d.ts.map +1 -1
  117. package/dist/types/common/constants/shared-channel.d.ts +5 -0
  118. package/dist/types/common/constants/shared-channel.d.ts.map +1 -0
  119. package/dist/types/common/context/shared-context.d.ts.map +1 -1
  120. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts +2 -0
  121. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts.map +1 -0
  122. package/dist/types/common/harvest/harvest-scheduler.d.ts +4 -0
  123. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  124. package/dist/types/common/harvest/harvest.component-test.d.ts +2 -0
  125. package/dist/types/common/harvest/harvest.component-test.d.ts.map +1 -0
  126. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  127. package/dist/types/common/session/session-entity.component-test.d.ts +2 -0
  128. package/dist/types/common/session/session-entity.component-test.d.ts.map +1 -0
  129. package/dist/types/common/session/session-entity.d.ts +9 -5
  130. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  131. package/dist/types/common/timer/interaction-timer.component-test.d.ts +2 -0
  132. package/dist/types/common/timer/interaction-timer.component-test.d.ts.map +1 -0
  133. package/dist/types/common/timer/timer.d.ts.map +1 -1
  134. package/dist/types/common/url/encode.component-test.d.ts +2 -0
  135. package/dist/types/common/url/encode.component-test.d.ts.map +1 -0
  136. package/dist/types/common/url/protocol.component-test.d.ts +2 -0
  137. package/dist/types/common/url/protocol.component-test.d.ts.map +1 -0
  138. package/dist/types/common/util/feature-flags.d.ts +1 -0
  139. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  140. package/dist/types/common/util/get-or-set.d.ts +9 -1
  141. package/dist/types/common/util/get-or-set.d.ts.map +1 -1
  142. package/dist/types/common/util/global-scope.d.ts +0 -9
  143. package/dist/types/common/util/global-scope.d.ts.map +1 -1
  144. package/dist/types/common/util/obfuscate.component-test.d.ts +2 -0
  145. package/dist/types/common/util/obfuscate.component-test.d.ts.map +1 -0
  146. package/dist/types/common/util/submit-data.d.ts +14 -10
  147. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  148. package/dist/types/common/util/traverse.d.ts +10 -1
  149. package/dist/types/common/util/traverse.d.ts.map +1 -1
  150. package/dist/types/common/window/nreum.d.ts.map +1 -1
  151. package/dist/types/features/jserrors/aggregate/index.d.ts +1 -0
  152. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  153. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts +8 -0
  154. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts.map +1 -0
  155. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  156. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -1
  157. package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
  158. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  159. package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
  160. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts +2 -0
  161. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts.map +1 -0
  162. package/dist/types/features/session_replay/aggregate/index.d.ts +14 -5
  163. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  164. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
  165. package/dist/types/features/session_replay/replay-mode.d.ts +9 -0
  166. package/dist/types/features/session_replay/replay-mode.d.ts.map +1 -0
  167. package/dist/types/features/session_trace/aggregate/index.d.ts +21 -3
  168. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  169. package/dist/types/features/session_trace/constants.d.ts +0 -1
  170. package/dist/types/features/session_trace/constants.d.ts.map +1 -1
  171. package/dist/types/features/session_trace/instrument/index.d.ts +0 -2
  172. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  173. package/dist/types/features/spa/constants.d.ts.map +1 -1
  174. package/dist/types/features/utils/agent-session.d.ts.map +1 -1
  175. package/dist/types/features/utils/aggregate-base.d.ts +6 -1
  176. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  177. package/dist/types/features/utils/handler-cache.d.ts +12 -11
  178. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  179. package/dist/types/features/utils/instrument-base.d.ts +17 -1
  180. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  181. package/dist/types/loaders/agent.d.ts.map +1 -1
  182. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  183. package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
  184. package/package.json +14 -8
  185. package/src/common/config/state/init.js +0 -1
  186. package/src/common/constants/shared-channel.js +13 -0
  187. package/src/common/context/shared-context.js +0 -1
  188. package/src/common/event-emitter/contextual-ee.test.js +10 -10
  189. package/src/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
  190. package/src/common/harvest/harvest-scheduler.js +17 -6
  191. package/src/common/harvest/harvest.component-test.js +169 -0
  192. package/src/common/harvest/harvest.js +5 -9
  193. package/src/common/session/{session-entity.test.js → session-entity.component-test.js} +70 -48
  194. package/src/common/session/session-entity.js +15 -12
  195. package/src/common/timer/interaction-timer.js +1 -1
  196. package/src/common/timer/timer.js +0 -1
  197. package/src/common/url/canonicalize-url.test.js +32 -21
  198. package/src/common/url/encode.js +2 -2
  199. package/src/common/util/console.test.js +34 -0
  200. package/src/common/util/data-size.test.js +27 -20
  201. package/src/common/util/feature-flags.js +24 -12
  202. package/src/common/util/feature-flags.test.js +98 -0
  203. package/src/common/util/get-or-set.js +8 -1
  204. package/src/common/util/get-or-set.test.js +58 -0
  205. package/src/common/util/global-scope.js +0 -26
  206. package/src/common/util/global-scope.test.js +87 -0
  207. package/src/common/util/obfuscate.component-test.js +173 -0
  208. package/src/common/util/obfuscate.js +2 -2
  209. package/src/common/util/stringify.test.js +49 -0
  210. package/src/common/util/submit-data.js +18 -19
  211. package/src/common/util/submit-data.test.js +226 -0
  212. package/src/common/util/traverse.js +18 -27
  213. package/src/common/util/traverse.test.js +50 -0
  214. package/src/common/window/nreum.js +0 -1
  215. package/src/common/wrap/wrap-raf.js +1 -1
  216. package/src/common/wrap/wrap-timer.js +1 -1
  217. package/src/features/jserrors/aggregate/index.js +5 -0
  218. package/src/features/jserrors/instrument/index.js +2 -15
  219. package/src/features/metrics/aggregate/endpoint-map.js +7 -0
  220. package/src/features/metrics/aggregate/index.js +3 -2
  221. package/src/features/metrics/aggregate/polyfill-detection.es5.js +0 -1
  222. package/src/features/metrics/instrument/index.js +0 -2
  223. package/src/features/page_view_event/aggregate/index.js +48 -51
  224. package/src/features/page_view_event/instrument/index.js +0 -1
  225. package/src/features/session_replay/aggregate/index.component-test.js +368 -0
  226. package/src/features/session_replay/aggregate/index.js +96 -71
  227. package/src/features/session_replay/instrument/index.js +0 -1
  228. package/src/features/session_replay/replay-mode.js +23 -0
  229. package/src/features/session_trace/aggregate/index.js +198 -79
  230. package/src/features/session_trace/constants.js +0 -1
  231. package/src/features/session_trace/instrument/index.js +2 -19
  232. package/src/features/spa/constants.js +0 -1
  233. package/src/features/utils/agent-session.js +22 -34
  234. package/src/features/utils/agent-session.test.js +194 -0
  235. package/src/features/utils/aggregate-base.js +12 -9
  236. package/src/features/utils/aggregate-base.test.js +122 -0
  237. package/src/features/utils/feature-base.test.js +45 -0
  238. package/src/features/utils/handler-cache.js +29 -24
  239. package/src/features/utils/handler-cache.test.js +72 -0
  240. package/src/features/utils/instrument-base.js +45 -29
  241. package/src/features/utils/instrument-base.test.js +190 -0
  242. package/src/features/utils/lazy-feature-loader.test.js +37 -0
  243. package/src/loaders/agent.js +0 -1
  244. package/src/loaders/api/api.js +2 -2
  245. package/src/loaders/configure/configure.js +0 -1
  246. package/src/loaders/features/featureDependencies.js +2 -0
  247. package/dist/cjs/common/storage/local-memory.js +0 -35
  248. package/dist/cjs/common/storage/local-memory.test.js +0 -20
  249. package/dist/cjs/common/util/s-hash.js +0 -19
  250. package/dist/cjs/features/metrics/instrument/workers-helper.js +0 -124
  251. package/dist/esm/common/storage/local-memory.js +0 -28
  252. package/dist/esm/common/storage/local-memory.test.js +0 -18
  253. package/dist/esm/common/util/s-hash.js +0 -13
  254. package/dist/esm/features/metrics/instrument/workers-helper.js +0 -119
  255. package/dist/types/common/storage/local-memory.d.ts +0 -8
  256. package/dist/types/common/storage/local-memory.d.ts.map +0 -1
  257. package/dist/types/common/util/s-hash.d.ts +0 -2
  258. package/dist/types/common/util/s-hash.d.ts.map +0 -1
  259. package/dist/types/features/metrics/instrument/workers-helper.d.ts +0 -7
  260. package/dist/types/features/metrics/instrument/workers-helper.d.ts.map +0 -1
  261. package/src/common/storage/local-memory.js +0 -30
  262. package/src/common/storage/local-memory.test.js +0 -19
  263. package/src/common/util/s-hash.js +0 -14
  264. package/src/features/metrics/instrument/workers-helper.js +0 -113
  265. /package/dist/cjs/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
  266. /package/dist/cjs/common/url/{encode.test.js → encode.component-test.js} +0 -0
  267. /package/dist/cjs/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
  268. /package/dist/esm/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
  269. /package/dist/esm/common/url/{encode.test.js → encode.component-test.js} +0 -0
  270. /package/dist/esm/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
  271. /package/src/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
  272. /package/src/common/url/{encode.test.js → encode.component-test.js} +0 -0
  273. /package/src/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
@@ -0,0 +1,169 @@
1
+ import { submitData } from '../util/submit-data'
2
+ import { Harvest } from './harvest'
3
+
4
+ jest.mock('../context/shared-context', () => ({
5
+ __esModule: true,
6
+ SharedContext: function () {
7
+ this.sharedContext = {
8
+ agentIdentifier: 'abcd'
9
+ }
10
+ }
11
+ }))
12
+ jest.mock('../config/config', () => ({
13
+ __esModule: true,
14
+ getConfigurationValue: jest.fn(),
15
+ getInfo: jest.fn().mockReturnValue({
16
+ errorBeacon: 'example.com',
17
+ licenseKey: 'abcd'
18
+ }),
19
+ getRuntime: jest.fn().mockReturnValue({
20
+ bytesSent: {},
21
+ queryBytesSent: {}
22
+ })
23
+ }))
24
+ jest.mock('../util/submit-data', () => ({
25
+ __esModule: true,
26
+ submitData: {
27
+ xhr: jest.fn(() => ({
28
+ addEventListener: jest.fn()
29
+ })),
30
+ beacon: jest.fn(),
31
+ img: jest.fn()
32
+ }
33
+ }))
34
+
35
+ describe('sendX', () => {
36
+ test.each([null, undefined, false])('should not send request when body is empty and sendEmptyBody is %s', (sendEmptyBody) => {
37
+ const sendCallback = jest.fn()
38
+ const harvester = new Harvest()
39
+ harvester.on('jserrors', () => ({
40
+ body: {},
41
+ qs: {}
42
+ }))
43
+
44
+ harvester.sendX({ endpoint: 'jserrors', cbFinished: sendCallback })
45
+
46
+ expect(sendCallback).toHaveBeenCalledWith({ sent: false })
47
+ expect(submitData.xhr).not.toHaveBeenCalled()
48
+ expect(submitData.img).not.toHaveBeenCalled()
49
+ expect(submitData.beacon).not.toHaveBeenCalled()
50
+ })
51
+
52
+ test('should send request when body is empty and sendEmptyBody is true', () => {
53
+ const harvester = new Harvest()
54
+ harvester.on('jserrors', () => ({
55
+ body: {},
56
+ qs: {}
57
+ }))
58
+
59
+ harvester.sendX({ endpoint: 'jserrors', opts: { sendEmptyBody: true }, cbFinished: jest.fn() })
60
+
61
+ expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
62
+ url: expect.stringContaining('https://example.com/jserrors/1/abcd?'),
63
+ body: undefined
64
+ }))
65
+ expect(submitData.img).not.toHaveBeenCalled()
66
+ expect(submitData.beacon).not.toHaveBeenCalled()
67
+ })
68
+
69
+ test.each([null, undefined, []])('should remove %s values from the body and query string when sending', (emptyValue) => {
70
+ const harvester = new Harvest()
71
+ harvester.on('jserrors', () => ({
72
+ body: { bar: 'foo', empty: emptyValue },
73
+ qs: { foo: 'bar', empty: emptyValue }
74
+ }))
75
+
76
+ harvester.sendX({ endpoint: 'jserrors', cbFinished: jest.fn() })
77
+
78
+ expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
79
+ url: expect.stringContaining('&foo=bar'),
80
+ body: JSON.stringify({ bar: 'foo' })
81
+ }))
82
+ expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
83
+ url: expect.not.stringContaining('&empty'),
84
+ body: expect.not.stringContaining('empty')
85
+ }))
86
+ expect(submitData.img).not.toHaveBeenCalled()
87
+ expect(submitData.beacon).not.toHaveBeenCalled()
88
+ })
89
+
90
+ test.each([1, false, true])('should not remove value %s (when it doesn\'t have a length) from the body and query string when sending', (nonStringValue) => {
91
+ const harvester = new Harvest()
92
+ harvester.on('jserrors', () => ({
93
+ body: { bar: 'foo', nonString: nonStringValue },
94
+ qs: { foo: 'bar', nonString: nonStringValue }
95
+ }))
96
+
97
+ harvester.sendX({ endpoint: 'jserrors', cbFinished: jest.fn() })
98
+
99
+ expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
100
+ url: expect.stringContaining(`&nonString=${nonStringValue}`),
101
+ body: JSON.stringify({ bar: 'foo', nonString: nonStringValue })
102
+ }))
103
+ expect(submitData.img).not.toHaveBeenCalled()
104
+ expect(submitData.beacon).not.toHaveBeenCalled()
105
+ })
106
+ })
107
+
108
+ describe('send', () => {
109
+ test.each([null, undefined, false])('should not send request when body is empty and sendEmptyBody is %s', (sendEmptyBody) => {
110
+ const sendCallback = jest.fn()
111
+ const harvester = new Harvest()
112
+
113
+ harvester.send({ endpoint: 'rum', payload: { qs: {}, body: {} }, opts: { sendEmptyBody }, cbFinished: sendCallback })
114
+
115
+ expect(sendCallback).toHaveBeenCalledWith({ sent: false })
116
+ expect(submitData.xhr).not.toHaveBeenCalled()
117
+ expect(submitData.img).not.toHaveBeenCalled()
118
+ expect(submitData.beacon).not.toHaveBeenCalled()
119
+ })
120
+
121
+ test('should send request when body is empty and sendEmptyBody is true', () => {
122
+ const harvester = new Harvest()
123
+
124
+ harvester.send({ endpoint: 'rum', payload: { qs: {}, body: {} }, opts: { sendEmptyBody: true } })
125
+
126
+ expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
127
+ url: expect.stringContaining('https://example.com/1/abcd?'),
128
+ body: undefined
129
+ }))
130
+ expect(submitData.img).not.toHaveBeenCalled()
131
+ expect(submitData.beacon).not.toHaveBeenCalled()
132
+ })
133
+
134
+ test.each([null, undefined, []])('should remove %s values from the body and query string when sending', (emptyValue) => {
135
+ const harvester = new Harvest()
136
+
137
+ harvester.send({
138
+ endpoint: 'rum',
139
+ payload: { qs: { foo: 'bar', empty: emptyValue }, body: { bar: 'foo', empty: emptyValue } }
140
+ })
141
+
142
+ expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
143
+ url: expect.stringContaining('&foo=bar'),
144
+ body: JSON.stringify({ bar: 'foo' })
145
+ }))
146
+ expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
147
+ url: expect.not.stringContaining('&empty'),
148
+ body: expect.not.stringContaining('empty')
149
+ }))
150
+ expect(submitData.img).not.toHaveBeenCalled()
151
+ expect(submitData.beacon).not.toHaveBeenCalled()
152
+ })
153
+
154
+ test.each([1, false, true])('should not remove value %s (when it doesn\'t have a length) from the body and query string when sending', (nonStringValue) => {
155
+ const harvester = new Harvest()
156
+
157
+ harvester.send({
158
+ endpoint: 'rum',
159
+ payload: { qs: { foo: 'bar', nonString: nonStringValue }, body: { bar: 'foo', nonString: nonStringValue } }
160
+ })
161
+
162
+ expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
163
+ url: expect.stringContaining(`&nonString=${nonStringValue}`),
164
+ body: JSON.stringify({ bar: 'foo', nonString: nonStringValue })
165
+ }))
166
+ expect(submitData.img).not.toHaveBeenCalled()
167
+ expect(submitData.beacon).not.toHaveBeenCalled()
168
+ })
169
+ })
@@ -98,7 +98,7 @@ export class Harvest extends SharedContext {
98
98
 
99
99
  var agentRuntime = getRuntime(this.sharedContext.agentIdentifier)
100
100
 
101
- if (!payload.body) { // no payload body? nothing to send, just run onfinish stuff and return
101
+ if (!payload.body && !opts?.sendEmptyBody) { // no payload body? nothing to send, just run onfinish stuff and return
102
102
  if (cbFinished) {
103
103
  cbFinished({ sent: false })
104
104
  }
@@ -108,7 +108,7 @@ export class Harvest extends SharedContext {
108
108
  let url = ''
109
109
  if (customUrl) url = customUrl
110
110
  else if (raw) url = `${this.getScheme()}://${info.errorBeacon}/${endpoint}`
111
- else url = `${this.getScheme()}://${info.errorBeacon}/${endpoint}/1/${info.licenseKey}`
111
+ else url = `${this.getScheme()}://${info.errorBeacon}${endpoint !== 'rum' ? `/${endpoint}` : ''}/1/${info.licenseKey}`
112
112
 
113
113
  var baseParams = !raw && includeBaseParams ? this.baseQueryString() : ''
114
114
  var payloadParams = payload.qs ? encodeObj(payload.qs, agentRuntime.maxBytes) : ''
@@ -208,6 +208,7 @@ export class Harvest extends SharedContext {
208
208
  if (singlePayload.body) mapOwn(singlePayload.body, makeBody)
209
209
  if (singlePayload.qs) mapOwn(singlePayload.qs, makeQueryString)
210
210
  }
211
+
211
212
  return { body: makeBody(), qs: makeQueryString() }
212
213
  }
213
214
 
@@ -223,17 +224,12 @@ export class Harvest extends SharedContext {
223
224
  }
224
225
  }
225
226
 
226
- function or (a, b) { return a || b }
227
-
228
227
  export function getSubmitMethod (endpoint, opts) {
229
228
  opts = opts || {}
230
229
  var method
231
230
  var useBody
232
231
 
233
- if (opts.needResponse) { // currently: only STN needs a response
234
- useBody = true
235
- method = submitData.xhr
236
- } else if (opts.unload && isBrowserScope) { // all the features' final harvest; neither methods work outside window context
232
+ if (opts.unload && isBrowserScope) { // all the features' final harvest; neither methods work outside window context
237
233
  useBody = haveSendBeacon
238
234
  method = haveSendBeacon ? submitData.beacon : submitData.img // really only IE doesn't have Beacon API for web browsers
239
235
  } else {
@@ -263,7 +259,7 @@ function createAccumulator () {
263
259
  var accumulator = {}
264
260
  var hasData = false
265
261
  return function (key, val) {
266
- if (val !== null && val !== undefined && val.length) {
262
+ if (val !== null && val !== undefined && val.toString()?.length) {
267
263
  accumulator[key] = val
268
264
  hasData = true
269
265
  }
@@ -1,13 +1,39 @@
1
-
2
- import { LocalMemory } from '../storage/local-memory'
3
- import { LocalStorage } from '../storage/local-storage'
4
-
5
1
  import { PREFIX } from './constants'
6
2
  import { SessionEntity } from './session-entity'
7
3
 
8
4
  const agentIdentifier = 'test_agent_identifier'
9
5
  const key = 'test_key'
10
6
  const value = 'test_value'
7
+ class LocalMemory {
8
+ constructor (initialState = {}) {
9
+ this.state = initialState
10
+ }
11
+
12
+ get (key) {
13
+ try {
14
+ return this.state[key]
15
+ } catch (err) {
16
+ return ''
17
+ }
18
+ }
19
+
20
+ set (key, value) {
21
+ try {
22
+ if (value === undefined || value === null) return this.remove(key)
23
+ this.state[key] = value
24
+ } catch (err) {
25
+ return
26
+ }
27
+ }
28
+
29
+ remove (key) {
30
+ try {
31
+ delete this.state[key]
32
+ } catch (err) {
33
+ return
34
+ }
35
+ }
36
+ }
11
37
 
12
38
  jest.mock('../timer/timer')
13
39
  jest.mock('../timer/interaction-timer')
@@ -24,9 +50,11 @@ jest.mock('../util/global-scope', () => ({
24
50
  }
25
51
  }))
26
52
 
53
+ let storage
27
54
  beforeEach(() => {
28
55
  jest.restoreAllMocks()
29
56
  mockBrowserScope.mockReturnValue(true)
57
+ storage = new LocalMemory()
30
58
  })
31
59
 
32
60
  describe('constructor', () => {
@@ -37,7 +65,7 @@ describe('constructor', () => {
37
65
  })
38
66
 
39
67
  test('top-level properties are set and exposed', () => {
40
- const session = new SessionEntity({ agentIdentifier, key })
68
+ const session = new SessionEntity({ agentIdentifier, key, storage })
41
69
  expect(session).toMatchObject({
42
70
  agentIdentifier: expect.any(String),
43
71
  key: expect.any(String),
@@ -52,119 +80,113 @@ describe('constructor', () => {
52
80
  expiresAt: expect.any(Number),
53
81
  inactiveAt: expect.any(Number),
54
82
  sessionReplay: expect.any(Number),
55
- sessionTraceActive: expect.any(Boolean)
83
+ sessionTraceMode: expect.any(Number)
56
84
  })
57
85
  })
58
86
  })
59
87
 
60
88
  test('can use sane defaults', () => {
61
- const session = new SessionEntity({ agentIdentifier, key })
89
+ const session = new SessionEntity({ agentIdentifier, key, storage })
62
90
  expect(session.state).toEqual(expect.objectContaining({
63
91
  value: expect.any(String),
64
92
  expiresAt: expect.any(Number),
65
93
  inactiveAt: expect.any(Number),
66
94
  updatedAt: expect.any(Number),
67
95
  sessionReplay: expect.any(Number),
68
- sessionTraceActive: expect.any(Boolean)
96
+ sessionTraceMode: expect.any(Number)
69
97
  }))
70
98
  })
71
99
 
72
- test('Workers are forced to use local memory', () => {
73
- mockBrowserScope.mockReturnValueOnce(false)
74
- const session = new SessionEntity({ agentIdentifier, key, storageAPI: new LocalStorage() })
75
- expect(session.storage instanceof LocalMemory).toEqual(true)
76
- })
77
-
78
100
  test('expiresAt is the correct future timestamp - new session', () => {
79
101
  const now = Date.now()
80
102
  jest.setSystemTime(now)
81
- const session = new SessionEntity({ agentIdentifier, key, expiresMs: 100 })
103
+ const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 100 })
82
104
  expect(session.state.expiresAt).toEqual(now + 100)
83
105
  })
84
106
 
85
107
  test('expiresAt is the correct future timestamp - existing session', () => {
86
108
  const now = Date.now()
87
109
  jest.setSystemTime(now)
88
- const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: now + 5000, inactiveAt: Infinity, updatedAt: now, sessionReplay: 0, sessionTraceActive: false, custom: {} } })
89
- const session = new SessionEntity({ agentIdentifier, key, expiresMs: 100, storageAPI: existingData })
110
+ const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: now + 5000, inactiveAt: Infinity, updatedAt: now, sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
111
+ const session = new SessionEntity({ agentIdentifier, key, expiresMs: 100, storage: existingData })
90
112
  expect(session.state.expiresAt).toEqual(now + 5000)
91
113
  })
92
114
 
93
115
  test('expiresAt never expires if 0', () => {
94
- const session = new SessionEntity({ agentIdentifier, key, expiresMs: 0 })
116
+ const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 0 })
95
117
  expect(session.state.expiresAt).toEqual(Infinity)
96
118
  })
97
119
 
98
120
  test('inactiveAt is the correct future timestamp - new session', () => {
99
121
  const now = Date.now()
100
122
  jest.setSystemTime(now)
101
- const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 100 })
123
+ const session = new SessionEntity({ agentIdentifier, key, storage, inactiveMs: 100 })
102
124
  expect(session.state.inactiveAt).toEqual(now + 100)
103
125
  })
104
126
 
105
127
  test('inactiveAt is the correct future timestamp - existing session', () => {
106
128
  const now = Date.now()
107
129
  jest.setSystemTime(now)
108
- const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, inactiveAt: now + 5000, expiresAt: Infinity, updatedAt: now, sessionReplay: 0, sessionTraceActive: false, custom: {} } })
109
- const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 100, storageAPI: existingData })
130
+ const existingData = new LocalMemory({ [`${PREFIX}_${key}`]: { value, inactiveAt: now + 5000, expiresAt: Infinity, updatedAt: now, sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
131
+ const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 100, storage: existingData })
110
132
  expect(session.state.inactiveAt).toEqual(now + 5000)
111
133
  })
112
134
 
113
135
  test('inactiveAt never expires if 0', () => {
114
- const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 0 })
136
+ const session = new SessionEntity({ agentIdentifier, key, storage, inactiveMs: 0 })
115
137
  expect(session.state.inactiveAt).toEqual(Infinity)
116
138
  })
117
139
 
118
140
  test('should handle isNew', () => {
119
- const newSession = new SessionEntity({ agentIdentifier, key, expiresMs: 10 })
141
+ const newSession = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
120
142
  expect(newSession.isNew).toBeTruthy()
121
143
 
122
- const storageAPI = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: Infinity, inactiveAt: Infinity, updatedAt: Date.now(), sessionReplay: 0, sessionTraceActive: false, custom: {} } })
123
- const existingSession = new SessionEntity({ agentIdentifier, key, expiresMs: 10, storageAPI })
144
+ const newStorage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: Infinity, inactiveAt: Infinity, updatedAt: Date.now(), sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
145
+ const existingSession = new SessionEntity({ agentIdentifier, key, expiresMs: 10, storage: newStorage })
124
146
  expect(existingSession.isNew).toBeFalsy()
125
147
  })
126
148
 
127
149
  test('invalid stored values sets new defaults', () => {
128
150
  // missing required fields
129
- const storageAPI = new LocalMemory({ [`${PREFIX}_${key}`]: { invalid_fields: true } })
130
- const session = new SessionEntity({ agentIdentifier, key, storageAPI })
151
+ const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { invalid_fields: true } })
152
+ const session = new SessionEntity({ agentIdentifier, key, storage })
131
153
  expect(session.state).toEqual(expect.objectContaining({
132
154
  value: expect.any(String),
133
155
  expiresAt: expect.any(Number),
134
156
  inactiveAt: expect.any(Number),
135
157
  updatedAt: expect.any(Number),
136
158
  sessionReplay: expect.any(Number),
137
- sessionTraceActive: expect.any(Boolean)
159
+ sessionTraceMode: expect.any(Number)
138
160
  }))
139
161
  })
140
162
 
141
163
  test('expired expiresAt value in storage sets new defaults', () => {
142
164
  const now = Date.now()
143
165
  jest.setSystemTime(now)
144
- const storageAPI = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: now - 100, inactiveAt: Infinity } })
145
- const session = new SessionEntity({ agentIdentifier, key, storageAPI })
166
+ const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: now - 100, inactiveAt: Infinity } })
167
+ const session = new SessionEntity({ agentIdentifier, key, storage })
146
168
  expect(session.state).toEqual(expect.objectContaining({
147
169
  value: expect.any(String),
148
170
  expiresAt: expect.any(Number),
149
171
  inactiveAt: expect.any(Number),
150
172
  updatedAt: expect.any(Number),
151
173
  sessionReplay: expect.any(Number),
152
- sessionTraceActive: expect.any(Boolean)
174
+ sessionTraceMode: expect.any(Number)
153
175
  }))
154
176
  })
155
177
 
156
178
  test('expired inactiveAt value in storage sets new defaults', () => {
157
179
  const now = Date.now()
158
180
  jest.setSystemTime(now)
159
- const storageAPI = new LocalMemory({ [`${PREFIX}_${key}`]: { value, inactiveAt: now - 100, expiresAt: Infinity } })
160
- const session = new SessionEntity({ agentIdentifier, key, storageAPI })
181
+ const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, inactiveAt: now - 100, expiresAt: Infinity } })
182
+ const session = new SessionEntity({ agentIdentifier, key, storage })
161
183
  expect(session.state).toEqual(expect.objectContaining({
162
184
  value: expect.any(String),
163
185
  expiresAt: expect.any(Number),
164
186
  inactiveAt: expect.any(Number),
165
187
  updatedAt: expect.any(Number),
166
188
  sessionReplay: expect.any(Number),
167
- sessionTraceActive: expect.any(Boolean)
189
+ sessionTraceMode: expect.any(Number)
168
190
  }))
169
191
  })
170
192
  })
@@ -173,7 +195,7 @@ describe('reset()', () => {
173
195
  test('should create new default values when resetting', () => {
174
196
  const now = Date.now()
175
197
  jest.setSystemTime(now)
176
- const session = new SessionEntity({ agentIdentifier, key, expiresMs: 10 })
198
+ const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
177
199
  const sessionVal = session.value
178
200
  expect(session.state.value).toBeTruthy()
179
201
  session.reset()
@@ -184,7 +206,7 @@ describe('reset()', () => {
184
206
  test('custom data should be wiped on reset', () => {
185
207
  const now = Date.now()
186
208
  jest.setSystemTime(now)
187
- const session = new SessionEntity({ agentIdentifier, key, expiresMs: 10 })
209
+ const session = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
188
210
  session.syncCustomAttribute('test', 123)
189
211
  expect(session.state.custom.test).toEqual(123)
190
212
  expect(session.read().custom.test).toEqual(123)
@@ -198,7 +220,7 @@ describe('reset()', () => {
198
220
 
199
221
  describe('read()', () => {
200
222
  test('"new" sessions get data from read()', () => {
201
- const newSession = new SessionEntity({ agentIdentifier, key, expiresMs: 10 })
223
+ const newSession = new SessionEntity({ agentIdentifier, key, storage, expiresMs: 10 })
202
224
  expect(newSession.isNew).toBeTruthy()
203
225
 
204
226
  expect(newSession.read()).toEqual(expect.objectContaining({
@@ -206,13 +228,13 @@ describe('read()', () => {
206
228
  expiresAt: expect.any(Number),
207
229
  inactiveAt: expect.any(Number),
208
230
  sessionReplay: expect.any(Number),
209
- sessionTraceActive: expect.any(Boolean)
231
+ sessionTraceMode: expect.any(Number)
210
232
  }))
211
233
  })
212
234
 
213
235
  test('"pre-existing" sessions get data from read()', () => {
214
- const storageAPI = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: Infinity, inactiveAt: Infinity, updatedAt: Date.now(), sessionReplay: 0, sessionTraceActive: false, custom: {} } })
215
- const session = new SessionEntity({ agentIdentifier, key, storageAPI })
236
+ const storage = new LocalMemory({ [`${PREFIX}_${key}`]: { value, expiresAt: Infinity, inactiveAt: Infinity, updatedAt: Date.now(), sessionReplay: 0, sessionTraceMode: 0, custom: {} } })
237
+ const session = new SessionEntity({ agentIdentifier, key, storage })
216
238
  expect(session.isNew).toBeFalsy()
217
239
  expect(session.read()).toEqual(expect.objectContaining({
218
240
  value,
@@ -224,7 +246,7 @@ describe('read()', () => {
224
246
 
225
247
  describe('write()', () => {
226
248
  test('write() sets data to top-level wrapper', () => {
227
- const session = new SessionEntity({ agentIdentifier, key })
249
+ const session = new SessionEntity({ agentIdentifier, key, storage })
228
250
  expect(session.state.value).not.toEqual(value)
229
251
  expect(session.state.expiresAt).not.toEqual(Infinity)
230
252
  expect(session.state.inactiveAt).not.toEqual(Infinity)
@@ -237,7 +259,7 @@ describe('write()', () => {
237
259
  test('write() sets data that read() can access', () => {
238
260
  const now = Date.now()
239
261
  jest.setSystemTime(now)
240
- const session = new SessionEntity({ agentIdentifier, key })
262
+ const session = new SessionEntity({ agentIdentifier, key, storage })
241
263
  session.write({ ...session.state, value, expiresAt: now + 100, inactiveAt: now + 100 })
242
264
  const read = session.read()
243
265
  expect(read.value).toEqual(value)
@@ -246,7 +268,7 @@ describe('write()', () => {
246
268
  })
247
269
 
248
270
  test('write() does not run with invalid data', () => {
249
- const session = new SessionEntity({ agentIdentifier, key })
271
+ const session = new SessionEntity({ agentIdentifier, key, storage })
250
272
  let out = session.write()
251
273
  expect(out).toEqual(undefined)
252
274
  out = session.write('string')
@@ -264,7 +286,7 @@ describe('refresh()', () => {
264
286
  test('refresh sets inactiveAt to future time', () => {
265
287
  const now = Date.now()
266
288
  jest.setSystemTime(now)
267
- const session = new SessionEntity({ agentIdentifier, key, inactiveMs: 100 })
289
+ const session = new SessionEntity({ agentIdentifier, key, storage, inactiveMs: 100 })
268
290
  expect(session.state.inactiveAt).toEqual(now + 100)
269
291
  jest.setSystemTime(now + 1000)
270
292
  session.refresh()
@@ -274,7 +296,7 @@ describe('refresh()', () => {
274
296
  test('refresh resets the entity if expiresTimer is invalid', () => {
275
297
  const now = Date.now()
276
298
  jest.setSystemTime(now)
277
- const session = new SessionEntity({ agentIdentifier, key, value })
299
+ const session = new SessionEntity({ agentIdentifier, key, storage, value })
278
300
  expect(session.state.value).toEqual(value)
279
301
  session.write({ ...session.state, expiresAt: now - 1 })
280
302
  session.refresh()
@@ -284,7 +306,7 @@ describe('refresh()', () => {
284
306
  test('refresh resets the entity if inactiveTimer is invalid', () => {
285
307
  const now = Date.now()
286
308
  jest.setSystemTime(now)
287
- const session = new SessionEntity({ agentIdentifier, key, value })
309
+ const session = new SessionEntity({ agentIdentifier, key, storage, value })
288
310
  expect(session.state.value).toEqual(value)
289
311
  session.write({ ...session.state, inactiveAt: now - 1 })
290
312
  session.refresh()
@@ -294,7 +316,7 @@ describe('refresh()', () => {
294
316
 
295
317
  describe('syncCustomAttribute()', () => {
296
318
  test('Custom data can be managed by session entity', () => {
297
- const session = new SessionEntity({ agentIdentifier, key })
319
+ const session = new SessionEntity({ agentIdentifier, key, storage })
298
320
 
299
321
  // if custom has never been set, and a "delete" action is triggered, do nothing
300
322
  session.syncCustomAttribute('test', null)
@@ -316,7 +338,7 @@ describe('syncCustomAttribute()', () => {
316
338
 
317
339
  test('Only runs in browser scope', () => {
318
340
  mockBrowserScope.mockReturnValue(false)
319
- const session = new SessionEntity({ agentIdentifier, key })
341
+ const session = new SessionEntity({ agentIdentifier, key, storage })
320
342
  session.syncCustomAttribute('test', 1)
321
343
  expect(session.read().custom?.test).toEqual(undefined)
322
344
  })
@@ -5,7 +5,6 @@ import { ee } from '../event-emitter/contextual-ee'
5
5
  import { Timer } from '../timer/timer'
6
6
  import { isBrowserScope } from '../util/global-scope'
7
7
  import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, PREFIX } from './constants'
8
- import { LocalMemory } from '../storage/local-memory'
9
8
  import { InteractionTimer } from '../timer/interaction-timer'
10
9
  import { wrapEvents } from '../wrap'
11
10
  import { getModeledObject } from '../config/state/configurable'
@@ -13,6 +12,11 @@ import { handle } from '../event-emitter/handle'
13
12
  import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants'
14
13
  import { FEATURE_NAMES } from '../../loaders/features/features'
15
14
 
15
+ export const MODE = {
16
+ OFF: 0,
17
+ FULL: 1,
18
+ ERROR: 2
19
+ }
16
20
  // this is what can be stored in local storage (not enforced but probably should be)
17
21
  // these values should sync between local storage and the parent class props
18
22
  const model = {
@@ -20,11 +24,10 @@ const model = {
20
24
  inactiveAt: 0,
21
25
  expiresAt: 0,
22
26
  updatedAt: Date.now(),
23
- sessionReplay: 0,
24
- sessionTraceActive: false,
27
+ sessionReplay: MODE.OFF,
28
+ sessionTraceMode: MODE.OFF,
25
29
  custom: {}
26
30
  }
27
-
28
31
  export const SESSION_EVENTS = {
29
32
  PAUSE: 'session-pause',
30
33
  RESET: 'session-reset',
@@ -42,16 +45,16 @@ export class SessionEntity {
42
45
  this.setup(opts)
43
46
  }
44
47
 
45
- setup ({ agentIdentifier, key, value = generateRandomHexString(16), expiresMs = DEFAULT_EXPIRES_MS, inactiveMs = DEFAULT_INACTIVE_MS, storageAPI = new LocalMemory() }) {
46
- if (!agentIdentifier || !key) throw new Error('Missing Required Fields')
47
- if (!isBrowserScope) this.storage = new LocalMemory()
48
- else this.storage = storageAPI
49
-
48
+ setup ({ agentIdentifier, key, storage, value = generateRandomHexString(16), expiresMs = DEFAULT_EXPIRES_MS, inactiveMs = DEFAULT_INACTIVE_MS }) {
49
+ if (!agentIdentifier || !key || !storage) {
50
+ throw new Error(`Missing required field(s):${!agentIdentifier ? ' agentID' : ''}${!key ? ' key' : ''}${!storage ? ' storage' : ''}`)
51
+ }
52
+ this.agentIdentifier = agentIdentifier
53
+ this.storage = storage
50
54
  this.state = {}
51
55
 
52
56
  this.sync(model)
53
57
 
54
- this.agentIdentifier = agentIdentifier
55
58
  // key is intended to act as the k=v pair
56
59
  this.key = key
57
60
  // value is intended to act as the primary value of the k=v pair
@@ -183,7 +186,7 @@ export class SessionEntity {
183
186
  this.sync(data) // update the parent class "state" properties with the local storage values
184
187
  //
185
188
  // TODO - compression would need happen here if we decide to do it
186
- this.storage.set(this.lookupKey, stringify(data))
189
+ this.storage.set(this.lookupKey, stringify(this.state))
187
190
  return data
188
191
  } catch (e) {
189
192
  // storage is inaccessible
@@ -207,7 +210,7 @@ export class SessionEntity {
207
210
  this.setup({
208
211
  agentIdentifier: this.agentIdentifier,
209
212
  key: this.key,
210
- storageAPI: this.storage,
213
+ storage: this.storage,
211
214
  expiresMs: this.expiresMs,
212
215
  inactiveMs: this.inactiveMs
213
216
  })
@@ -44,8 +44,8 @@ export class InteractionTimer extends Timer {
44
44
  if (state === 'hidden') this.pause()
45
45
  // vis change --> visible is treated like a new interaction with the page
46
46
  else {
47
- this.onResume()
48
47
  this.refresh()
48
+ this.onResume() // emit resume event after state updated
49
49
  }
50
50
  }, false, false, this.abortController?.signal)
51
51
  }
@@ -1,4 +1,3 @@
1
-
2
1
  export class Timer {
3
2
  constructor (opts, ms) {
4
3
  if (!opts.onEnd) throw new Error('onEnd handler is required')