@newrelic/browser-agent 1.234.0 → 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 (196) 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/harvest/harvest-scheduler.js +21 -5
  6. package/dist/cjs/common/session/{session-entity.test.js → session-entity.component-test.js} +79 -42
  7. package/dist/cjs/common/session/session-entity.js +19 -11
  8. package/dist/cjs/common/timer/interaction-timer.js +1 -1
  9. package/dist/cjs/common/url/canonicalize-url.test.js +26 -30
  10. package/dist/cjs/common/util/data-size.test.js +37 -20
  11. package/dist/cjs/common/util/feature-flags.js +23 -12
  12. package/dist/cjs/common/util/feature-flags.test.js +84 -0
  13. package/dist/cjs/common/util/global-scope.js +1 -32
  14. package/dist/cjs/common/util/global-scope.test.js +72 -0
  15. package/dist/cjs/common/util/obfuscate.component-test.js +129 -0
  16. package/dist/cjs/common/util/obfuscate.js +2 -2
  17. package/dist/cjs/common/util/submit-data.js +3 -3
  18. package/dist/cjs/common/util/submit-data.test.js +145 -121
  19. package/dist/cjs/common/wrap/wrap-raf.js +1 -1
  20. package/dist/cjs/common/wrap/wrap-timer.js +1 -1
  21. package/dist/cjs/features/jserrors/aggregate/index.js +4 -0
  22. package/dist/cjs/features/jserrors/instrument/index.js +2 -15
  23. package/dist/cjs/features/session_replay/aggregate/index.component-test.js +457 -0
  24. package/dist/cjs/features/session_replay/aggregate/index.js +99 -82
  25. package/dist/cjs/features/session_replay/replay-mode.js +28 -0
  26. package/dist/cjs/features/session_trace/aggregate/index.js +222 -99
  27. package/dist/cjs/features/session_trace/constants.js +1 -3
  28. package/dist/cjs/features/session_trace/instrument/index.js +0 -16
  29. package/dist/cjs/features/spa/constants.js +0 -1
  30. package/dist/cjs/features/utils/agent-session.js +20 -36
  31. package/dist/cjs/features/utils/agent-session.test.js +211 -0
  32. package/dist/cjs/features/utils/aggregate-base.js +7 -12
  33. package/dist/cjs/features/utils/aggregate-base.test.js +110 -0
  34. package/dist/cjs/features/utils/feature-base.test.js +42 -0
  35. package/dist/cjs/features/utils/handler-cache.js +28 -23
  36. package/dist/cjs/features/utils/handler-cache.test.js +53 -0
  37. package/dist/cjs/features/utils/instrument-base.js +58 -39
  38. package/dist/cjs/features/utils/instrument-base.test.js +179 -0
  39. package/dist/cjs/features/utils/lazy-feature-loader.test.js +30 -0
  40. package/dist/cjs/loaders/agent.js +0 -1
  41. package/dist/cjs/loaders/api/api.js +1 -1
  42. package/dist/cjs/loaders/features/featureDependencies.js +2 -0
  43. package/dist/esm/common/constants/env.cdn.js +1 -1
  44. package/dist/esm/common/constants/env.npm.js +1 -1
  45. package/dist/esm/common/constants/shared-channel.js +12 -0
  46. package/dist/esm/common/harvest/harvest-scheduler.js +21 -5
  47. package/dist/esm/common/session/{session-entity.test.js → session-entity.component-test.js} +77 -40
  48. package/dist/esm/common/session/session-entity.js +17 -11
  49. package/dist/esm/common/timer/interaction-timer.js +1 -1
  50. package/dist/esm/common/url/canonicalize-url.test.js +25 -29
  51. package/dist/esm/common/util/data-size.test.js +35 -20
  52. package/dist/esm/common/util/feature-flags.js +23 -12
  53. package/dist/esm/common/util/feature-flags.test.js +80 -0
  54. package/dist/esm/common/util/global-scope.js +1 -29
  55. package/dist/esm/common/util/global-scope.test.js +70 -0
  56. package/dist/esm/common/util/obfuscate.component-test.js +125 -0
  57. package/dist/esm/common/util/obfuscate.js +2 -2
  58. package/dist/esm/common/util/submit-data.js +3 -3
  59. package/dist/esm/common/util/submit-data.test.js +143 -121
  60. package/dist/esm/common/wrap/wrap-raf.js +1 -1
  61. package/dist/esm/common/wrap/wrap-timer.js +1 -1
  62. package/dist/esm/features/jserrors/aggregate/index.js +4 -0
  63. package/dist/esm/features/jserrors/instrument/index.js +2 -15
  64. package/dist/esm/features/session_replay/aggregate/index.component-test.js +453 -0
  65. package/dist/esm/features/session_replay/aggregate/index.js +92 -78
  66. package/dist/esm/features/session_replay/replay-mode.js +23 -0
  67. package/dist/esm/features/session_trace/aggregate/index.js +223 -100
  68. package/dist/esm/features/session_trace/constants.js +0 -1
  69. package/dist/esm/features/session_trace/instrument/index.js +1 -17
  70. package/dist/esm/features/spa/constants.js +0 -1
  71. package/dist/esm/features/utils/agent-session.js +21 -37
  72. package/dist/esm/features/utils/agent-session.test.js +207 -0
  73. package/dist/esm/features/utils/aggregate-base.js +7 -12
  74. package/dist/esm/features/utils/aggregate-base.test.js +108 -0
  75. package/dist/esm/features/utils/feature-base.test.js +40 -0
  76. package/dist/esm/features/utils/handler-cache.js +28 -23
  77. package/dist/esm/features/utils/handler-cache.test.js +51 -0
  78. package/dist/esm/features/utils/instrument-base.js +58 -39
  79. package/dist/esm/features/utils/instrument-base.test.js +175 -0
  80. package/dist/esm/features/utils/lazy-feature-loader.test.js +29 -0
  81. package/dist/esm/loaders/agent.js +0 -1
  82. package/dist/esm/loaders/api/api.js +2 -2
  83. package/dist/esm/loaders/features/featureDependencies.js +2 -0
  84. package/dist/types/common/constants/shared-channel.d.ts +5 -0
  85. package/dist/types/common/constants/shared-channel.d.ts.map +1 -0
  86. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts +2 -0
  87. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts.map +1 -0
  88. package/dist/types/common/harvest/harvest-scheduler.d.ts +4 -0
  89. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  90. package/dist/types/common/harvest/harvest.component-test.d.ts +2 -0
  91. package/dist/types/common/harvest/harvest.component-test.d.ts.map +1 -0
  92. package/dist/types/common/session/session-entity.component-test.d.ts +2 -0
  93. package/dist/types/common/session/session-entity.component-test.d.ts.map +1 -0
  94. package/dist/types/common/session/session-entity.d.ts +9 -5
  95. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  96. package/dist/types/common/timer/interaction-timer.component-test.d.ts +2 -0
  97. package/dist/types/common/timer/interaction-timer.component-test.d.ts.map +1 -0
  98. package/dist/types/common/url/encode.component-test.d.ts +2 -0
  99. package/dist/types/common/url/encode.component-test.d.ts.map +1 -0
  100. package/dist/types/common/url/protocol.component-test.d.ts +2 -0
  101. package/dist/types/common/url/protocol.component-test.d.ts.map +1 -0
  102. package/dist/types/common/util/feature-flags.d.ts +1 -0
  103. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  104. package/dist/types/common/util/global-scope.d.ts +0 -9
  105. package/dist/types/common/util/global-scope.d.ts.map +1 -1
  106. package/dist/types/common/util/obfuscate.component-test.d.ts +2 -0
  107. package/dist/types/common/util/obfuscate.component-test.d.ts.map +1 -0
  108. package/dist/types/features/jserrors/aggregate/index.d.ts +1 -0
  109. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  110. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts +2 -0
  111. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts.map +1 -0
  112. package/dist/types/features/session_replay/aggregate/index.d.ts +14 -5
  113. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  114. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
  115. package/dist/types/features/session_replay/replay-mode.d.ts +9 -0
  116. package/dist/types/features/session_replay/replay-mode.d.ts.map +1 -0
  117. package/dist/types/features/session_trace/aggregate/index.d.ts +21 -3
  118. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  119. package/dist/types/features/session_trace/constants.d.ts +0 -1
  120. package/dist/types/features/session_trace/constants.d.ts.map +1 -1
  121. package/dist/types/features/session_trace/instrument/index.d.ts +0 -2
  122. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  123. package/dist/types/features/spa/constants.d.ts.map +1 -1
  124. package/dist/types/features/utils/agent-session.d.ts.map +1 -1
  125. package/dist/types/features/utils/aggregate-base.d.ts +6 -1
  126. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  127. package/dist/types/features/utils/handler-cache.d.ts +12 -11
  128. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  129. package/dist/types/features/utils/instrument-base.d.ts +17 -1
  130. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  131. package/dist/types/loaders/agent.d.ts.map +1 -1
  132. package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
  133. package/package.json +9 -7
  134. package/src/common/constants/shared-channel.js +13 -0
  135. package/src/common/harvest/harvest-scheduler.js +17 -6
  136. package/src/common/session/{session-entity.test.js → session-entity.component-test.js} +70 -47
  137. package/src/common/session/session-entity.js +15 -12
  138. package/src/common/timer/interaction-timer.js +1 -1
  139. package/src/common/url/canonicalize-url.test.js +32 -21
  140. package/src/common/util/data-size.test.js +27 -20
  141. package/src/common/util/feature-flags.js +24 -12
  142. package/src/common/util/feature-flags.test.js +98 -0
  143. package/src/common/util/global-scope.js +0 -26
  144. package/src/common/util/global-scope.test.js +87 -0
  145. package/src/common/util/obfuscate.component-test.js +173 -0
  146. package/src/common/util/obfuscate.js +2 -2
  147. package/src/common/util/submit-data.js +3 -3
  148. package/src/common/util/submit-data.test.js +123 -115
  149. package/src/common/wrap/wrap-raf.js +1 -1
  150. package/src/common/wrap/wrap-timer.js +1 -1
  151. package/src/features/jserrors/aggregate/index.js +5 -0
  152. package/src/features/jserrors/instrument/index.js +2 -15
  153. package/src/features/session_replay/aggregate/index.component-test.js +368 -0
  154. package/src/features/session_replay/aggregate/index.js +96 -71
  155. package/src/features/session_replay/instrument/index.js +0 -1
  156. package/src/features/session_replay/replay-mode.js +23 -0
  157. package/src/features/session_trace/aggregate/index.js +198 -79
  158. package/src/features/session_trace/constants.js +0 -1
  159. package/src/features/session_trace/instrument/index.js +2 -19
  160. package/src/features/spa/constants.js +0 -1
  161. package/src/features/utils/agent-session.js +22 -34
  162. package/src/features/utils/agent-session.test.js +194 -0
  163. package/src/features/utils/aggregate-base.js +12 -9
  164. package/src/features/utils/aggregate-base.test.js +122 -0
  165. package/src/features/utils/feature-base.test.js +45 -0
  166. package/src/features/utils/handler-cache.js +29 -23
  167. package/src/features/utils/handler-cache.test.js +72 -0
  168. package/src/features/utils/instrument-base.js +45 -29
  169. package/src/features/utils/instrument-base.test.js +190 -0
  170. package/src/features/utils/lazy-feature-loader.test.js +37 -0
  171. package/src/loaders/agent.js +0 -1
  172. package/src/loaders/api/api.js +2 -2
  173. package/src/loaders/features/featureDependencies.js +2 -0
  174. package/dist/cjs/common/storage/local-memory.js +0 -35
  175. package/dist/cjs/common/storage/local-memory.test.js +0 -20
  176. package/dist/esm/common/storage/local-memory.js +0 -28
  177. package/dist/esm/common/storage/local-memory.test.js +0 -18
  178. package/dist/types/common/storage/local-memory.d.ts +0 -8
  179. package/dist/types/common/storage/local-memory.d.ts.map +0 -1
  180. package/src/common/storage/local-memory.js +0 -30
  181. package/src/common/storage/local-memory.test.js +0 -19
  182. /package/dist/cjs/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +0 -0
  183. /package/dist/cjs/common/harvest/{harvest.test.js → harvest.component-test.js} +0 -0
  184. /package/dist/cjs/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
  185. /package/dist/cjs/common/url/{encode.test.js → encode.component-test.js} +0 -0
  186. /package/dist/cjs/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
  187. /package/dist/esm/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +0 -0
  188. /package/dist/esm/common/harvest/{harvest.test.js → harvest.component-test.js} +0 -0
  189. /package/dist/esm/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
  190. /package/dist/esm/common/url/{encode.test.js → encode.component-test.js} +0 -0
  191. /package/dist/esm/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
  192. /package/src/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +0 -0
  193. /package/src/common/harvest/{harvest.test.js → harvest.component-test.js} +0 -0
  194. /package/src/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
  195. /package/src/common/url/{encode.test.js → encode.component-test.js} +0 -0
  196. /package/src/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
