@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
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+
3
+ var _faker = require("@faker-js/faker");
4
+ var _instrumentBase = require("./instrument-base");
5
+ var _featureBase = require("./feature-base");
6
+ var _drain = require("../../common/drain/drain");
7
+ var _load = require("../../common/window/load");
8
+ var _lazyFeatureLoader = require("./lazy-feature-loader");
9
+ var _config = require("../../common/config/config");
10
+ var _agentSession = require("./agent-session");
11
+ var _console = require("../../common/util/console");
12
+ var globalScopeModule = _interopRequireWildcard(require("../../common/util/global-scope"));
13
+ var _features = require("../../loaders/features/features");
14
+ 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); }
15
+ 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; }
16
+ jest.enableAutomock();
17
+ jest.unmock('./instrument-base');
18
+ jest.unmock('../../loaders/features/features');
19
+ jest.mock('../../common/drain/drain', () => ({
20
+ __esModule: true,
21
+ drain: jest.fn(),
22
+ registerDrain: jest.fn()
23
+ }));
24
+ jest.mock('../../common/window/load', () => ({
25
+ __esModule: true,
26
+ onWindowLoad: jest.fn()
27
+ }));
28
+ jest.mock('../../common/util/global-scope', () => ({
29
+ __esModule: true,
30
+ isBrowserScope: undefined,
31
+ isWorkerScope: undefined
32
+ }));
33
+ jest.mock('../../common/config/config', () => ({
34
+ __esModule: true,
35
+ getConfigurationValue: jest.fn()
36
+ }));
37
+ jest.mock('./feature-base', () => ({
38
+ __esModule: true,
39
+ FeatureBase: jest.fn(function () {
40
+ this.agentIdentifier = arguments.length <= 0 ? undefined : arguments[0];
41
+ this.aggregator = arguments.length <= 1 ? undefined : arguments[1];
42
+ this.featureName = arguments.length <= 2 ? undefined : arguments[2];
43
+ })
44
+ }));
45
+ jest.mock('./agent-session', () => ({
46
+ __esModule: true,
47
+ setupAgentSession: jest.fn()
48
+ }));
49
+ let agentIdentifier;
50
+ let aggregator;
51
+ let featureName;
52
+ let mockAggregate;
53
+ beforeEach(() => {
54
+ jest.replaceProperty(globalScopeModule, 'isBrowserScope', true);
55
+ jest.replaceProperty(globalScopeModule, 'isWorkerScope', false);
56
+ agentIdentifier = _faker.faker.datatype.uuid();
57
+ aggregator = {};
58
+ featureName = _faker.faker.datatype.uuid();
59
+ mockAggregate = jest.fn(() => {/* noop */});
60
+ jest.mocked(_lazyFeatureLoader.lazyFeatureLoader).mockResolvedValue({
61
+ Aggregate: mockAggregate
62
+ });
63
+ });
64
+ test('should construct a new instrument', () => {
65
+ const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName);
66
+ expect(_featureBase.FeatureBase).toHaveBeenCalledWith(agentIdentifier, aggregator, featureName);
67
+ expect(instrument.featAggregate).toBeUndefined();
68
+ expect(instrument.auto).toEqual(true);
69
+ expect(instrument.abortHandler).toBeUndefined();
70
+ expect(_drain.registerDrain).toHaveBeenCalledWith(agentIdentifier, featureName);
71
+ });
72
+ test('should not immediately drain', () => {
73
+ const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName, false);
74
+ expect(_drain.registerDrain).not.toHaveBeenCalled();
75
+ });
76
+ test('should import aggregator on window load', async () => {
77
+ const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName);
78
+ const aggregateArgs = {
79
+ [_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
80
+ };
81
+ instrument.importAggregator(aggregateArgs);
82
+ const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
83
+ await windowLoadCallback();
84
+ expect(_load.onWindowLoad).toHaveBeenCalledWith(expect.any(Function), true);
85
+ expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalledWith(featureName, 'aggregate');
86
+ expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs);
87
+ });
88
+ test('should immediately import aggregator in worker scope', async () => {
89
+ jest.replaceProperty(globalScopeModule, 'isBrowserScope', false);
90
+ jest.replaceProperty(globalScopeModule, 'isWorkerScope', true);
91
+ const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName);
92
+ const aggregateArgs = {
93
+ [_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
94
+ };
95
+ instrument.importAggregator(aggregateArgs);
96
+
97
+ // In worker scope, we cannot wait on importLater method
98
+ await new Promise(process.nextTick);
99
+ expect(_load.onWindowLoad).not.toHaveBeenCalled();
100
+ expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalledWith(featureName, 'aggregate');
101
+ expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs);
102
+ });
103
+ test('should import the session manager and replay aggregate for new session', async () => {
104
+ jest.mocked(_config.getConfigurationValue).mockReturnValue(true);
105
+ jest.mocked(_agentSession.setupAgentSession).mockReturnValue({
106
+ isNew: true
107
+ });
108
+ const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, _features.FEATURE_NAMES.sessionReplay);
109
+ const aggregateArgs = {
110
+ [_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
111
+ };
112
+ instrument.importAggregator(aggregateArgs);
113
+ const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
114
+ await windowLoadCallback();
115
+ expect(_config.getConfigurationValue).toHaveBeenCalledWith(agentIdentifier, 'privacy.cookies_enabled');
116
+ expect(_agentSession.setupAgentSession).toHaveBeenCalledWith(agentIdentifier);
117
+ expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalledWith(_features.FEATURE_NAMES.sessionReplay, 'aggregate');
118
+ expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs);
119
+ });
120
+ test('should import the session manager and replay aggregate when a recording is active', async () => {
121
+ jest.mocked(_config.getConfigurationValue).mockReturnValue(true);
122
+ jest.mocked(_agentSession.setupAgentSession).mockReturnValue({
123
+ isNew: false,
124
+ state: {
125
+ sessionReplay: 1
126
+ }
127
+ });
128
+ const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, _features.FEATURE_NAMES.sessionReplay);
129
+ const aggregateArgs = {
130
+ [_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
131
+ };
132
+ instrument.importAggregator(aggregateArgs);
133
+ const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
134
+ await windowLoadCallback();
135
+ expect(_config.getConfigurationValue).toHaveBeenCalledWith(agentIdentifier, 'privacy.cookies_enabled');
136
+ expect(_agentSession.setupAgentSession).toHaveBeenCalledWith(agentIdentifier);
137
+ expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalledWith(_features.FEATURE_NAMES.sessionReplay, 'aggregate');
138
+ expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs);
139
+ });
140
+ test('should not import session aggregate when session is not new and a recording is not active', async () => {
141
+ jest.mocked(_config.getConfigurationValue).mockReturnValue(true);
142
+ jest.mocked(_agentSession.setupAgentSession).mockReturnValue({
143
+ isNew: false,
144
+ state: {
145
+ sessionReplay: 0
146
+ }
147
+ });
148
+ const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, _features.FEATURE_NAMES.sessionReplay);
149
+ const aggregateArgs = {
150
+ [_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
151
+ };
152
+ instrument.importAggregator(aggregateArgs);
153
+ const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
154
+ await windowLoadCallback();
155
+ expect(_config.getConfigurationValue).toHaveBeenCalledWith(agentIdentifier, 'privacy.cookies_enabled');
156
+ expect(_agentSession.setupAgentSession).toHaveBeenCalledWith(agentIdentifier);
157
+ expect(_drain.drain).toHaveBeenCalledWith(agentIdentifier, _features.FEATURE_NAMES.sessionReplay);
158
+ expect(_lazyFeatureLoader.lazyFeatureLoader).not.toHaveBeenCalled();
159
+ expect(mockAggregate).not.toHaveBeenCalled();
160
+ });
161
+ test('feature still imports by default even when setupAgentSession throws an error', async () => {
162
+ jest.mocked(_config.getConfigurationValue).mockReturnValue(true);
163
+ jest.mocked(_agentSession.setupAgentSession).mockImplementation(() => {
164
+ throw new Error(_faker.faker.lorem.sentence());
165
+ });
166
+ const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName);
167
+ const aggregateArgs = {
168
+ [_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
169
+ };
170
+ instrument.abortHandler = jest.fn();
171
+ instrument.importAggregator(aggregateArgs);
172
+ const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
173
+ await windowLoadCallback();
174
+ expect(_load.onWindowLoad).toHaveBeenCalledWith(expect.any(Function), true);
175
+ expect(instrument.abortHandler).not.toHaveBeenCalled();
176
+ expect(_console.warn).toHaveBeenCalledWith(expect.stringContaining('A problem occurred when starting up session manager'), expect.any(Error));
177
+ expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalled();
178
+ expect(mockAggregate).toHaveBeenCalled();
179
+ });
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ var _faker = require("@faker-js/faker");
4
+ var _features = require("../../loaders/features/features");
5
+ var _lazyFeatureLoader = require("./lazy-feature-loader");
6
+ // Use enableAutomock to make it easier to mock all the things that get imported by the aggregators
7
+ jest.enableAutomock();
8
+ // Unmock the file under test and the constants file
9
+ jest.unmock('../../loaders/features/features');
10
+ jest.unmock('./lazy-feature-loader');
11
+ test.each(Object.keys(_features.FEATURE_NAMES))('should import the aggregate for feature %s', async key => {
12
+ const featureName = _features.FEATURE_NAMES[key];
13
+ const randomId = _faker.faker.datatype.uuid();
14
+ jest.setMock("../".concat(featureName, "/aggregate"), {
15
+ id: randomId,
16
+ featureName
17
+ });
18
+ const result = await (0, _lazyFeatureLoader.lazyFeatureLoader)(featureName, 'aggregate');
19
+ expect(result.id).toEqual(randomId);
20
+ expect(result.featureName).toEqual(featureName);
21
+ });
22
+ test('should throw an error when the featureName is not supported', async () => {
23
+ const featureName = _faker.faker.datatype.uuid();
24
+ expect(() => (0, _lazyFeatureLoader.lazyFeatureLoader)(featureName, 'aggregate')).toThrow();
25
+ });
26
+ test('should return undefined when the featurePart is not supported', async () => {
27
+ const featureName = _faker.faker.datatype.uuid();
28
+ const featurePart = _faker.faker.datatype.uuid();
29
+ expect((0, _lazyFeatureLoader.lazyFeatureLoader)(featureName, featurePart)).toBeUndefined();
30
+ });
@@ -34,7 +34,6 @@ class Agent {
34
34
  });
