@newrelic/browser-agent 1.232.1 → 1.233.1

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 (242) hide show
  1. package/dist/cjs/cdn/experimental.js +27 -0
  2. package/dist/cjs/cdn/polyfills.js +5 -2
  3. package/dist/cjs/common/config/state/configurable.js +15 -26
  4. package/dist/cjs/common/config/state/info.js +1 -1
  5. package/dist/cjs/common/config/state/init.js +101 -56
  6. package/dist/cjs/common/config/state/loader-config.js +1 -1
  7. package/dist/cjs/common/config/state/runtime.js +1 -5
  8. package/dist/cjs/common/constants/env.cdn.js +1 -1
  9. package/dist/cjs/common/constants/env.npm.js +1 -1
  10. package/dist/cjs/common/drain/drain.js +1 -1
  11. package/dist/cjs/common/harvest/harvest-scheduler.js +43 -8
  12. package/dist/cjs/common/harvest/harvest-scheduler.test.js +39 -0
  13. package/dist/cjs/common/harvest/harvest.js +106 -55
  14. package/dist/cjs/common/session/session-entity.js +35 -22
  15. package/dist/cjs/common/session/session-entity.test.js +73 -49
  16. package/dist/cjs/common/timer/interaction-timer.js +9 -12
  17. package/dist/cjs/common/url/protocol.test.js +0 -1
  18. package/dist/cjs/common/util/feature-flags.js +2 -1
  19. package/dist/cjs/common/util/submit-data.js +57 -18
  20. package/dist/cjs/common/wrap/wrap-fetch.js +1 -1
  21. package/dist/cjs/common/wrap/wrap-function.js +1 -1
  22. package/dist/cjs/common/wrap/wrap-promise.js +1 -1
  23. package/dist/cjs/features/ajax/aggregate/index.js +2 -2
  24. package/dist/cjs/features/jserrors/aggregate/index.js +7 -5
  25. package/dist/cjs/features/metrics/aggregate/framework-detection.js +67 -0
  26. package/dist/cjs/features/metrics/aggregate/framework-detection.test.js +137 -0
  27. package/dist/cjs/features/metrics/aggregate/index.js +7 -3
  28. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.js +14 -0
  29. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.test.js +17 -0
  30. package/dist/cjs/features/metrics/aggregate/polyfill-detection.js +53 -0
  31. package/dist/cjs/features/metrics/aggregate/polyfill-detection.test.js +165 -0
  32. package/dist/cjs/features/page_action/aggregate/index.js +2 -2
  33. package/dist/cjs/features/page_view_event/aggregate/index.js +6 -3
  34. package/dist/cjs/features/page_view_timing/aggregate/index.js +2 -2
  35. package/dist/cjs/features/session_replay/aggregate/index.js +336 -0
  36. package/dist/cjs/features/session_replay/constants.js +9 -0
  37. package/dist/cjs/features/session_replay/index.js +12 -0
  38. package/dist/cjs/features/session_replay/instrument/index.js +29 -0
  39. package/dist/cjs/features/session_trace/aggregate/index.js +163 -162
  40. package/dist/cjs/features/session_trace/constants.js +2 -9
  41. package/dist/cjs/features/session_trace/instrument/index.js +24 -66
  42. package/dist/cjs/features/spa/aggregate/index.js +2 -2
  43. package/dist/cjs/features/utils/agent-session.js +1 -2
  44. package/dist/cjs/features/utils/aggregate-base.js +64 -0
  45. package/dist/cjs/features/utils/feature-base.js +0 -31
  46. package/dist/cjs/features/utils/handler-cache.js +3 -4
  47. package/dist/cjs/features/utils/instrument-base.js +42 -10
  48. package/dist/cjs/features/utils/{lazy-loader.js → lazy-feature-loader.js} +4 -2
  49. package/dist/cjs/loaders/agent.js +1 -1
  50. package/dist/cjs/loaders/api/apiAsync.js +3 -1
  51. package/dist/cjs/loaders/configure/configure.js +3 -3
  52. package/dist/cjs/loaders/features/featureDependencies.js +0 -12
  53. package/dist/cjs/loaders/features/features.js +3 -1
  54. package/dist/cjs/loaders/micro-agent.js +6 -6
  55. package/dist/esm/cdn/experimental.js +24 -0
  56. package/dist/esm/cdn/polyfills.js +5 -2
  57. package/dist/esm/common/config/state/configurable.js +14 -24
  58. package/dist/esm/common/config/state/info.js +2 -2
  59. package/dist/esm/common/config/state/init.js +102 -57
  60. package/dist/esm/common/config/state/loader-config.js +2 -2
  61. package/dist/esm/common/config/state/runtime.js +2 -4
  62. package/dist/esm/common/constants/env.cdn.js +1 -1
  63. package/dist/esm/common/constants/env.npm.js +1 -1
  64. package/dist/esm/common/drain/drain.js +1 -1
  65. package/dist/esm/common/harvest/harvest-scheduler.js +43 -8
  66. package/dist/esm/common/harvest/harvest-scheduler.test.js +37 -0
  67. package/dist/esm/common/harvest/harvest.js +108 -56
  68. package/dist/esm/common/session/session-entity.js +35 -22
  69. package/dist/esm/common/session/session-entity.test.js +73 -49
  70. package/dist/esm/common/timer/interaction-timer.js +9 -12
  71. package/dist/esm/common/url/protocol.test.js +0 -1
  72. package/dist/esm/common/util/feature-flags.js +2 -1
  73. package/dist/esm/common/util/submit-data.js +57 -18
  74. package/dist/esm/common/wrap/wrap-fetch.js +1 -1
  75. package/dist/esm/common/wrap/wrap-function.js +1 -1
  76. package/dist/esm/common/wrap/wrap-promise.js +1 -1
  77. package/dist/esm/features/ajax/aggregate/index.js +2 -2
  78. package/dist/esm/features/jserrors/aggregate/index.js +7 -5
  79. package/dist/esm/features/metrics/aggregate/framework-detection.js +61 -0
  80. package/dist/esm/features/metrics/aggregate/framework-detection.test.js +133 -0
  81. package/dist/esm/features/metrics/aggregate/index.js +7 -3
  82. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.js +8 -0
  83. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.test.js +15 -0
  84. package/dist/esm/features/metrics/aggregate/polyfill-detection.js +47 -0
  85. package/dist/esm/features/metrics/aggregate/polyfill-detection.test.js +163 -0
  86. package/dist/esm/features/page_action/aggregate/index.js +2 -2
  87. package/dist/esm/features/page_view_event/aggregate/index.js +6 -3
  88. package/dist/esm/features/page_view_timing/aggregate/index.js +2 -2
  89. package/dist/esm/features/session_replay/aggregate/index.js +330 -0
  90. package/dist/esm/features/session_replay/constants.js +2 -0
  91. package/dist/esm/features/session_replay/index.js +12 -0
  92. package/dist/esm/features/session_replay/instrument/index.js +21 -0
  93. package/dist/esm/features/session_trace/aggregate/index.js +163 -162
  94. package/dist/esm/features/session_trace/constants.js +1 -5
  95. package/dist/esm/features/session_trace/instrument/index.js +24 -66
  96. package/dist/esm/features/spa/aggregate/index.js +2 -2
  97. package/dist/esm/features/utils/agent-session.js +1 -2
  98. package/dist/esm/features/utils/aggregate-base.js +57 -0
  99. package/dist/esm/features/utils/feature-base.js +1 -32
  100. package/dist/esm/features/utils/handler-cache.js +3 -4
  101. package/dist/esm/features/utils/instrument-base.js +42 -10
  102. package/dist/esm/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
  103. package/dist/esm/loaders/agent.js +1 -1
  104. package/dist/esm/loaders/api/apiAsync.js +3 -1
  105. package/dist/esm/loaders/configure/configure.js +3 -3
  106. package/dist/esm/loaders/features/featureDependencies.js +0 -11
  107. package/dist/esm/loaders/features/features.js +3 -1
  108. package/dist/esm/loaders/micro-agent.js +6 -6
  109. package/dist/types/cdn/experimental.d.ts +2 -0
  110. package/dist/types/cdn/experimental.d.ts.map +1 -0
  111. package/dist/types/common/config/state/configurable.d.ts +1 -3
  112. package/dist/types/common/config/state/configurable.d.ts.map +1 -1
  113. package/dist/types/common/config/state/init.d.ts.map +1 -1
  114. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  115. package/dist/types/common/harvest/harvest-scheduler.d.ts +26 -3
  116. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  117. package/dist/types/common/harvest/harvest.d.ts +37 -34
  118. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  119. package/dist/types/common/session/session-entity.d.ts +6 -3
  120. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  121. package/dist/types/common/timer/interaction-timer.d.ts +2 -1
  122. package/dist/types/common/timer/interaction-timer.d.ts.map +1 -1
  123. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  124. package/dist/types/common/util/submit-data.d.ts +40 -14
  125. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  126. package/dist/types/features/ajax/aggregate/index.d.ts +2 -2
  127. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  128. package/dist/types/features/jserrors/aggregate/index.d.ts +2 -2
  129. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  130. package/dist/types/features/metrics/aggregate/framework-detection.d.ts.map +1 -0
  131. package/dist/types/features/metrics/aggregate/index.d.ts +2 -2
  132. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  133. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts +6 -0
  134. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts.map +1 -0
  135. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts +7 -0
  136. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -0
  137. package/dist/types/features/page_action/aggregate/index.d.ts +2 -2
  138. package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
  139. package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -2
  140. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  141. package/dist/types/features/page_view_timing/aggregate/index.d.ts +2 -2
  142. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  143. package/dist/types/features/session_replay/aggregate/index.d.ts +100 -0
  144. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -0
  145. package/dist/types/features/session_replay/constants.d.ts +2 -0
  146. package/dist/types/features/session_replay/constants.d.ts.map +1 -0
  147. package/dist/types/features/session_replay/index.d.ts +2 -0
  148. package/dist/types/features/session_replay/index.d.ts.map +1 -0
  149. package/dist/types/features/session_replay/instrument/index.d.ts +6 -0
  150. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -0
  151. package/dist/types/features/session_trace/aggregate/index.d.ts +8 -57
  152. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  153. package/dist/types/features/session_trace/constants.d.ts +0 -3
  154. package/dist/types/features/session_trace/constants.d.ts.map +1 -1
  155. package/dist/types/features/session_trace/instrument/index.d.ts +1 -3
  156. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  157. package/dist/types/features/spa/aggregate/index.d.ts +2 -2
  158. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  159. package/dist/types/features/utils/agent-session.d.ts.map +1 -1
  160. package/dist/types/features/utils/aggregate-base.d.ts +11 -0
  161. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -0
  162. package/dist/types/features/utils/feature-base.d.ts +0 -5
  163. package/dist/types/features/utils/feature-base.d.ts.map +1 -1
  164. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  165. package/dist/types/features/utils/instrument-base.d.ts +3 -1
  166. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  167. package/dist/types/features/utils/{lazy-loader.d.ts → lazy-feature-loader.d.ts} +2 -2
  168. package/dist/types/features/utils/lazy-feature-loader.d.ts.map +1 -0
  169. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  170. package/dist/types/loaders/features/featureDependencies.d.ts +0 -1
  171. package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
  172. package/dist/types/loaders/features/features.d.ts +1 -0
  173. package/dist/types/loaders/features/features.d.ts.map +1 -1
  174. package/package.json +30 -20
  175. package/src/cdn/experimental.js +36 -0
  176. package/src/cdn/polyfills.js +4 -1
  177. package/src/common/config/state/configurable.js +18 -24
  178. package/src/common/config/state/info.js +2 -2
  179. package/src/common/config/state/init.js +62 -28
  180. package/src/common/config/state/loader-config.js +2 -2
  181. package/src/common/config/state/runtime.js +2 -4
  182. package/src/common/drain/drain.js +1 -1
  183. package/src/common/harvest/harvest-scheduler.js +48 -8
  184. package/src/common/harvest/harvest-scheduler.test.js +25 -0
  185. package/src/common/harvest/harvest.js +72 -50
  186. package/src/common/session/session-entity.js +34 -23
  187. package/src/common/session/session-entity.test.js +57 -51
  188. package/src/common/timer/interaction-timer.js +9 -12
  189. package/src/common/url/protocol.test.js +0 -1
  190. package/src/common/util/feature-flags.js +2 -2
  191. package/src/common/util/submit-data.js +28 -17
  192. package/src/common/wrap/wrap-fetch.js +1 -1
  193. package/src/common/wrap/wrap-function.js +1 -1
  194. package/src/common/wrap/wrap-promise.js +1 -1
  195. package/src/features/ajax/aggregate/index.js +2 -2
  196. package/src/features/jserrors/aggregate/index.js +7 -5
  197. package/src/features/metrics/aggregate/framework-detection.js +73 -0
  198. package/src/features/metrics/aggregate/framework-detection.test.js +201 -0
  199. package/src/features/metrics/aggregate/index.js +8 -3
  200. package/src/features/metrics/aggregate/polyfill-detection.es5.js +9 -0
  201. package/src/features/metrics/aggregate/polyfill-detection.es5.test.js +16 -0
  202. package/src/features/metrics/aggregate/polyfill-detection.js +48 -0
  203. package/src/features/metrics/aggregate/polyfill-detection.test.js +163 -0
  204. package/src/features/page_action/aggregate/index.js +2 -2
  205. package/src/features/page_view_event/aggregate/index.js +5 -5
  206. package/src/features/page_view_timing/aggregate/index.js +2 -2
  207. package/src/features/session_replay/aggregate/index.js +319 -0
  208. package/src/features/session_replay/constants.js +3 -0
  209. package/src/features/session_replay/index.js +12 -0
  210. package/src/features/session_replay/instrument/index.js +22 -0
  211. package/src/features/session_trace/aggregate/index.js +148 -187
  212. package/src/features/session_trace/constants.js +0 -4
  213. package/src/features/session_trace/instrument/index.js +17 -69
  214. package/src/features/spa/aggregate/index.js +2 -2
  215. package/src/features/utils/agent-session.js +1 -2
  216. package/src/features/utils/aggregate-base.js +51 -0
  217. package/src/features/utils/feature-base.js +1 -31
  218. package/src/features/utils/handler-cache.js +3 -4
  219. package/src/features/utils/instrument-base.js +40 -8
  220. package/src/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
  221. package/src/loaders/agent.js +1 -1
  222. package/src/loaders/api/apiAsync.js +1 -1
  223. package/src/loaders/configure/configure.js +4 -3
  224. package/src/loaders/features/featureDependencies.js +0 -12
  225. package/src/loaders/features/features.js +3 -1
  226. package/src/loaders/micro-agent.js +4 -4
  227. package/dist/cjs/common/metrics/framework-detection.js +0 -72
  228. package/dist/cjs/common/util/user-agent.js +0 -57
  229. package/dist/cjs/common/window/supports-performance-observer.js +0 -15
  230. package/dist/esm/common/metrics/framework-detection.js +0 -66
  231. package/dist/esm/common/util/user-agent.js +0 -48
  232. package/dist/esm/common/window/supports-performance-observer.js +0 -9
  233. package/dist/types/common/metrics/framework-detection.d.ts.map +0 -1
  234. package/dist/types/common/util/user-agent.d.ts +0 -5
  235. package/dist/types/common/util/user-agent.d.ts.map +0 -1
  236. package/dist/types/common/window/supports-performance-observer.d.ts +0 -2
  237. package/dist/types/common/window/supports-performance-observer.d.ts.map +0 -1
  238. package/dist/types/features/utils/lazy-loader.d.ts.map +0 -1
  239. package/src/common/metrics/framework-detection.js +0 -71
  240. package/src/common/util/user-agent.js +0 -56
  241. package/src/common/window/supports-performance-observer.js +0 -10
  242. /package/dist/types/{common/metrics → features/metrics/aggregate}/framework-detection.d.ts +0 -0