package/README.md CHANGED
@@ -6,7 +6,7 @@ The New Relic browser agent instruments your web application or site and provide
6
6
 
7
7
  - The instructions on this page pertain to installing the browser agent as an NPM package.
8
8
 
9
- - The browser agent is also generally available as a copy-paste JavaScript snippet and via auto-injection by backend apps. See *[Install the browser agent](https://docs.newrelic.com/docs/browser/browser-monitoring/installation/install-browser-monitoring-agent/)* for info on these alternatives.
9
+ - The browser agent is also generally available as a copy-paste JavaScript snippet and via auto-injection by backend apps. See *[Install the browser agent](https://docs.newrelic.com/docs/browser/browser-monitoring/installation/install-browser-monitoring-agent/)* for info on these alternatives. Releases are deployed to customers gradually, so the version available via these other methods often lags the current release of this package.
10
10
 
11
11
  - For questions and feedback on this package, please visit the [Explorer's Hub](https://forum.newrelic.com/s/), New Relic's community support forum.
12
12
 
@@ -12,7 +12,7 @@ exports.VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = "1.234.0";
15
+ const VERSION = "1.235.0";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -12,7 +12,7 @@ exports.VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = "1.234.0";
15
+ const VERSION = "1.235.0";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.sharedChannel = void 0;
7
+ /**
8
+ * @file Keeps an object alive that is passed to all feature aggregate modules.
9
+ * The purpose is to have a way for communication and signals to relay across features at runtime.
10
+ * This object can hold any arbitrary values and should be treated as on-the-fly dynamic.
11
+ */
12
+
13
+ let onReplayReady;
14
+ const sessionReplayInitialized = new Promise(resolve => onReplayReady = resolve);
15
+ const sharedChannel = Object.freeze({
16
+ onReplayReady,
17
+ sessionReplayInitialized
18
+ });
19
+ exports.sharedChannel = sharedChannel;
@@ -9,6 +9,7 @@ var _sharedContext = require("../context/shared-context");
9
9
  var _harvest = require("./harvest");
10
10
  var _eol = require("../unload/eol");
11
11
  var _config = require("../config/config");
12
+ var _sessionEntity = require("../session/session-entity");
12
13
  /*
13
14
  * Copyright 2020 New Relic Corporation. All rights reserved.
14
15
  * SPDX-License-Identifier: Apache-2.0
@@ -42,9 +43,18 @@ class HarvestScheduler extends _sharedContext.SharedContext {
42
43
  // unload if EOL mechanism fires
43
44
  (0, _eol.subscribeToEOL)(this.unload.bind(this), (0, _config.getConfigurationValue)(this.sharedContext.agentIdentifier, 'allow_bfcache')); // TO DO: remove feature flag after rls stable
44
45
 
45
- // unload if session resets
46
- this.sharedContext?.ee.on('session-reset', this.unload.bind(this));
46
+ /* Flush all buffered data if session resets and give up retries. This should be synchronous to ensure that the correct `session` value is sent.
47
+ Since session-reset generates a new session ID and the ID is grabbed at send-time, any delays or retries would cause the payload to be sent under
48
+ the wrong session ID. */
49
+ this.sharedContext?.ee.on(_sessionEntity.SESSION_EVENTS.RESET, () => this.runHarvest({
50
+ forceNoRetry: true
51
+ }));
47
52
  }
53
+
54
+ /**
55
+ * This function is only meant for the last outgoing harvest cycle of a page. It trickles down to using sendBeacon, which should not be used
56
+ * to send payloads while the page is still active, due to limitations on how much data can be buffered in the API at any one time.
57
+ */
48
58
  unload() {
49
59
  if (this.aborted) return;
50
60
  // If opts.onUnload is defined, these are special actions to execute before attempting to send the final payload.
@@ -116,7 +126,7 @@ class HarvestScheduler extends _sharedContext.SharedContext {
116
126
  payload,
117
127
  opts,
118
128
  submitMethod,
119
- cbFinished: onHarvestFinished,
129
+ cbFinished: cbRanAfterSend,
120
130
  customUrl: this.opts.customUrl,
121
131
  raw: this.opts.raw
122
132
  });
@@ -125,8 +135,14 @@ class HarvestScheduler extends _sharedContext.SharedContext {
125
135
  this.scheduleHarvest();
126
136
  }
127
137
  return;
128
- function onHarvestFinished(result) {
129
- if (result.blocked) scheduler.onHarvestBlocked(opts, result);else scheduler.onHarvestFinished(opts, result);
138
+
139
+ /**
140
+ * This is executed immediately after harvest sends the data via XHR, or if there's nothing to send. Note that this excludes on unloading / sendBeacon.
141
+ * @param {Object} result
142
+ */
143
+ function cbRanAfterSend(result) {
144
+ if (opts?.forceNoRetry) result.retry = false; // discard unsent data rather than re-queuing for next harvest attempt
145
+ scheduler.onHarvestFinished(opts, result);
130
146
  }
131
147
  }
132
148
  onHarvestFinished(opts, result) {
@@ -1,12 +1,38 @@
1
1
  "use strict";
2
2
 
3
- var _localMemory = require("../storage/local-memory");
4
- var _localStorage = require("../storage/local-storage");
5
3
  var _constants = require("./constants");
6
4
  var _sessionEntity = require("./session-entity");
7
5
  const agentIdentifier = 'test_agent_identifier';
8
6
  const key = 'test_key';
9
7
  const value = 'test_value';
8
+ class LocalMemory {
9
+ constructor() {
10
+ let initialState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
11
+ this.state = initialState;
12
+ }
13
+ get(key) {
14
+ try {
15
+ return this.state[key];
16
+ } catch (err) {
17
+ return '';
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
+ remove(key) {
29
+ try {
30
+ delete this.state[key];
31
+ } catch (err) {
32
+ return;
33
+ }
34
+ }
35
+ }
10
36
  jest.mock('../timer/timer');
11
37
  jest.mock('../timer/interaction-timer');
12
38
  jest.useFakeTimers();
@@ -20,9 +46,11 @@ jest.mock('../util/global-scope', () => ({
20
46
  return global.window;
21
47
  }
22
48
  }));
49
+ let storage;
23
50
  beforeEach(() => {
24
51
  jest.restoreAllMocks();
25
52
  mockBrowserScope.mockReturnValue(true);
53
+ storage = new LocalMemory();
26
54
  });
27
55
  describe('constructor', () => {
28
56
  test('must use required fields', () => {
@@ -33,7 +61,8 @@ describe('constructor', () => {
33
61
  test('top-level properties are set and exposed', () => {
34
62
  const session = new _sessionEntity.SessionEntity({
35
63
  agentIdentifier,
36
- key
64
+ key,
65
+ storage
37
66
  });
38
67
  expect(session).toMatchObject({
39
68
  agentIdentifier: expect.any(String),
@@ -49,14 +78,15 @@ describe('constructor', () => {
49
78
  expiresAt: expect.any(Number),
50
79
  inactiveAt: expect.any(Number),
51
80
  sessionReplay: expect.any(Number),
52
- sessionTraceActive: expect.any(Boolean)
81
+ sessionTraceMode: expect.any(Number)
53
82
  })
54
83
  });
55
84
  });
56
85
  test('can use sane defaults', () => {
57
86
  const session = new _sessionEntity.SessionEntity({
58
87
  agentIdentifier,
59
- key
88
+ key,
89
+ storage
60
90
  });
61
91
  expect(session.state).toEqual(expect.objectContaining({
62
92
  value: expect.any(String),
@@ -64,24 +94,16 @@ describe('constructor', () => {
64
94
  inactiveAt: expect.any(Number),
65
95
  updatedAt: expect.any(Number),
66
96
  sessionReplay: expect.any(Number),
67
- sessionTraceActive: expect.any(Boolean)
97
+ sessionTraceMode: expect.any(Number)
68
98
  }));
69
99
  });
70
- test('Workers are forced to use local memory', () => {
71
- mockBrowserScope.mockReturnValueOnce(false);
72
- const session = new _sessionEntity.SessionEntity({
73
- agentIdentifier,
74
- key,
75
- storageAPI: new _localStorage.LocalStorage()
76
- });
77
- expect(session.storage instanceof _localMemory.LocalMemory).toEqual(true);
78
- });
79
100
  test('expiresAt is the correct future timestamp - new session', () => {
80
101
  const now = Date.now();
81
102
  jest.setSystemTime(now);
82
103
  const session = new _sessionEntity.SessionEntity({
83
104
  agentIdentifier,
84
105
  key,
106
+ storage,
85
107
  expiresMs: 100
86
108
  });
87
109
  expect(session.state.expiresAt).toEqual(now + 100);
@@ -89,14 +111,14 @@ describe('constructor', () => {
89
111
  test('expiresAt is the correct future timestamp - existing session', () => {
90
112
  const now = Date.now();
91
113
  jest.setSystemTime(now);
92
- const existingData = new _localMemory.LocalMemory({
114
+ const existingData = new LocalMemory({
93
115
  ["".concat(_constants.PREFIX, "_").concat(key)]: {
94
116
  value,
95
117
  expiresAt: now + 5000,
96
118
  inactiveAt: Infinity,
97
119
  updatedAt: now,
98
120
  sessionReplay: 0,
99
- sessionTraceActive: false,
121
+ sessionTraceMode: 0,
100
122
  custom: {}
101
123
  }
102
124
  });
@@ -104,7 +126,7 @@ describe('constructor', () => {
104
126
  agentIdentifier,
105
127
  key,
106
128
  expiresMs: 100,
107
- storageAPI: existingData
129
+ storage: existingData
108
130
  });
109
131
  expect(session.state.expiresAt).toEqual(now + 5000);
110
132
  });
@@ -112,6 +134,7 @@ describe('constructor', () => {
112
134
  const session = new _sessionEntity.SessionEntity({
113
135
  agentIdentifier,
114
136
  key,
137
+ storage,
115
138
  expiresMs: 0
116
139
  });
117
140
  expect(session.state.expiresAt).toEqual(Infinity);
@@ -122,6 +145,7 @@ describe('constructor', () => {
122
145
  const session = new _sessionEntity.SessionEntity({
123
146
  agentIdentifier,
124
147
  key,
148
+ storage,
125
149
  inactiveMs: 100
126
150
  });
127
151
  expect(session.state.inactiveAt).toEqual(now + 100);
@@ -129,14 +153,14 @@ describe('constructor', () => {
129
153
  test('inactiveAt is the correct future timestamp - existing session', () => {
130
154
  const now = Date.now();
131
155
  jest.setSystemTime(now);
132
- const existingData = new _localMemory.LocalMemory({
156
+ const existingData = new LocalMemory({
133
157
  ["".concat(_constants.PREFIX, "_").concat(key)]: {
134
158
  value,
135
159
  inactiveAt: now + 5000,
136
160
  expiresAt: Infinity,
137
161
  updatedAt: now,
138
162
  sessionReplay: 0,
139
- sessionTraceActive: false,
163
+ sessionTraceMode: 0,
140
164
  custom: {}
141
165
  }
142
166
  });
@@ -144,7 +168,7 @@ describe('constructor', () => {
144
168
  agentIdentifier,
145
169
  key,
146
170
  inactiveMs: 100,
147
- storageAPI: existingData
171
+ storage: existingData
148
172
  });
149
173
  expect(session.state.inactiveAt).toEqual(now + 5000);
150
174
  });
@@ -152,6 +176,7 @@ describe('constructor', () => {
152
176
  const session = new _sessionEntity.SessionEntity({
153
177
  agentIdentifier,
154
178
  key,
179
+ storage,
155
180
  inactiveMs: 0
156
181
  });
157
182
  expect(session.state.inactiveAt).toEqual(Infinity);
@@ -160,17 +185,18 @@ describe('constructor', () => {
160
185
  const newSession = new _sessionEntity.SessionEntity({
161
186
  agentIdentifier,
162
187
  key,
188
+ storage,
163
189
  expiresMs: 10
164
190
  });
165
191
  expect(newSession.isNew).toBeTruthy();
166
- const storageAPI = new _localMemory.LocalMemory({
192
+ const newStorage = new LocalMemory({
167
193
  ["".concat(_constants.PREFIX, "_").concat(key)]: {
168
194
  value,
169
195
  expiresAt: Infinity,
170
196
  inactiveAt: Infinity,
171
197
  updatedAt: Date.now(),
172
198
  sessionReplay: 0,
173
- sessionTraceActive: false,
199
+ sessionTraceMode: 0,
174
200
  custom: {}
175
201
  }
176
202
  });
@@ -178,13 +204,13 @@ describe('constructor', () => {
178
204
  agentIdentifier,
179
205
  key,
180
206
  expiresMs: 10,
181
- storageAPI
207
+ storage: newStorage
182
208
  });
183
209
  expect(existingSession.isNew).toBeFalsy();
184
210
  });
185
211
  test('invalid stored values sets new defaults', () => {
186
212
  // missing required fields
187
- const storageAPI = new _localMemory.LocalMemory({
213
+ const storage = new LocalMemory({
188
214
  ["".concat(_constants.PREFIX, "_").concat(key)]: {
189
215
  invalid_fields: true
190
216
  }
@@ -192,7 +218,7 @@ describe('constructor', () => {
192
218
  const session = new _sessionEntity.SessionEntity({
193
219
  agentIdentifier,
194
220
  key,
195
- storageAPI
221
+ storage
196
222
  });
197
223
  expect(session.state).toEqual(expect.objectContaining({
198
224
  value: expect.any(String),
@@ -200,13 +226,13 @@ describe('constructor', () => {
200
226
  inactiveAt: expect.any(Number),
201
227
  updatedAt: expect.any(Number),
202
228
  sessionReplay: expect.any(Number),
203
- sessionTraceActive: expect.any(Boolean)
229
+ sessionTraceMode: expect.any(Number)
204
230
  }));
205
231
  });
206
232
  test('expired expiresAt value in storage sets new defaults', () => {
207
233
  const now = Date.now();
208
234
  jest.setSystemTime(now);
209
- const storageAPI = new _localMemory.LocalMemory({
235
+ const storage = new LocalMemory({
210
236
  ["".concat(_constants.PREFIX, "_").concat(key)]: {
211
237
  value,
212
238
  expiresAt: now - 100,
@@ -216,7 +242,7 @@ describe('constructor', () => {
216
242
  const session = new _sessionEntity.SessionEntity({
217
243
  agentIdentifier,
218
244
  key,
219
- storageAPI
245
+ storage
220
246
  });
221
247
  expect(session.state).toEqual(expect.objectContaining({
222
248
  value: expect.any(String),
@@ -224,13 +250,13 @@ describe('constructor', () => {
224
250
  inactiveAt: expect.any(Number),
225
251
  updatedAt: expect.any(Number),
226
252
  sessionReplay: expect.any(Number),
227
- sessionTraceActive: expect.any(Boolean)
253
+ sessionTraceMode: expect.any(Number)
228
254
  }));
229
255
  });
230
256
  test('expired inactiveAt value in storage sets new defaults', () => {
231
257
  const now = Date.now();
232
258
  jest.setSystemTime(now);
233
- const storageAPI = new _localMemory.LocalMemory({
259
+ const storage = new LocalMemory({
234
260
  ["".concat(_constants.PREFIX, "_").concat(key)]: {
235
261
  value,
236
262
  inactiveAt: now - 100,
@@ -240,7 +266,7 @@ describe('constructor', () => {
240
266
  const session = new _sessionEntity.SessionEntity({
241
267
  agentIdentifier,
242
268
  key,
243
- storageAPI
269
+ storage
244
270
  });
245
271
  expect(session.state).toEqual(expect.objectContaining({
246
272
  value: expect.any(String),
@@ -248,7 +274,7 @@ describe('constructor', () => {
248
274
  inactiveAt: expect.any(Number),
249
275
  updatedAt: expect.any(Number),
250
276
  sessionReplay: expect.any(Number),
251
- sessionTraceActive: expect.any(Boolean)
277
+ sessionTraceMode: expect.any(Number)
252
278
  }));
253
279
  });
254
280
  });
@@ -259,6 +285,7 @@ describe('reset()', () => {
259
285
  const session = new _sessionEntity.SessionEntity({
260
286
  agentIdentifier,
261
287
  key,
288
+ storage,
262
289
  expiresMs: 10
263
290
  });
264
291
  const sessionVal = session.value;
@@ -273,6 +300,7 @@ describe('reset()', () => {
273
300
  const session = new _sessionEntity.SessionEntity({
274
301
  agentIdentifier,
275
302
  key,
303
+ storage,
276
304
  expiresMs: 10
277
305
  });
278
306
  session.syncCustomAttribute('test', 123);
@@ -290,6 +318,7 @@ describe('read()', () => {
290
318
  const newSession = new _sessionEntity.SessionEntity({
291
319
  agentIdentifier,
292
320
  key,
321
+ storage,
293
322
  expiresMs: 10
294
323
  });
295
324
  expect(newSession.isNew).toBeTruthy();
@@ -298,25 +327,25 @@ describe('read()', () => {
298
327
  expiresAt: expect.any(Number),
299
328
  inactiveAt: expect.any(Number),
300
329
  sessionReplay: expect.any(Number),
301
- sessionTraceActive: expect.any(Boolean)
330
+ sessionTraceMode: expect.any(Number)
302
331
  }));
303
332
  });
304
333
  test('"pre-existing" sessions get data from read()', () => {
305
- const storageAPI = new _localMemory.LocalMemory({
334
+ const storage = new LocalMemory({
306
335
  ["".concat(_constants.PREFIX, "_").concat(key)]: {
307
336
  value,
308
337
  expiresAt: Infinity,
309
338
  inactiveAt: Infinity,
310
339
  updatedAt: Date.now(),
311
340
  sessionReplay: 0,
312
- sessionTraceActive: false,
341
+ sessionTraceMode: 0,
313
342
  custom: {}
314
343
  }
315
344
  });
316
345
  const session = new _sessionEntity.SessionEntity({
317
346
  agentIdentifier,
318
347
  key,
319
- storageAPI
348
+ storage
320
349
  });
321
350
  expect(session.isNew).toBeFalsy();
322
351
  expect(session.read()).toEqual(expect.objectContaining({
@@ -330,7 +359,8 @@ describe('write()', () => {
330
359
  test('write() sets data to top-level wrapper', () => {
331
360
  const session = new _sessionEntity.SessionEntity({
332
361
  agentIdentifier,
333
- key
362
+ key,
363
+ storage
334
364
  });
335
365
  expect(session.state.value).not.toEqual(value);
336
366
  expect(session.state.expiresAt).not.toEqual(Infinity);
@@ -350,7 +380,8 @@ describe('write()', () => {
350
380
  jest.setSystemTime(now);
351
381
  const session = new _sessionEntity.SessionEntity({
352
382
  agentIdentifier,
353
- key
383
+ key,
384
+ storage
354
385
  });
355
386
  session.write({
356
387
  ...session.state,
@@ -366,7 +397,8 @@ describe('write()', () => {
366
397
  test('write() does not run with invalid data', () => {
367
398
  const session = new _sessionEntity.SessionEntity({
368
399
  agentIdentifier,
369
- key
400
+ key,
401
+ storage
370
402
  });
371
403
  let out = session.write();
372
404
  expect(out).toEqual(undefined);
@@ -387,6 +419,7 @@ describe('refresh()', () => {
387
419
  const session = new _sessionEntity.SessionEntity({
388
420
  agentIdentifier,
389
421
  key,
422
+ storage,
390
423
  inactiveMs: 100
391
424
  });
392
425
  expect(session.state.inactiveAt).toEqual(now + 100);
@@ -400,6 +433,7 @@ describe('refresh()', () => {
400
433
  const session = new _sessionEntity.SessionEntity({
401
434
  agentIdentifier,
402
435
  key,
436
+ storage,
403
437
  value
404
438
  });
405
439
  expect(session.state.value).toEqual(value);
@@ -416,6 +450,7 @@ describe('refresh()', () => {
416
450
  const session = new _sessionEntity.SessionEntity({
417
451
  agentIdentifier,
418
452
  key,
453
+ storage,
419
454
  value
420
455
  });
421
456
  expect(session.state.value).toEqual(value);
@@ -431,7 +466,8 @@ describe('syncCustomAttribute()', () => {
431
466
  test('Custom data can be managed by session entity', () => {
432
467
  const session = new _sessionEntity.SessionEntity({
433
468
  agentIdentifier,
434
- key
469
+ key,
470
+ storage
435
471
  });
436
472
 
437
473
  // if custom has never been set, and a "delete" action is triggered, do nothing
@@ -452,7 +488,8 @@ describe('syncCustomAttribute()', () => {
452
488
  mockBrowserScope.mockReturnValue(false);
453
489
  const session = new _sessionEntity.SessionEntity({
454
490
  agentIdentifier,
455
- key
491
+ key,
492
+ storage
456
493
  });
457
494
  session.syncCustomAttribute('test', 1);
458
495
  expect(session.read().custom?.test).toEqual(undefined);
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.SessionEntity = exports.SESSION_EVENTS = void 0;
6
+ exports.SessionEntity = exports.SESSION_EVENTS = exports.MODE = void 0;
7
7
  var _uniqueId = require("../ids/unique-id");
8
8
  var _console = require("../util/console");
9
9
  var _stringify = require("../util/stringify");
@@ -11,22 +11,27 @@ var _contextualEe = require("../event-emitter/contextual-ee");
11
11
  var _timer = require("../timer/timer");
12
12
  var _globalScope = require("../util/global-scope");
13
13
  var _constants = require("./constants");
14
- var _localMemory = require("../storage/local-memory");
15
14
  var _interactionTimer = require("../timer/interaction-timer");
16
15
  var _wrap = require("../wrap");
17
16
  var _configurable = require("../config/state/configurable");
18
17
  var _handle = require("../event-emitter/handle");
19
18
  var _constants2 = require("../../features/metrics/constants");
20
19
  var _features = require("../../loaders/features/features");
20
+ const MODE = {
21
+ OFF: 0,
22
+ FULL: 1,
23
+ ERROR: 2
24
+ };
21
25
  // this is what can be stored in local storage (not enforced but probably should be)
22
26
  // these values should sync between local storage and the parent class props
27
+ exports.MODE = MODE;
23
28
  const model = {
24
29
  value: '',
25
30
  inactiveAt: 0,
26
31
  expiresAt: 0,
27
32
  updatedAt: Date.now(),
28
- sessionReplay: 0,
29
- sessionTraceActive: false,
33
+ sessionReplay: MODE.OFF,
34
+ sessionTraceMode: MODE.OFF,
30
35
  custom: {}
31
36
  };
32
37
  const SESSION_EVENTS = {
@@ -49,16 +54,19 @@ class SessionEntity {
49
54
  let {
50
55
  agentIdentifier,
51
56
  key,
57
+ storage,
52
58
  value = (0, _uniqueId.generateRandomHexString)(16),
53
59
  expiresMs = _constants.DEFAULT_EXPIRES_MS,
54
- inactiveMs = _constants.DEFAULT_INACTIVE_MS,
55
- storageAPI = new _localMemory.LocalMemory()
60
+ inactiveMs = _constants.DEFAULT_INACTIVE_MS
56
61
  } = _ref;
57
- if (!agentIdentifier || !key) throw new Error('Missing Required Fields');
58
- if (!_globalScope.isBrowserScope) this.storage = new _localMemory.LocalMemory();else this.storage = storageAPI;
62
+ if (!agentIdentifier || !key || !storage) {
63
+ throw new Error("Missing required field(s):".concat(!agentIdentifier ? ' agentID' : '').concat(!key ? ' key' : '').concat(!storage ? ' storage' : ''));
64
+ }
65
+ this.agentIdentifier = agentIdentifier;
66
+ this.storage = storage;
59
67
  this.state = {};
60
68
  this.sync(model);
61
- this.agentIdentifier = agentIdentifier;
69
+
62
70
  // key is intended to act as the k=v pair
63
71
  this.key = key;
64
72
  // value is intended to act as the primary value of the k=v pair
@@ -185,7 +193,7 @@ class SessionEntity {
185
193
  this.sync(data); // update the parent class "state" properties with the local storage values
186
194
  //
187
195
  // TODO - compression would need happen here if we decide to do it
188
- this.storage.set(this.lookupKey, (0, _stringify.stringify)(data));
196
+ this.storage.set(this.lookupKey, (0, _stringify.stringify)(this.state));
189
197
  return data;
190
198
  } catch (e) {
191
199
  // storage is inaccessible
@@ -207,7 +215,7 @@ class SessionEntity {
207
215
  this.setup({
208
216
  agentIdentifier: this.agentIdentifier,
209
217
  key: this.key,
210
- storageAPI: this.storage,
218
+ storage: this.storage,
211
219
  expiresMs: this.expiresMs,
212
220
  inactiveMs: this.inactiveMs
213
221
  });
@@ -49,8 +49,8 @@ class InteractionTimer extends _timer.Timer {
49
49
  if (state === 'hidden') this.pause();
50
50
  // vis change --> visible is treated like a new interaction with the page
51
51
  else {
52
- this.onResume();
53
52
  this.refresh();
53
+ this.onResume(); // emit resume event after state updated
54
54
  }
55
55
  }, false, false, this.abortController?.signal);
56
56
  }
@@ -1,42 +1,38 @@
1
1
  "use strict";
2
2
 
3
+ var _faker = require("@faker-js/faker");
4
+ var globalScopeModule = _interopRequireWildcard(require("../util/global-scope"));
5
+ var cleanUrlModule = _interopRequireWildcard(require("./clean-url"));
6
+ var _canonicalizeUrl = require("./canonicalize-url");
3
7
  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); }
4
8
  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; }
9
+ jest.mock('../util/global-scope');
10
+ jest.mock('./clean-url');
11
+ beforeEach(() => {
12
+ jest.spyOn(cleanUrlModule, 'cleanURL').mockImplementation(input => input);
13
+ jest.replaceProperty(globalScopeModule, 'initialLocation', _faker.faker.internet.url());
14
+ });
5
15
  afterEach(() => {
6
- jest.resetModules();
16
+ jest.resetAllMocks();
7
17
  });
8
18
  test.each([null, undefined, 34])('returns empty string when url argument is %s', async url => {
9
- const {
10
- canonicalizeUrl
11
- } = await Promise.resolve().then(() => _interopRequireWildcard(require('./canonicalize-url')));
12
- expect(canonicalizeUrl(url)).toEqual('');
19
+ expect((0, _canonicalizeUrl.canonicalizeUrl)(url)).toEqual('');
20
+ });
21
+ test('uses cleanURL to clean the input and initial location URLs', () => {
22
+ const url = _faker.faker.internet.url();
23
+ (0, _canonicalizeUrl.canonicalizeUrl)(url);
24
+ expect(cleanUrlModule.cleanURL).toHaveBeenCalledWith(globalScopeModule.initialLocation);
25
+ expect(cleanUrlModule.cleanURL).toHaveBeenCalledWith(url);
26
+ expect(cleanUrlModule.cleanURL).toHaveBeenCalledTimes(2);
13
27
  });
14
- test('strips URLs of query strings and fragments', async () => {
15
- jest.doMock('../util/global-scope', () => ({
16
- initialLocation: 'http://different-domain.com/'
17
- }));
18
- const {
19
- canonicalizeUrl
20
- } = await Promise.resolve().then(() => _interopRequireWildcard(require('./canonicalize-url')));
21
- expect(canonicalizeUrl('http://example.com/path?query=string#fragment')).toBe('http://example.com/path');
22
- expect(canonicalizeUrl('https://www.example.com/path/to/file.html?param=value')).toBe('https://www.example.com/path/to/file.html');
23
- expect(canonicalizeUrl('https://www.example.com/?param=value#fragment')).toBe('https://www.example.com/');
28
+ test('returns <inline> when input and initial page urls are the same', async () => {
29
+ expect((0, _canonicalizeUrl.canonicalizeUrl)(globalScopeModule.initialLocation)).toEqual('<inline>');
24
30
  });
25
- test('returns <inline> when matching the page URL of the loader', async () => {
26
- jest.doMock('../util/global-scope', () => ({
27
- initialLocation: 'http://example.com/'
28
- }));
29
- const {
30
- canonicalizeUrl
31
- } = await Promise.resolve().then(() => _interopRequireWildcard(require('./canonicalize-url')));
32
- expect(canonicalizeUrl('http://example.com/')).toEqual('<inline>');
31
+ test('returns input url when it does not match initial page url', async () => {
32
+ const url = _faker.faker.internet.url();
33
+ expect((0, _canonicalizeUrl.canonicalizeUrl)(url)).toEqual(url);
33
34
  });
34
35
  test('does not identify sub-paths of the loader origin as <inline>', async () => {
35
- jest.doMock('../util/global-scope', () => ({
36
- initialLocation: 'http://example.com/'
37
- }));
38
- const {
39
- canonicalizeUrl
40
- } = await Promise.resolve().then(() => _interopRequireWildcard(require('./canonicalize-url')));
41
- expect(canonicalizeUrl('http://example.com/path/to/script.js')).not.toEqual('<inline>');
36
+ const url = globalScopeModule.initialLocation + '/path/to/script.js';
37
+ expect((0, _canonicalizeUrl.canonicalizeUrl)(url)).not.toEqual('<inline>');
42
38
  });