35
35
  this.features = {};
36
36
  this.desiredFeatures = new Set(options.features || []); // expected to be a list of static Instrument/InstrumentBase classes, see "spa.js" for example
37
-
38
37
  // For Now... ALL agents must make the rum call whether the page_view_event feature was enabled or not.
39
38
  // NR1 creates an index on the rum call, and if not seen for a few days, will remove the browser app!
40
39
  // Future work is being planned to evaluate removing this behavior from the backend, but for now we must ensure this call is made
@@ -158,7 +158,7 @@ function setAPI(agentIdentifier, forceDrain) {
158
158
  };
159
159
 
160
160
  // theres no window.load event on non-browser scopes, lazy load immediately
161
- if (_globalScope.isWorkerScope) lazyLoad();
161
+ if (!_globalScope.isBrowserScope) lazyLoad();
162
162
  // try to stay out of the way of the window.load event, lazy load once that has finished.
163
163
  else (0, _load.onWindowLoad)(() => lazyLoad(), true);
164
164
  function lazyLoad() {
@@ -11,6 +11,8 @@ function getFeatureDependencyNames(feature) {
11
11
  return [_features.FEATURE_NAMES.jserrors];
12
12
  case _features.FEATURE_NAMES.sessionTrace:
13
13
  return [_features.FEATURE_NAMES.ajax, _features.FEATURE_NAMES.pageViewEvent];
14
+ case _features.FEATURE_NAMES.sessionReplay:
15
+ return [_features.FEATURE_NAMES.sessionTrace];
14
16
  case _features.FEATURE_NAMES.pageViewTiming:
15
17
  return [_features.FEATURE_NAMES.pageViewEvent];
16
18
  // this could change if we disconnect window load timings
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.234.0";
9
+ export const VERSION = "1.235.0";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.234.0";
9
+ export const VERSION = "1.235.0";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @file Keeps an object alive that is passed to all feature aggregate modules.
3
+ * The purpose is to have a way for communication and signals to relay across features at runtime.
4
+ * This object can hold any arbitrary values and should be treated as on-the-fly dynamic.
5
+ */
6
+
7
+ let onReplayReady;
8
+ const sessionReplayInitialized = new Promise(resolve => onReplayReady = resolve);
9
+ export const sharedChannel = Object.freeze({
10
+ onReplayReady,
11
+ sessionReplayInitialized
12
+ });
@@ -8,6 +8,7 @@ import { SharedContext } from '../context/shared-context';
8
8
  import { Harvest, getSubmitMethod } from './harvest';
9
9
  import { subscribeToEOL } from '../unload/eol';
10
10
  import { getConfigurationValue } from '../config/config';
11
+ import { SESSION_EVENTS } from '../session/session-entity';
11
12
 
12
13
  /**
13
14
  * Periodically invokes harvest calls and handles retries
@@ -37,9 +38,18 @@ export class HarvestScheduler extends SharedContext {
37
38
  // unload if EOL mechanism fires
38
39
  subscribeToEOL(this.unload.bind(this), getConfigurationValue(this.sharedContext.agentIdentifier, 'allow_bfcache')); // TO DO: remove feature flag after rls stable
39
40
 
40
- // unload if session resets
41
- this.sharedContext?.ee.on('session-reset', this.unload.bind(this));
41
+ /* Flush all buffered data if session resets and give up retries. This should be synchronous to ensure that the correct `session` value is sent.
42
+ 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
43
+ the wrong session ID. */
44
+ this.sharedContext?.ee.on(SESSION_EVENTS.RESET, () => this.runHarvest({
45
+ forceNoRetry: true
46
+ }));
42
47
  }
48
+
49
+ /**
50
+ * 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
51
+ * 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.
52
+ */
43
53
  unload() {
44
54
  if (this.aborted) return;
45
55
  // If opts.onUnload is defined, these are special actions to execute before attempting to send the final payload.
@@ -111,7 +121,7 @@ export class HarvestScheduler extends SharedContext {
111
121
  payload,
112
122
  opts,
113
123
  submitMethod,
114
- cbFinished: onHarvestFinished,
124
+ cbFinished: cbRanAfterSend,
115
125
  customUrl: this.opts.customUrl,
116
126
  raw: this.opts.raw
117
127
  });
@@ -120,8 +130,14 @@ export class HarvestScheduler extends SharedContext {
120
130
  this.scheduleHarvest();
121
131
  }
122
132
  return;
123
- function onHarvestFinished(result) {
124
- if (result.blocked) scheduler.onHarvestBlocked(opts, result);else scheduler.onHarvestFinished(opts, result);
133
+
134
+ /**
135
+ * 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.
136
+ * @param {Object} result
137
+ */
138
+ function cbRanAfterSend(result) {
139
+ if (opts?.forceNoRetry) result.retry = false; // discard unsent data rather than re-queuing for next harvest attempt
140
+ scheduler.onHarvestFinished(opts, result);
125
141
  }
126
142
  }
127
143
  onHarvestFinished(opts, result) {