@@ -8,19 +8,27 @@ import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, PREFIX } from './constants';
8
8
  import { LocalMemory } from '../storage/local-memory';
9
9
  import { InteractionTimer } from '../timer/interaction-timer';
10
10
  import { wrapEvents } from '../wrap';
11
- import { Configurable } from '../config/state/configurable';
11
+ import { getModeledObject } from '../config/state/configurable';
12
12
  import { handle } from '../event-emitter/handle';
13
13
  import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants';
14
14
  import { FEATURE_NAMES } from '../../loaders/features/features';
15
+
16
+ // this is what can be stored in local storage (not enforced but probably should be)
17
+ // these values should sync between local storage and the parent class props
15
18
  const model = {
16
19
  value: '',
17
20
  inactiveAt: 0,
18
21
  expiresAt: 0,
19
22
  updatedAt: Date.now(),
20
- sessionReplayActive: false,
23
+ sessionReplay: 0,
21
24
  sessionTraceActive: false,
22
25
  custom: {}
23
26
  };
27
+ export const SESSION_EVENTS = {
28
+ PAUSE: 'session-pause',
29
+ RESET: 'session-reset',
30
+ RESUME: 'session-resume'
31
+ };
24
32
  export class SessionEntity {
25
33
  /**
26
34
  * Create a self-managing Session Entity. This entity is scoped to the agent identifier which triggered it, allowing for multiple simultaneous session objects to exist.
@@ -42,13 +50,13 @@ export class SessionEntity {
42
50
  } = _ref;
43
51
  if (!agentIdentifier || !key) throw new Error('Missing Required Fields');
44
52
  if (!isBrowserScope) this.storage = new LocalMemory();else this.storage = storageAPI;
53
+ this.state = {};
45
54
  this.sync(model);
46
55
  this.agentIdentifier = agentIdentifier;
47
-
48
56
  // key is intended to act as the k=v pair
49
57
  this.key = key;
50
58
  // value is intended to act as the primary value of the k=v pair
51
- this.value = value;
59
+ this.state.value = value;
52
60
  this.expiresMs = expiresMs;
53
61
  this.inactiveMs = inactiveMs;
54
62
  this.ee = ee.get(agentIdentifier);
@@ -65,7 +73,7 @@ export class SessionEntity {
65
73
  // the set-up of the timer used to expire the session "naturally" at a certain time
66
74
  // this gets ignored if the value is falsy, allowing for session entities that do not expire
67
75
  if (expiresMs) {
68
- this.expiresAt = initialRead?.expiresAt || this.getFutureTimestamp(expiresMs);
76
+ this.state.expiresAt = initialRead?.expiresAt || this.getFutureTimestamp(expiresMs);
69
77
  this.expiresTimer = new Timer({
70
78
  // When the inactive timer ends, collect a SM and reset the session
71
79
  onEnd: () => {
@@ -73,16 +81,16 @@ export class SessionEntity {
73
81
  this.collectSM('duration', this);
74
82
  this.reset();
75
83
  }
76
- }, this.expiresAt - Date.now());
84
+ }, this.state.expiresAt - Date.now());
77
85
  } else {
78
- this.expiresAt = Infinity;
86
+ this.state.expiresAt = Infinity;
79
87
  }
80
88
 
81
89
  // the set-up of the timer used to expire the session due to "inactivity" at a certain time
82
90
  // this gets ignored if the value is falsy, allowing for session entities that do not expire
83
91
  // this gets "refreshed" when "activity" is observed
84
92
  if (inactiveMs) {
85
- this.inactiveAt = initialRead?.inactiveAt || this.getFutureTimestamp(inactiveMs);
93
+ this.state.inactiveAt = initialRead?.inactiveAt || this.getFutureTimestamp(inactiveMs);
86
94
  this.inactiveTimer = new InteractionTimer({
87
95
  // When the inactive timer ends, collect a SM and reset the session
88
96
  onEnd: () => {
@@ -92,21 +100,27 @@ export class SessionEntity {
92
100
  },
93
101
  // When the inactive timer refreshes, it will update the storage values with an update timestamp
94
102
  onRefresh: this.refresh.bind(this),
103
+ onResume: () => {
104
+ this.ee.emit(SESSION_EVENTS.RESUME);
105
+ },
95
106
  // When the inactive timer pauses, update the storage values with an update timestamp
96
- onPause: () => this.write(new Configurable(this.read(), model)),
107
+ onPause: () => {
108
+ if (this.initialized) this.ee.emit(SESSION_EVENTS.PAUSE);
109
+ this.write(getModeledObject(this.state, model));
110
+ },
97
111
  ee: this.ee,
98
112
  refreshEvents: ['click', 'keydown', 'scroll']
99
- }, this.inactiveAt - Date.now());
113
+ }, this.state.inactiveAt - Date.now());
100
114
  } else {
101
- this.inactiveAt = Infinity;
115
+ this.state.inactiveAt = Infinity;
102
116
  }
103
117
 
104
118
  // The fact that the session is "new" or pre-existing is used in some places in the agent. Session Replay and Trace
105
119
  // can use this info to inform whether to trust a new sampling decision vs continue a previous tracking effort.
106
- this.isNew = !Object.keys(initialRead).length;
120
+ if (this.isNew === undefined) this.isNew = !Object.keys(initialRead).length;
107
121
  // if its a "new" session, we write to storage API with the default values. These values may change over the lifespan of the agent run.
108
- // we can use configurable here to help us know and manage what values are being used. -- see "model" above
109
- if (this.isNew) this.write(new Configurable(this, model), true);else this.sync(initialRead);
122
+ // we can use a modeled object here to help us know and manage what values are being used. -- see "model" above
123
+ if (this.isNew) this.write(getModeledObject(this.state, model), true);else this.sync(initialRead);
110
124
  this.initialized = true;
111
125
  }
112
126
 
@@ -115,7 +129,7 @@ export class SessionEntity {
115
129
  return "".concat(PREFIX, "_").concat(this.key);
116
130
  }
117
131
  sync(data) {
118
- Object.assign(this, data);
132
+ Object.assign(this.state, data);
119
133
  }
120
134
 
121
135
  /**
@@ -162,7 +176,8 @@ export class SessionEntity {
162
176
  if (!data || typeof data !== 'object') return;
163
177
  // everytime we update, we can update a timestamp for sanity
164
178
  data.updatedAt = Date.now();
165
- this.sync(data);
179
+ this.sync(data); // update the parent class "state" properties with the local storage values
180
+ //
166
181
  // TODO - compression would need happen here if we decide to do it
167
182
  this.storage.set(this.lookupKey, stringify(data));
168
183
  return data;
@@ -178,12 +193,11 @@ export class SessionEntity {
178
193
  // * stop recording (stn and sr)...
179
194
  // * delete the session and start over
180
195
  try {
181
- if (this.initialized) this.ee.emit('session-reset');
196
+ if (this.initialized) this.ee.emit(SESSION_EVENTS.RESET);
182
197
  this.storage.remove(this.lookupKey);
183
198
  this.inactiveTimer?.abort?.();
184
199
  this.expiresTimer?.clear?.();
185
- delete this.custom;
186
- delete this.value;
200
+ delete this.isNew;
187
201
  this.setup({
188
202
  agentIdentifier: this.agentIdentifier,
189
203
  key: this.key,
@@ -203,10 +217,9 @@ export class SessionEntity {
203
217
  refresh() {
204
218
  // read here & invalidate
205
219
  const existingData = this.read();
206
- this.inactiveAt = this.getFutureTimestamp(this.inactiveMs);
207
220
  this.write({
208
221
  ...existingData,
209
- inactiveAt: this.inactiveAt
222
+ inactiveAt: this.getFutureTimestamp(this.inactiveMs)
210
223
  });
211
224
  }
212
225
 
@@ -223,7 +236,7 @@ export class SessionEntity {
223
236
  * @returns {boolean}
224
237
  */
225
238
  isInvalid(data) {
226
- const requiredKeys = ['value', 'expiresAt', 'inactiveAt'];
239
+ const requiredKeys = Object.keys(model);
227
240
  return !requiredKeys.every(x => Object.keys(data).includes(x));
228
241
  }
229
242
  collectSM(type, data, useUpdatedAt) {
@@ -36,17 +36,19 @@ describe('constructor', () => {
36
36
  expect(session).toMatchObject({
37
37
  agentIdentifier: expect.any(String),
38
38
  key: expect.any(String),
39
- value: expect.any(String),
40
39
  expiresMs: expect.any(Number),
41
- expiresAt: expect.any(Number),
42
40
  expiresTimer: expect.any(Object),
43
41
  inactiveMs: expect.any(Number),
44
- inactiveAt: expect.any(Number),
45
42
  inactiveTimer: expect.any(Object),
46
43
  isNew: expect.any(Boolean),
47
- sessionReplayActive: expect.any(Boolean),
48
- sessionTraceActive: expect.any(Boolean),
49
- storage: expect.any(Object)
44
+ storage: expect.any(Object),
45
+ state: expect.objectContaining({
46
+ value: expect.any(String),
47
+ expiresAt: expect.any(Number),
48
+ inactiveAt: expect.any(Number),
49
+ sessionReplay: expect.any(Number),
50
+ sessionTraceActive: expect.any(Boolean)
51
+ })
50
52
  });
51
53
  });
52
54
  test('can use sane defaults', () => {
@@ -54,11 +56,12 @@ describe('constructor', () => {
54
56
  agentIdentifier,
55
57
  key
56
58
  });
57
- expect(session).toEqual(expect.objectContaining({
59
+ expect(session.state).toEqual(expect.objectContaining({
58
60
  value: expect.any(String),
59
61
  expiresAt: expect.any(Number),
60
62
  inactiveAt: expect.any(Number),
61
- sessionReplayActive: expect.any(Boolean),
63
+ updatedAt: expect.any(Number),
64
+ sessionReplay: expect.any(Number),
62
65
  sessionTraceActive: expect.any(Boolean)
63
66
  }));
64
67
  });
@@ -79,7 +82,7 @@ describe('constructor', () => {
79
82
  key,
80
83
  expiresMs: 100
81
84
  });
82
- expect(session.expiresAt).toEqual(now + 100);
85
+ expect(session.state.expiresAt).toEqual(now + 100);
83
86
  });
84
87
  test('expiresAt is the correct future timestamp - existing session', () => {
85
88
  const now = Date.now();
@@ -88,7 +91,11 @@ describe('constructor', () => {
88
91
  ["".concat(PREFIX, "_").concat(key)]: {
89
92
  value,
90
93
  expiresAt: now + 5000,
91
- inactiveAt: Infinity
94
+ inactiveAt: Infinity,
95
+ updatedAt: now,
96
+ sessionReplay: 0,
97
+ sessionTraceActive: false,
98
+ custom: {}
92
99
  }
93
100
  });
94
101
  const session = new SessionEntity({
@@ -97,7 +104,7 @@ describe('constructor', () => {
97
104
  expiresMs: 100,
98
105
  storageAPI: existingData
99
106
  });
100
- expect(session.expiresAt).toEqual(now + 5000);
107
+ expect(session.state.expiresAt).toEqual(now + 5000);
101
108
  });
102
109
  test('expiresAt never expires if 0', () => {
103
110
  const session = new SessionEntity({
@@ -105,7 +112,7 @@ describe('constructor', () => {
105
112
  key,
106
113
  expiresMs: 0
107
114
  });
108
- expect(session.expiresAt).toEqual(Infinity);
115
+ expect(session.state.expiresAt).toEqual(Infinity);
109
116
  });
110
117
  test('inactiveAt is the correct future timestamp - new session', () => {
111
118
  const now = Date.now();
@@ -115,7 +122,7 @@ describe('constructor', () => {
115
122
  key,
116
123
  inactiveMs: 100
117
124
  });
118
- expect(session.inactiveAt).toEqual(now + 100);
125
+ expect(session.state.inactiveAt).toEqual(now + 100);
119
126
  });
120
127
  test('inactiveAt is the correct future timestamp - existing session', () => {
121
128
  const now = Date.now();
@@ -124,7 +131,11 @@ describe('constructor', () => {
124
131
  ["".concat(PREFIX, "_").concat(key)]: {
125
132
  value,
126
133
  inactiveAt: now + 5000,
127
- expiresAt: Infinity
134
+ expiresAt: Infinity,
135
+ updatedAt: now,
136
+ sessionReplay: 0,
137
+ sessionTraceActive: false,
138
+ custom: {}
128
139
  }
129
140
  });
130
141
  const session = new SessionEntity({
@@ -133,7 +144,7 @@ describe('constructor', () => {
133
144
  inactiveMs: 100,
134
145
  storageAPI: existingData
135
146
  });
136
- expect(session.inactiveAt).toEqual(now + 5000);
147
+ expect(session.state.inactiveAt).toEqual(now + 5000);
137
148
  });
138
149
  test('inactiveAt never expires if 0', () => {
139
150
  const session = new SessionEntity({
@@ -141,7 +152,7 @@ describe('constructor', () => {
141
152
  key,
142
153
  inactiveMs: 0
143
154
  });
144
- expect(session.inactiveAt).toEqual(Infinity);
155
+ expect(session.state.inactiveAt).toEqual(Infinity);
145
156
  });
146
157
  test('should handle isNew', () => {
147
158
  const newSession = new SessionEntity({
@@ -154,7 +165,11 @@ describe('constructor', () => {
154
165
  ["".concat(PREFIX, "_").concat(key)]: {
155
166
  value,
156
167
  expiresAt: Infinity,
157
- inactiveAt: Infinity
168
+ inactiveAt: Infinity,
169
+ updatedAt: Date.now(),
170
+ sessionReplay: 0,
171
+ sessionTraceActive: false,
172
+ custom: {}
158
173
  }
159
174
  });
160
175
  const existingSession = new SessionEntity({
@@ -177,11 +192,12 @@ describe('constructor', () => {
177
192
  key,
178
193
  storageAPI
179
194
  });
180
- expect(session).toEqual(expect.objectContaining({
195
+ expect(session.state).toEqual(expect.objectContaining({
181
196
  value: expect.any(String),
182
197
  expiresAt: expect.any(Number),
183
198
  inactiveAt: expect.any(Number),
184
- sessionReplayActive: expect.any(Boolean),
199
+ updatedAt: expect.any(Number),
200
+ sessionReplay: expect.any(Number),
185
201
  sessionTraceActive: expect.any(Boolean)
186
202
  }));
187
203
  });
@@ -200,11 +216,12 @@ describe('constructor', () => {
200
216
  key,
201
217
  storageAPI
202
218
  });
203
- expect(session).toEqual(expect.objectContaining({
219
+ expect(session.state).toEqual(expect.objectContaining({
204
220
  value: expect.any(String),
205
221
  expiresAt: expect.any(Number),
206
222
  inactiveAt: expect.any(Number),
207
- sessionReplayActive: expect.any(Boolean),
223
+ updatedAt: expect.any(Number),
224
+ sessionReplay: expect.any(Number),
208
225
  sessionTraceActive: expect.any(Boolean)
209
226
  }));
210
227
  });
@@ -223,11 +240,12 @@ describe('constructor', () => {
223
240
  key,
224
241
  storageAPI
225
242
  });
226
- expect(session).toEqual(expect.objectContaining({
243
+ expect(session.state).toEqual(expect.objectContaining({
227
244
  value: expect.any(String),
228
245
  expiresAt: expect.any(Number),
229
246
  inactiveAt: expect.any(Number),
230
- sessionReplayActive: expect.any(Boolean),
247
+ updatedAt: expect.any(Number),
248
+ sessionReplay: expect.any(Number),
231
249
  sessionTraceActive: expect.any(Boolean)
232
250
  }));
233
251
  });
@@ -242,10 +260,10 @@ describe('reset()', () => {
242
260
  expiresMs: 10
243
261
  });
244
262
  const sessionVal = session.value;
245
- expect(session.value).toBeTruthy();
263
+ expect(session.state.value).toBeTruthy();
246
264
  session.reset();
247
- expect(session.value).toBeTruthy();
248
- expect(session.value).not.toEqual(sessionVal);
265
+ expect(session.state.value).toBeTruthy();
266
+ expect(session.state.value).not.toEqual(sessionVal);
249
267
  });
250
268
  test('custom data should be wiped on reset', () => {
251
269
  const now = Date.now();
@@ -256,12 +274,12 @@ describe('reset()', () => {
256
274
  expiresMs: 10
257
275
  });
258
276
  session.syncCustomAttribute('test', 123);
259
- expect(session.custom.test).toEqual(123);
277
+ expect(session.state.custom.test).toEqual(123);
260
278
  expect(session.read().custom.test).toEqual(123);
261
279
 
262
280
  // simulate a timer expiring
263
281
  session.reset();
264
- expect(session.custom?.test).toEqual(undefined);
282
+ expect(session.state.custom?.test).toEqual(undefined);
265
283
  expect(session.read()?.custom?.test).toEqual(undefined);
266
284
  });
267
285
  });
@@ -277,7 +295,7 @@ describe('read()', () => {
277
295
  value: expect.any(String),
278
296
  expiresAt: expect.any(Number),
279
297
  inactiveAt: expect.any(Number),
280
- sessionReplayActive: expect.any(Boolean),
298
+ sessionReplay: expect.any(Number),
281
299
  sessionTraceActive: expect.any(Boolean)
282
300
  }));
283
301
  });
@@ -286,7 +304,11 @@ describe('read()', () => {
286
304
  ["".concat(PREFIX, "_").concat(key)]: {
287
305
  value,
288
306
  expiresAt: Infinity,
289
- inactiveAt: Infinity
307
+ inactiveAt: Infinity,
308
+ updatedAt: Date.now(),
309
+ sessionReplay: 0,
310
+ sessionTraceActive: false,
311
+ custom: {}
290
312
  }
291
313
  });
292
314
  const session = new SessionEntity({
@@ -308,17 +330,18 @@ describe('write()', () => {
308
330
  agentIdentifier,
309
331
  key
310
332
  });
311
- expect(session.value).not.toEqual(value);
312
- expect(session.expiresAt).not.toEqual(Infinity);
313
- expect(session.inactiveAt).not.toEqual(Infinity);
333
+ expect(session.state.value).not.toEqual(value);
334
+ expect(session.state.expiresAt).not.toEqual(Infinity);
335
+ expect(session.state.inactiveAt).not.toEqual(Infinity);
314
336
  session.write({
337
+ ...session.state,
315
338
  value,
316
339
  expiresAt: Infinity,
317
340
  inactiveAt: Infinity
318
341
  });
319
- expect(session.value).toEqual(value);
320
- expect(session.expiresAt).toEqual(Infinity);
321
- expect(session.inactiveAt).toEqual(Infinity);
342
+ expect(session.state.value).toEqual(value);
343
+ expect(session.state.expiresAt).toEqual(Infinity);
344
+ expect(session.state.inactiveAt).toEqual(Infinity);
322
345
  });
323
346
  test('write() sets data that read() can access', () => {
324
347
  const now = Date.now();
@@ -328,6 +351,7 @@ describe('write()', () => {
328
351
  key
329
352
  });
330
353
  session.write({
354
+ ...session.state,
331
355
  value,
332
356
  expiresAt: now + 100,
333
357
  inactiveAt: now + 100
@@ -363,10 +387,10 @@ describe('refresh()', () => {
363
387
  key,
364
388
  inactiveMs: 100
365
389
  });
366
- expect(session.inactiveAt).toEqual(now + 100);
390
+ expect(session.state.inactiveAt).toEqual(now + 100);
367
391
  jest.setSystemTime(now + 1000);
368
392
  session.refresh();
369
- expect(session.inactiveAt).toEqual(now + 100 + 1000);
393
+ expect(session.state.inactiveAt).toEqual(now + 100 + 1000);
370
394
  });
371
395
  test('refresh resets the entity if expiresTimer is invalid', () => {
372
396
  const now = Date.now();
@@ -376,13 +400,13 @@ describe('refresh()', () => {
376
400
  key,
377
401
  value
378
402
  });
379
- expect(session.value).toEqual(value);
403
+ expect(session.state.value).toEqual(value);
380
404
  session.write({
381
- ...session.read(),
405
+ ...session.state,
382
406
  expiresAt: now - 1
383
407
  });
384
408
  session.refresh();
385
- expect(session.value).not.toEqual(value);
409
+ expect(session.state.value).not.toEqual(value);
386
410
  });
387
411
  test('refresh resets the entity if inactiveTimer is invalid', () => {
388
412
  const now = Date.now();
@@ -392,13 +416,13 @@ describe('refresh()', () => {
392
416
  key,
393
417
  value
394
418
  });
395
- expect(session.value).toEqual(value);
419
+ expect(session.state.value).toEqual(value);
396
420
  session.write({
397
- ...session.read(),
421
+ ...session.state,
398
422
  inactiveAt: now - 1
399
423
  });
400
424
  session.refresh();
401
- expect(session.value).not.toEqual(value);
425
+ expect(session.state.value).not.toEqual(value);
402
426
  });
403
427
  });
404
428
  describe('syncCustomAttribute()', () => {
@@ -410,17 +434,17 @@ describe('syncCustomAttribute()', () => {
410
434
 
411
435
  // if custom has never been set, and a "delete" action is triggered, do nothing
412
436
  session.syncCustomAttribute('test', null);
413
- expect(session?.custom?.test).toEqual(undefined);
437
+ expect(session?.state?.custom?.test).toEqual(undefined);
414
438
  session.syncCustomAttribute('test', 1);
415
- expect(session?.custom?.test).toEqual(1);
439
+ expect(session?.state?.custom?.test).toEqual(1);
416
440
  session.syncCustomAttribute('test', 'string');
417
- expect(session?.custom?.test).toEqual('string');
441
+ expect(session?.state?.custom?.test).toEqual('string');
418
442
  session.syncCustomAttribute('test', false);
419
- expect(session?.custom?.test).toEqual(false);
443
+ expect(session?.state?.custom?.test).toEqual(false);
420
444
 
421
445
  // null specifically deletes the object completely
422
446
  session.syncCustomAttribute('test', null);
423
- expect(session?.custom?.test).toEqual(undefined);
447
+ expect(session?.state?.custom?.test).toEqual(undefined);
424
448
  });
425
449
  test('Only runs in browser scope', () => {
426
450
  mockBrowserScope.mockReturnValue(false);
@@ -5,8 +5,9 @@ import { isBrowserScope } from '../util/global-scope';
5
5
  export class InteractionTimer extends Timer {
6
6
  constructor(opts, ms) {
7
7
  super(opts, ms);
8
- this.onRefresh = opts.onRefresh;
9
- this.onPause = opts.onPause;
8
+ this.onPause = typeof opts.onPause === 'function' ? opts.onPause : () => {/* noop */};
9
+ this.onRefresh = typeof opts.onRefresh === 'function' ? opts.onRefresh : () => {/* noop */};
10
+ this.onResume = typeof opts.onResume === 'function' ? opts.onResume : () => {/* noop */};
10
11
 
11
12
  // used by pause/resume
12
13
  this.remainingMs = undefined;
@@ -41,7 +42,10 @@ export class InteractionTimer extends Timer {
41
42
  subscribeToVisibilityChange(state => {
42
43
  if (state === 'hidden') this.pause();
43
44
  // vis change --> visible is treated like a new interaction with the page
44
- else this.refresh();
45
+ else {
46
+ this.onResume();
47
+ this.refresh();
48
+ }
45
49
  }, false, false, this.abortController?.signal);
46
50
  }
47
51
  }
@@ -50,7 +54,7 @@ export class InteractionTimer extends Timer {
50
54
  this.abortController?.abort();
51
55
  }
52
56
  pause() {
53
- this.onPause?.();
57
+ this.onPause();
54
58
  clearTimeout(this.timer);
55
59
  this.remainingMs = this.initialMs - (Date.now() - this.startTimestamp);
56
60
  }
@@ -59,13 +63,6 @@ export class InteractionTimer extends Timer {
59
63
  this.timer = this.create(cb, ms);
60
64
  this.startTimestamp = Date.now();
61
65
  this.remainingMs = undefined;
62
- this.onRefresh?.();
66
+ this.onRefresh();
63
67
  }
64
-
65
- // NOT CURRENTLY UTILIZED BY ANYTHING
66
- // resume () {
67
- // if (!this.remainingMs || !this.isValid()) return
68
- // this.timer = this.create(this.cb, this.remainingMs)
69
- // this.remainingMs = undefined
70
- // }
71
68
  }
@@ -1,4 +1,3 @@
1
- import { faker } from '@faker-js/faker';
2
1
  import { isFileProtocol } from './protocol';
3
2
  test('should return true when location url contains file protocol', () => {
4
3
  jest.spyOn(window, 'location', 'get').mockReturnValue({
@@ -11,7 +11,8 @@ const bucketMap = {
11
11
  stn: [FEATURE_NAMES.sessionTrace],
12
12
  err: [FEATURE_NAMES.jserrors, FEATURE_NAMES.metrics],
13
13
  ins: [FEATURE_NAMES.pageAction],
14
- spa: [FEATURE_NAMES.spa]
14
+ spa: [FEATURE_NAMES.spa],
15
+ sr: [FEATURE_NAMES.sessionReplay]
15
16
  };
16
17
  export function activateFeatures(flags, agentIdentifier) {
17
18
  var sharedEE = ee.get(agentIdentifier);
@@ -7,11 +7,17 @@ export const submitData = {};
7
7
 
8
8
  /**
9
9
  * Send via JSONP. Do NOT call this function outside of a guaranteed web window environment.
10
- * @param {string} url
11
- * @param {string} jsonp
10
+ * @param {Object} args - The args
11
+ * @param {string} args.url - The URL to send to
12
+ * @param {string} args.jsonp - The string name of the jsonp cb method
13
+ * @returns {XMLHttpRequest}
12
14
  * @returns {Element}
13
15
  */
14
- submitData.jsonp = function jsonp(url, jsonp) {
16
+ submitData.jsonp = function jsonp(_ref) {
17
+ let {
18
+ url,
19
+ jsonp
20
+ } = _ref;
15
21
  try {
16
22
  if (isWorkerScope) {
17
23
  try {
@@ -19,7 +25,9 @@ submitData.jsonp = function jsonp(url, jsonp) {
19
25
  } catch (e) {
20
26
  // for now theres no other way to execute the callback from ingest without jsonp, or unsafe eval / new Function calls
21
27
  // future work needs to be conducted to allow ingest to return a more traditional JSON API-like experience for the entitlement flags
22
- submitData.xhrGet(url + '&jsonp=' + jsonp);
28
+ submitData.xhrGet({
29
+ url: url + '&jsonp=' + jsonp
30
+ });
23
31
  return false;
24
32
  }
25
33
  } else {
@@ -34,19 +42,38 @@ submitData.jsonp = function jsonp(url, jsonp) {
34
42
  // do nothing
35
43
  }
36
44
  };
37
- submitData.xhrGet = function xhrGet(url) {
38
- return submitData.xhr(url, undefined, false, 'GET');
45
+ submitData.xhrGet = function xhrGet(_ref2) {
46
+ let {
47
+ url
48
+ } = _ref2;
49
+ return submitData.xhr({
50
+ url,
51
+ sync: false,
52
+ method: 'GET'
53
+ });
39
54
  };
40
55
 
41
56
  /**
42
57
  * Send via XHR
43
- * @param {string} url
44
- * @param {string} body
45
- * @param {boolean} sync
58
+ * @param {Object} args - The args
59
+ * @param {string} args.url - The URL to send to
60
+ * @param {string=} args.body - The Stringified body
61
+ * @param {boolean=} args.sync - Run XHR as Synchronous
62
+ * @param {string=} [args.method=POST] - The XHR method to use
63
+ * @param {{key: string, value: string}[]} [args.headers] - The headers to attach
46
64
  * @returns {XMLHttpRequest}
47
65
  */
48
- submitData.xhr = function xhr(url, body, sync) {
49
- let method = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'POST';
66
+ submitData.xhr = function xhr(_ref3) {
67
+ let {
68
+ url,
69
+ body,
70
+ sync,
71
+ method = 'POST',
72
+ headers = [{
73
+ key: 'content-type',
74
+ value: 'text/plain'
75
+ }]
76
+ } = _ref3;
50
77
  var request = new XMLHttpRequest();
51
78
  request.open(method, url, !sync);
52
79
  try {
@@ -55,7 +82,9 @@ submitData.xhr = function xhr(url, body, sync) {
55
82
  } catch (e) {
56
83
  // do nothing
57
84
  }
58
- request.setRequestHeader('content-type', 'text/plain');
85
+ headers.forEach(header => {
86
+ request.setRequestHeader(header.key, header.value);
87
+ });
59
88
  request.send(body);
60
89
  return request;
61
90
  };
@@ -69,10 +98,15 @@ submitData.xhr = function xhr(url, body, sync) {
69
98
 
70
99
  /**
71
100
  * Send by appending an <img> element to the page. Do NOT call this function outside of a guaranteed web window environment.
72
- * @param {string} url
73
- * @returns {Element}
101
+ * @param {Object} args - The args
102
+ * @param {string} args.url - The URL to send to
103
+ * @returns {HTMLImageElement}
74
104
  */
75
- submitData.img = function img(url) {
105
+ submitData.img = function img(_ref4) {
106
+ let {
107
+ url
108
+ } = _ref4;
109
+ console.log('img url', url);
76
110
  var element = new Image();
77
111
  element.src = url;
78
112
  return element;
@@ -80,11 +114,16 @@ submitData.img = function img(url) {
80
114
 
81
115
  /**
82
116
  * Send via sendBeacon. Do NOT call this function outside of a guaranteed web window environment.
83
- * @param {string} url
84
- * @param {string} body
117
+ * @param {Object} args - The args
118
+ * @param {string} args.url - The URL to send to
119
+ * @param {string=} args.body - The Stringified body
85
120
  * @returns {boolean}
86
121
  */
87
- submitData.beacon = function (url, body) {
122
+ submitData.beacon = function (_ref5) {
123
+ let {
124
+ url,
125
+ body
126
+ } = _ref5;
88
127
  // Navigator has to be bound to ensure it does not error in some browsers
89
128
  // https://xgwang.me/posts/you-may-not-know-beacon/#it-may-throw-error%2C-be-sure-to-catch
90
129
  const send = window.navigator.sendBeacon.bind(window.navigator);