@newrelic/browser-agent 0.1.231 → 1.232.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.
- package/README.md +2 -2
- package/dist/cjs/common/config/state/configurable.js +27 -21
- package/dist/cjs/common/config/state/init.js +8 -0
- package/dist/cjs/common/config/state/runtime.js +24 -26
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/context/shared-context.js +2 -1
- package/dist/cjs/common/event-emitter/contextual-ee.test.js +2 -2
- package/dist/cjs/common/event-emitter/register-handler.test.js +1 -1
- package/dist/cjs/common/event-listener/event-listener-opts.js +4 -2
- package/dist/cjs/common/harvest/harvest-scheduler.js +14 -11
- package/dist/cjs/common/harvest/harvest.js +3 -1
- package/dist/cjs/common/session/constants.js +12 -0
- package/dist/cjs/common/session/session-entity.js +278 -0
- package/dist/cjs/common/session/session-entity.test.js +436 -0
- package/dist/cjs/common/storage/first-party-cookies.js +35 -0
- package/dist/cjs/common/storage/local-memory.js +35 -0
- package/dist/cjs/common/storage/local-memory.test.js +20 -0
- package/dist/cjs/common/storage/local-storage.js +33 -0
- package/dist/cjs/common/storage/local-storage.test.js +14 -0
- package/dist/cjs/common/timer/interaction-timer.js +78 -0
- package/dist/cjs/common/timer/interaction-timer.test.js +216 -0
- package/dist/cjs/common/timer/timer.js +32 -0
- package/dist/cjs/common/timer/timer.test.js +105 -0
- package/dist/cjs/common/unload/eol.js +2 -2
- package/dist/cjs/common/util/data-size.js +6 -0
- package/dist/cjs/common/util/data-size.test.js +47 -0
- package/dist/cjs/common/util/invoke.js +73 -0
- package/dist/cjs/common/util/invoke.test.js +49 -0
- package/dist/cjs/common/util/obfuscate.js +0 -4
- package/dist/cjs/common/window/page-visibility.js +3 -1
- package/dist/cjs/common/wrap/wrap-timer.js +1 -1
- package/dist/cjs/features/ajax/aggregate/index.js +2 -2
- package/dist/cjs/features/jserrors/aggregate/index.js +3 -3
- package/dist/cjs/features/metrics/aggregate/index.js +13 -2
- package/dist/cjs/features/page_action/aggregate/index.js +2 -2
- package/dist/cjs/features/page_view_event/aggregate/index.js +6 -3
- package/dist/cjs/features/page_view_timing/aggregate/index.js +6 -6
- package/dist/cjs/features/session_trace/aggregate/index.js +2 -2
- package/dist/cjs/features/spa/aggregate/index.js +6 -5
- package/dist/cjs/features/utils/agent-session.js +73 -0
- package/dist/cjs/features/utils/feature-base.js +1 -1
- package/dist/cjs/features/utils/instrument-base.js +7 -2
- package/dist/cjs/features/utils/lazy-loader.js +1 -1
- package/dist/cjs/loaders/agent.js +1 -1
- package/dist/cjs/loaders/api/api.js +1 -4
- package/dist/cjs/loaders/api/apiAsync.js +3 -2
- package/dist/cjs/loaders/configure/configure.js +0 -6
- package/dist/esm/common/config/state/configurable.js +26 -20
- package/dist/esm/common/config/state/init.js +8 -0
- package/dist/esm/common/config/state/runtime.js +24 -26
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/context/shared-context.js +2 -1
- package/dist/esm/common/event-emitter/contextual-ee.test.js +2 -2
- package/dist/esm/common/event-emitter/register-handler.test.js +1 -1
- package/dist/esm/common/event-listener/event-listener-opts.js +4 -2
- package/dist/esm/common/harvest/harvest-scheduler.js +14 -11
- package/dist/esm/common/harvest/harvest.js +3 -1
- package/dist/esm/common/session/constants.js +3 -0
- package/dist/esm/common/session/session-entity.js +271 -0
- package/dist/esm/common/session/session-entity.test.js +434 -0
- package/dist/esm/common/storage/first-party-cookies.js +28 -0
- package/dist/esm/common/storage/local-memory.js +28 -0
- package/dist/esm/common/storage/local-memory.test.js +18 -0
- package/dist/esm/common/storage/local-storage.js +26 -0
- package/dist/esm/common/storage/local-storage.test.js +12 -0
- package/dist/esm/common/timer/interaction-timer.js +71 -0
- package/dist/esm/common/timer/interaction-timer.test.js +214 -0
- package/dist/esm/common/timer/timer.js +25 -0
- package/dist/esm/common/timer/timer.test.js +103 -0
- package/dist/esm/common/unload/eol.js +1 -1
- package/dist/esm/common/util/data-size.js +7 -0
- package/dist/esm/common/util/data-size.test.js +45 -0
- package/dist/esm/common/util/invoke.js +66 -0
- package/dist/esm/common/util/invoke.test.js +47 -0
- package/dist/esm/common/util/obfuscate.js +0 -4
- package/dist/esm/common/window/page-visibility.js +3 -1
- package/dist/esm/common/wrap/wrap-timer.js +1 -1
- package/dist/esm/features/ajax/aggregate/index.js +2 -2
- package/dist/esm/features/jserrors/aggregate/index.js +3 -3
- package/dist/esm/features/metrics/aggregate/index.js +14 -3
- package/dist/esm/features/page_action/aggregate/index.js +2 -2
- package/dist/esm/features/page_view_event/aggregate/index.js +6 -3
- package/dist/esm/features/page_view_timing/aggregate/index.js +6 -6
- package/dist/esm/features/session_trace/aggregate/index.js +2 -2
- package/dist/esm/features/spa/aggregate/index.js +6 -5
- package/dist/esm/features/utils/agent-session.js +67 -0
- package/dist/esm/features/utils/feature-base.js +1 -1
- package/dist/esm/features/utils/instrument-base.js +7 -2
- package/dist/esm/features/utils/lazy-loader.js +1 -1
- package/dist/esm/loaders/agent.js +1 -1
- package/dist/esm/loaders/api/api.js +2 -5
- package/dist/esm/loaders/api/apiAsync.js +2 -1
- package/dist/esm/loaders/configure/configure.js +2 -8
- package/dist/types/common/config/state/configurable.d.ts.map +1 -1
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/config/state/runtime.d.ts.map +1 -1
- package/dist/types/common/context/shared-context.d.ts.map +1 -1
- package/dist/types/common/event-listener/event-listener-opts.d.ts +2 -2
- package/dist/types/common/event-listener/event-listener-opts.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest-scheduler.d.ts +1 -0
- package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/session/constants.d.ts +4 -0
- package/dist/types/common/session/constants.d.ts.map +1 -0
- package/dist/types/common/session/session-entity.d.ts +72 -0
- package/dist/types/common/session/session-entity.d.ts.map +1 -0
- package/dist/types/common/storage/first-party-cookies.d.ts +8 -0
- package/dist/types/common/storage/first-party-cookies.d.ts.map +1 -0
- package/dist/types/common/storage/local-memory.d.ts +8 -0
- package/dist/types/common/storage/local-memory.d.ts.map +1 -0
- package/dist/types/common/storage/local-storage.d.ts +6 -0
- package/dist/types/common/storage/local-storage.d.ts.map +1 -0
- package/dist/types/common/timer/interaction-timer.d.ts +11 -0
- package/dist/types/common/timer/interaction-timer.d.ts.map +1 -0
- package/dist/types/common/timer/timer.d.ts +12 -0
- package/dist/types/common/timer/timer.d.ts.map +1 -0
- package/dist/types/common/util/data-size.d.ts +7 -1
- package/dist/types/common/util/data-size.d.ts.map +1 -1
- package/dist/types/common/util/invoke.d.ts +35 -0
- package/dist/types/common/util/invoke.d.ts.map +1 -0
- package/dist/types/common/util/obfuscate.d.ts.map +1 -1
- package/dist/types/common/window/page-visibility.d.ts +1 -1
- package/dist/types/common/window/page-visibility.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts +2 -2
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +2 -2
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts +2 -2
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_action/aggregate/index.d.ts +2 -2
- package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -2
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts +2 -2
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +2 -2
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/index.d.ts +2 -2
- package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/agent-session.d.ts +2 -0
- package/dist/types/features/utils/agent-session.d.ts.map +1 -0
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/features/utils/lazy-loader.d.ts +2 -2
- package/dist/types/features/utils/lazy-loader.d.ts.map +1 -1
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/dist/types/loaders/api/apiAsync.d.ts.map +1 -1
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/package.json +6 -5
- package/src/common/config/state/configurable.js +26 -19
- package/src/common/config/state/init.js +7 -0
- package/src/common/config/state/runtime.js +22 -27
- package/src/common/context/shared-context.js +2 -1
- package/src/common/event-emitter/contextual-ee.test.js +2 -2
- package/src/common/event-emitter/register-handler.test.js +1 -1
- package/src/common/event-listener/event-listener-opts.js +4 -4
- package/src/common/harvest/harvest-scheduler.js +12 -8
- package/src/common/harvest/harvest.js +3 -1
- package/src/common/session/constants.js +3 -0
- package/src/common/session/session-entity.js +271 -0
- package/src/common/session/session-entity.test.js +317 -0
- package/src/common/storage/first-party-cookies.js +31 -0
- package/src/common/storage/local-memory.js +30 -0
- package/src/common/storage/local-memory.test.js +19 -0
- package/src/common/storage/local-storage.js +28 -0
- package/src/common/storage/local-storage.test.js +17 -0
- package/src/common/timer/interaction-timer.js +75 -0
- package/src/common/timer/interaction-timer.test.js +167 -0
- package/src/common/timer/timer.js +31 -0
- package/src/common/timer/timer.test.js +100 -0
- package/src/common/unload/eol.js +1 -1
- package/src/common/util/data-size.js +6 -0
- package/src/common/util/data-size.test.js +50 -0
- package/src/common/util/invoke.js +55 -0
- package/src/common/util/invoke.test.js +65 -0
- package/src/common/util/obfuscate.js +0 -4
- package/src/common/window/page-visibility.js +2 -2
- package/src/common/wrap/wrap-timer.js +1 -1
- package/src/features/ajax/aggregate/index.js +2 -2
- package/src/features/jserrors/aggregate/index.js +3 -3
- package/src/features/metrics/aggregate/index.js +18 -3
- package/src/features/page_action/aggregate/index.js +2 -2
- package/src/features/page_view_event/aggregate/index.js +6 -3
- package/src/features/page_view_timing/aggregate/index.js +6 -6
- package/src/features/session_trace/aggregate/index.js +2 -2
- package/src/features/spa/aggregate/index.js +5 -5
- package/src/features/utils/agent-session.js +68 -0
- package/src/features/utils/feature-base.js +1 -1
- package/src/features/utils/instrument-base.js +5 -2
- package/src/features/utils/lazy-loader.js +1 -1
- package/src/loaders/agent.js +1 -1
- package/src/loaders/api/api.js +2 -5
- package/src/loaders/api/apiAsync.js +2 -1
- package/src/loaders/configure/configure.js +2 -7
- package/dist/cjs/common/util/single.js +0 -23
- package/dist/cjs/common/window/session-storage.js +0 -87
- package/dist/cjs/features/utils/aggregate-base.js +0 -13
- package/dist/esm/common/util/single.js +0 -16
- package/dist/esm/common/window/session-storage.js +0 -77
- package/dist/esm/features/utils/aggregate-base.js +0 -6
- package/dist/types/common/util/single.d.ts +0 -2
- package/dist/types/common/util/single.d.ts.map +0 -1
- package/dist/types/common/window/session-storage.d.ts +0 -18
- package/dist/types/common/window/session-storage.d.ts.map +0 -1
- package/dist/types/features/utils/aggregate-base.d.ts +0 -4
- package/dist/types/features/utils/aggregate-base.d.ts.map +0 -1
- package/src/common/util/single.js +0 -18
- package/src/common/window/session-storage.js +0 -75
- package/src/features/utils/aggregate-base.js +0 -7
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { InteractionTimer } from './interaction-timer';
|
|
2
|
+
jest.useFakeTimers();
|
|
3
|
+
let now;
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
now = Date.now();
|
|
6
|
+
jest.setSystemTime(now);
|
|
7
|
+
});
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
jest.clearAllMocks();
|
|
10
|
+
});
|
|
11
|
+
describe('constructor', () => {
|
|
12
|
+
test('appropriate properties are set with valid values -- no refresh', () => {
|
|
13
|
+
const timer = new InteractionTimer({
|
|
14
|
+
onEnd: jest.fn()
|
|
15
|
+
}, 100);
|
|
16
|
+
const requiredKeys = ['onEnd', 'initialMs', 'startTimestamp', 'timer'];
|
|
17
|
+
expect(requiredKeys.every(rk => !!timer[rk])).toBeTruthy();
|
|
18
|
+
});
|
|
19
|
+
test('appropriate properties are set with valid values -- with refresh', () => {
|
|
20
|
+
const timer = new InteractionTimer({
|
|
21
|
+
onEnd: jest.fn()
|
|
22
|
+
}, 100);
|
|
23
|
+
const requiredKeys = ['onEnd', 'refresh', 'initialMs', 'startTimestamp', 'timer'];
|
|
24
|
+
expect(requiredKeys.every(rk => !!timer[rk])).toBeTruthy();
|
|
25
|
+
});
|
|
26
|
+
test('required keys are enforced', () => {
|
|
27
|
+
try {
|
|
28
|
+
new InteractionTimer({}, 100);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
expect(e).toEqual(new Error('onEnd handler is required'));
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
new InteractionTimer({
|
|
34
|
+
onEnd: jest.fn()
|
|
35
|
+
});
|
|
36
|
+
} catch (e) {
|
|
37
|
+
expect(e).toEqual(new Error('ms duration is required'));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
test('refresh type timers set event listeners', () => {
|
|
41
|
+
// eslint-disable-next-line
|
|
42
|
+
let ee = {
|
|
43
|
+
on: jest.fn().mockImplementation((evt, cb) => {
|
|
44
|
+
cb([{
|
|
45
|
+
type: 'click'
|
|
46
|
+
}]);
|
|
47
|
+
})
|
|
48
|
+
};
|
|
49
|
+
let it = new InteractionTimer({
|
|
50
|
+
onEnd: jest.fn(),
|
|
51
|
+
onRefresh: jest.fn(),
|
|
52
|
+
ee
|
|
53
|
+
}, 100);
|
|
54
|
+
// scroll, keypress, click
|
|
55
|
+
expect(ee.on).toHaveBeenCalledTimes(1);
|
|
56
|
+
expect(it.onRefresh).toHaveBeenCalledTimes(1);
|
|
57
|
+
|
|
58
|
+
// eslint-disable-next-line
|
|
59
|
+
ee = {
|
|
60
|
+
on: jest.fn().mockImplementation((evt, cb) => {
|
|
61
|
+
cb([{
|
|
62
|
+
type: 'scroll'
|
|
63
|
+
}]);
|
|
64
|
+
})
|
|
65
|
+
};
|
|
66
|
+
it = new InteractionTimer({
|
|
67
|
+
onEnd: jest.fn(),
|
|
68
|
+
onRefresh: jest.fn(),
|
|
69
|
+
ee
|
|
70
|
+
}, 100);
|
|
71
|
+
// scroll, keypress, click
|
|
72
|
+
expect(ee.on).toHaveBeenCalledTimes(1);
|
|
73
|
+
expect(it.onRefresh).toHaveBeenCalledTimes(1);
|
|
74
|
+
|
|
75
|
+
// eslint-disable-next-line
|
|
76
|
+
ee = {
|
|
77
|
+
on: jest.fn().mockImplementation((evt, cb) => {
|
|
78
|
+
cb([{
|
|
79
|
+
type: 'keydown'
|
|
80
|
+
}]);
|
|
81
|
+
})
|
|
82
|
+
};
|
|
83
|
+
it = new InteractionTimer({
|
|
84
|
+
onEnd: jest.fn(),
|
|
85
|
+
onRefresh: jest.fn(),
|
|
86
|
+
ee
|
|
87
|
+
}, 100);
|
|
88
|
+
// scroll, keypress, click
|
|
89
|
+
expect(ee.on).toHaveBeenCalledTimes(1);
|
|
90
|
+
expect(it.onRefresh).toHaveBeenCalledTimes(1);
|
|
91
|
+
const aelSpy = jest.spyOn(document, 'addEventListener');
|
|
92
|
+
// eslint-disable-next-line
|
|
93
|
+
ee = {
|
|
94
|
+
on: jest.fn().mockImplementation((evt, cb) => {
|
|
95
|
+
cb([{
|
|
96
|
+
type: 'keydown'
|
|
97
|
+
}]);
|
|
98
|
+
})
|
|
99
|
+
};
|
|
100
|
+
it = new InteractionTimer({
|
|
101
|
+
onEnd: jest.fn(),
|
|
102
|
+
onRefresh: jest.fn(),
|
|
103
|
+
ee
|
|
104
|
+
}, 100);
|
|
105
|
+
// visibility change
|
|
106
|
+
expect(aelSpy).toHaveBeenCalledTimes(1);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('create()', () => {
|
|
110
|
+
test('Create sets a timeout that can execute a cb', () => {
|
|
111
|
+
const timer = new InteractionTimer({
|
|
112
|
+
onEnd: jest.fn()
|
|
113
|
+
}, 100);
|
|
114
|
+
expect(timer.timer).toBeTruthy();
|
|
115
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
116
|
+
jest.runOnlyPendingTimers();
|
|
117
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(1);
|
|
118
|
+
});
|
|
119
|
+
test('Create can fallback to use defaults', () => {
|
|
120
|
+
let called = 0;
|
|
121
|
+
const timer1 = new InteractionTimer({
|
|
122
|
+
onEnd: jest.fn()
|
|
123
|
+
}, 100);
|
|
124
|
+
timer1.create();
|
|
125
|
+
const timer2 = new InteractionTimer({
|
|
126
|
+
onEnd: jest.fn()
|
|
127
|
+
}, 100);
|
|
128
|
+
timer2.create(timer2.onEnd);
|
|
129
|
+
const timer3 = new InteractionTimer({
|
|
130
|
+
onEnd: jest.fn()
|
|
131
|
+
}, 100);
|
|
132
|
+
timer3.create(undefined, 100);
|
|
133
|
+
jest.runAllTimers(200);
|
|
134
|
+
expect(timer1.onEnd).toHaveBeenCalledTimes(1);
|
|
135
|
+
expect(timer2.onEnd).toHaveBeenCalledTimes(1);
|
|
136
|
+
expect(timer3.onEnd).toHaveBeenCalledTimes(1);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
describe('refresh()', () => {
|
|
140
|
+
test('refresh prevents the callback from firing', () => {
|
|
141
|
+
const timer = new InteractionTimer({
|
|
142
|
+
onEnd: jest.fn(),
|
|
143
|
+
onRefresh: jest.fn()
|
|
144
|
+
}, 100);
|
|
145
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
146
|
+
jest.advanceTimersByTime(75);
|
|
147
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
148
|
+
timer.refresh();
|
|
149
|
+
jest.advanceTimersByTime(75);
|
|
150
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
151
|
+
jest.advanceTimersByTime(100);
|
|
152
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(1);
|
|
153
|
+
});
|
|
154
|
+
test('refresh executes a callback for consumers', () => {
|
|
155
|
+
const timer = new InteractionTimer({
|
|
156
|
+
onEnd: jest.fn(),
|
|
157
|
+
onRefresh: jest.fn()
|
|
158
|
+
}, 100);
|
|
159
|
+
timer.refresh();
|
|
160
|
+
expect(timer.onRefresh).toHaveBeenCalledTimes(1);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
describe('pause()', () => {
|
|
164
|
+
test('pause prevents the callback from firing', () => {
|
|
165
|
+
const timer = new InteractionTimer({
|
|
166
|
+
onEnd: jest.fn()
|
|
167
|
+
}, 100);
|
|
168
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
169
|
+
timer.pause();
|
|
170
|
+
jest.advanceTimersByTime(150);
|
|
171
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
172
|
+
});
|
|
173
|
+
test('pause sets remainingMs timestamp', () => {
|
|
174
|
+
const timer = new InteractionTimer({
|
|
175
|
+
onEnd: jest.fn()
|
|
176
|
+
}, 100);
|
|
177
|
+
expect(timer.remainingMs).toEqual(undefined);
|
|
178
|
+
timer.pause();
|
|
179
|
+
expect(timer.remainingMs).toEqual(timer.initialMs - (now - timer.startTimestamp));
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
describe('clear()', () => {
|
|
183
|
+
test('clear prevents the callback from firing and deletes the pointer', () => {
|
|
184
|
+
const timer = new InteractionTimer({
|
|
185
|
+
onEnd: jest.fn()
|
|
186
|
+
}, 100);
|
|
187
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
188
|
+
timer.clear();
|
|
189
|
+
jest.advanceTimersByTime(150);
|
|
190
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
191
|
+
expect(timer.timer).toEqual(null);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
describe('end()', () => {
|
|
195
|
+
test('end clears the callback and calls the onEnd callback', () => {
|
|
196
|
+
const timer = new InteractionTimer({
|
|
197
|
+
onEnd: jest.fn()
|
|
198
|
+
}, 100);
|
|
199
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
200
|
+
timer.end();
|
|
201
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(1);
|
|
202
|
+
expect(timer.timer).toEqual(null);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
describe('isValid', () => {
|
|
206
|
+
test('isValid validates timeStamps', () => {
|
|
207
|
+
const timer = new InteractionTimer({
|
|
208
|
+
onEnd: jest.fn()
|
|
209
|
+
}, 100);
|
|
210
|
+
expect(timer.isValid()).toEqual(true);
|
|
211
|
+
timer.startTimestamp -= 100;
|
|
212
|
+
expect(timer.isValid()).toEqual(false);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class Timer {
|
|
2
|
+
constructor(opts, ms) {
|
|
3
|
+
if (!opts.onEnd) throw new Error('onEnd handler is required');
|
|
4
|
+
if (!ms) throw new Error('ms duration is required');
|
|
5
|
+
this.onEnd = opts.onEnd;
|
|
6
|
+
this.initialMs = ms;
|
|
7
|
+
this.startTimestamp = Date.now();
|
|
8
|
+
this.timer = this.create(this.onEnd, ms);
|
|
9
|
+
}
|
|
10
|
+
create(cb, ms) {
|
|
11
|
+
if (this.timer) this.clear();
|
|
12
|
+
return setTimeout(() => cb ? cb() : this.onEnd(), ms || this.initialMs);
|
|
13
|
+
}
|
|
14
|
+
clear() {
|
|
15
|
+
clearTimeout(this.timer);
|
|
16
|
+
this.timer = null;
|
|
17
|
+
}
|
|
18
|
+
end() {
|
|
19
|
+
this.clear();
|
|
20
|
+
this.onEnd();
|
|
21
|
+
}
|
|
22
|
+
isValid() {
|
|
23
|
+
return this.initialMs - (Date.now() - this.startTimestamp) > 0;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Timer } from './timer';
|
|
2
|
+
jest.useFakeTimers();
|
|
3
|
+
let now;
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
now = Date.now();
|
|
6
|
+
jest.setSystemTime(now);
|
|
7
|
+
});
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
jest.clearAllMocks();
|
|
10
|
+
});
|
|
11
|
+
describe('constructor', () => {
|
|
12
|
+
test('appropriate properties are set with valid values -- no refresh', () => {
|
|
13
|
+
const timer = new Timer({
|
|
14
|
+
onEnd: jest.fn()
|
|
15
|
+
}, 100);
|
|
16
|
+
const requiredKeys = ['onEnd', 'initialMs', 'startTimestamp', 'timer'];
|
|
17
|
+
expect(requiredKeys.every(rk => !!timer[rk])).toBeTruthy();
|
|
18
|
+
});
|
|
19
|
+
test('appropriate properties are set with valid values -- with refresh', () => {
|
|
20
|
+
const timer = new Timer({
|
|
21
|
+
onEnd: jest.fn()
|
|
22
|
+
}, 100);
|
|
23
|
+
const requiredKeys = ['onEnd', 'initialMs', 'startTimestamp', 'timer'];
|
|
24
|
+
expect(requiredKeys.every(rk => !!timer[rk])).toBeTruthy();
|
|
25
|
+
});
|
|
26
|
+
test('required keys are enforced', () => {
|
|
27
|
+
try {
|
|
28
|
+
new Timer({}, 100);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
expect(e).toEqual(new Error('onEnd handler is required'));
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
new Timer({
|
|
34
|
+
onEnd: jest.fn()
|
|
35
|
+
});
|
|
36
|
+
} catch (e) {
|
|
37
|
+
expect(e).toEqual(new Error('ms duration is required'));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('create()', () => {
|
|
42
|
+
test('Create sets a timeout that can execute a cb', () => {
|
|
43
|
+
const timer = new Timer({
|
|
44
|
+
onEnd: jest.fn()
|
|
45
|
+
}, 100);
|
|
46
|
+
expect(timer.timer).toBeTruthy();
|
|
47
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
48
|
+
jest.runOnlyPendingTimers();
|
|
49
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(1);
|
|
50
|
+
});
|
|
51
|
+
test('Create can fallback to use defaults', () => {
|
|
52
|
+
let called = 0;
|
|
53
|
+
const timer1 = new Timer({
|
|
54
|
+
onEnd: jest.fn()
|
|
55
|
+
}, 100);
|
|
56
|
+
timer1.create();
|
|
57
|
+
const timer2 = new Timer({
|
|
58
|
+
onEnd: jest.fn()
|
|
59
|
+
}, 100);
|
|
60
|
+
timer2.create(timer2.onEnd);
|
|
61
|
+
const timer3 = new Timer({
|
|
62
|
+
onEnd: jest.fn()
|
|
63
|
+
}, 100);
|
|
64
|
+
timer3.create(undefined, 100);
|
|
65
|
+
jest.runAllTimers(200);
|
|
66
|
+
expect(timer1.onEnd).toHaveBeenCalledTimes(1);
|
|
67
|
+
expect(timer2.onEnd).toHaveBeenCalledTimes(1);
|
|
68
|
+
expect(timer3.onEnd).toHaveBeenCalledTimes(1);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('clear()', () => {
|
|
72
|
+
test('clear prevents the callback from firing and deletes the pointer', () => {
|
|
73
|
+
const timer = new Timer({
|
|
74
|
+
onEnd: jest.fn()
|
|
75
|
+
}, 100);
|
|
76
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
77
|
+
timer.clear();
|
|
78
|
+
jest.advanceTimersByTime(150);
|
|
79
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
80
|
+
expect(timer.timer).toEqual(null);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe('end()', () => {
|
|
84
|
+
test('end clears the callback and calls the onEnd callback', () => {
|
|
85
|
+
const timer = new Timer({
|
|
86
|
+
onEnd: jest.fn()
|
|
87
|
+
}, 100);
|
|
88
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(0);
|
|
89
|
+
timer.end();
|
|
90
|
+
expect(timer.onEnd).toHaveBeenCalledTimes(1);
|
|
91
|
+
expect(timer.timer).toEqual(null);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('isValid', () => {
|
|
95
|
+
test('isValid validates timeStamps', () => {
|
|
96
|
+
const timer = new Timer({
|
|
97
|
+
onEnd: jest.fn()
|
|
98
|
+
}, 100);
|
|
99
|
+
expect(timer.isValid()).toEqual(true);
|
|
100
|
+
timer.startTimestamp -= 100;
|
|
101
|
+
expect(timer.isValid()).toEqual(false);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { ffVersion } from '../browser-version/firefox-version';
|
|
6
6
|
import { windowAddEventListener } from '../event-listener/event-listener-opts';
|
|
7
|
-
import { single } from '../util/
|
|
7
|
+
import { single } from '../util/invoke';
|
|
8
8
|
import { globalScope, isWorkerScope, isBrowserScope } from '../util/global-scope';
|
|
9
9
|
import { subscribeToVisibilityChange } from '../window/page-visibility';
|
|
10
10
|
if (isWorkerScope) {
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { stringify } from './stringify';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns the size of the provided data. Designed for measuring XHR responses.
|
|
10
|
+
*
|
|
11
|
+
* @param {*} data - The data to be measured.
|
|
12
|
+
* @returns {(number|undefined)} - The size of the data or undefined if size cannot be determined.
|
|
13
|
+
*/
|
|
7
14
|
export function dataSize(data) {
|
|
8
15
|
if (typeof data === 'string' && data.length) return data.length;
|
|
9
16
|
if (typeof data !== 'object') return undefined;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { dataSize } from './data-size';
|
|
2
|
+
describe('dataSize', () => {
|
|
3
|
+
test('returns length of string', () => {
|
|
4
|
+
const str = 'Hello, world!';
|
|
5
|
+
expect(dataSize(str)).toBe(str.length);
|
|
6
|
+
});
|
|
7
|
+
test('returns undefined for non-object, number, or empty string', () => {
|
|
8
|
+
expect(dataSize(Infinity)).toBeUndefined();
|
|
9
|
+
expect(dataSize(12345)).toBeUndefined(); // might not actually be by design, but this is how it works today
|
|
10
|
+
expect(dataSize('')).toBeUndefined();
|
|
11
|
+
});
|
|
12
|
+
test('returns byte length of ArrayBuffer object', () => {
|
|
13
|
+
const buffer = new ArrayBuffer(8);
|
|
14
|
+
expect(dataSize(buffer)).toBe(8);
|
|
15
|
+
});
|
|
16
|
+
test('returns size of Blob object', () => {
|
|
17
|
+
const blob = new Blob(['Hello, world!'], {
|
|
18
|
+
type: 'text/plain'
|
|
19
|
+
});
|
|
20
|
+
expect(dataSize(blob)).toBe(blob.size);
|
|
21
|
+
});
|
|
22
|
+
test('returns undefined for FormData object', () => {
|
|
23
|
+
const formData = new FormData();
|
|
24
|
+
expect(dataSize(formData)).toBeUndefined();
|
|
25
|
+
});
|
|
26
|
+
test('returns length of JSON string representation of object', () => {
|
|
27
|
+
const obj = {
|
|
28
|
+
str: 'Hello, world!',
|
|
29
|
+
num: 12345,
|
|
30
|
+
nestedObj: {
|
|
31
|
+
arr: [1, 2, 3]
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const expectedSize = JSON.stringify(obj).length;
|
|
35
|
+
expect(dataSize(obj)).toBe(expectedSize);
|
|
36
|
+
});
|
|
37
|
+
test('returns undefined for object with toJSON method that throws an error', () => {
|
|
38
|
+
const obj = {
|
|
39
|
+
toJSON: () => {
|
|
40
|
+
throw new Error('Error in toJSON');
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
expect(dataSize(obj)).toBeUndefined();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reduce the invocation of the supplied function so that it is only invoked
|
|
3
|
+
* once within a given timeout.
|
|
4
|
+
*
|
|
5
|
+
* If `wait` is `0`, the function will be invoked during the next tick.
|
|
6
|
+
* If `options.leading` is false or not provided, the function will be invoked
|
|
7
|
+
* N milliseconds after the last invocation of the returned function where
|
|
8
|
+
* N is the `timeout` value.
|
|
9
|
+
* If `options.leading` is true, the function will be invoked immediately upon
|
|
10
|
+
* the first invocation of the returned function and not again for N milliseconds
|
|
11
|
+
* where N is the `timeout` value.
|
|
12
|
+
* @param {function} func Function whose invocation should be limited so it is only invoked
|
|
13
|
+
* once within a given timeout period.
|
|
14
|
+
* @param {number} timeout Time in milliseconds that the function should only be invoked
|
|
15
|
+
* once within.
|
|
16
|
+
* @param {object} options Debounce options
|
|
17
|
+
* @param {boolean} options.leading Forces the function to be invoked on the first
|
|
18
|
+
* invocation of the returned function instead of N milliseconds after the last
|
|
19
|
+
* invocation.
|
|
20
|
+
* @returns {function} A wrapping function that will ensure the provided function
|
|
21
|
+
* is invoked only once within the given timeout.
|
|
22
|
+
*/
|
|
23
|
+
export function debounce(func) {
|
|
24
|
+
var _this = this;
|
|
25
|
+
let timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;
|
|
26
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
27
|
+
const leading = options?.leading || false;
|
|
28
|
+
let timer;
|
|
29
|
+
return function () {
|
|
30
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
31
|
+
args[_key] = arguments[_key];
|
|
32
|
+
}
|
|
33
|
+
if (leading && timer === undefined) {
|
|
34
|
+
func.apply(_this, args);
|
|
35
|
+
timer = setTimeout(() => timer = clearTimeout(timer), timeout);
|
|
36
|
+
}
|
|
37
|
+
if (!leading) {
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
timer = setTimeout(() => {
|
|
40
|
+
func.apply(_this, args);
|
|
41
|
+
}, timeout);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Reduce the invocation of the supplied function so that it is only invoked
|
|
48
|
+
* once.
|
|
49
|
+
* @param {function} func Function whose invocation should be limited so it is only invoked
|
|
50
|
+
* once.
|
|
51
|
+
* @returns {function} A wrapping function that will ensure the provided function
|
|
52
|
+
* is invoked only once.
|
|
53
|
+
*/
|
|
54
|
+
export function single(func) {
|
|
55
|
+
var _this2 = this;
|
|
56
|
+
let called = false;
|
|
57
|
+
return function () {
|
|
58
|
+
if (!called) {
|
|
59
|
+
called = true;
|
|
60
|
+
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
61
|
+
args[_key2] = arguments[_key2];
|
|
62
|
+
}
|
|
63
|
+
func.apply(_this2, args);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { debounce, single } from './invoke';
|
|
2
|
+
jest.useFakeTimers();
|
|
3
|
+
describe('debounce', () => {
|
|
4
|
+
test('should run the supplied function after 100ms', () => {
|
|
5
|
+
let mockCallback = jest.fn();
|
|
6
|
+
let debouncedMethod = debounce(mockCallback, 100);
|
|
7
|
+
execFnTimes(debouncedMethod, 100);
|
|
8
|
+
expect(mockCallback).not.toHaveBeenCalled();
|
|
9
|
+
jest.advanceTimersByTime(1000);
|
|
10
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
11
|
+
});
|
|
12
|
+
test('should rerun the supplied function when called again after 100ms', () => {
|
|
13
|
+
let mockCallback = jest.fn();
|
|
14
|
+
let debouncedMethod = debounce(mockCallback, 100);
|
|
15
|
+
execFnTimes(debouncedMethod, 100);
|
|
16
|
+
jest.advanceTimersByTime(200);
|
|
17
|
+
execFnTimes(debouncedMethod, 100);
|
|
18
|
+
jest.advanceTimersByTime(2000);
|
|
19
|
+
expect(mockCallback).toHaveBeenCalledTimes(2);
|
|
20
|
+
});
|
|
21
|
+
test('should run the supplied function on the first event and debounce subsequent events', () => {
|
|
22
|
+
let mockCallback = jest.fn();
|
|
23
|
+
let debouncedMethod = debounce(mockCallback, 100, {
|
|
24
|
+
leading: true
|
|
25
|
+
});
|
|
26
|
+
execFnTimes(debouncedMethod, 100);
|
|
27
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
28
|
+
jest.advanceTimersByTime(200);
|
|
29
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
30
|
+
execFnTimes(debouncedMethod, 100);
|
|
31
|
+
jest.advanceTimersByTime(200);
|
|
32
|
+
expect(mockCallback).toHaveBeenCalledTimes(2);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('single', () => {
|
|
36
|
+
test('should run the supplied function only once', () => {
|
|
37
|
+
let mockCallback = jest.fn();
|
|
38
|
+
let singleMethod = single(mockCallback, 100);
|
|
39
|
+
execFnTimes(singleMethod, 100);
|
|
40
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
function execFnTimes(fn, count) {
|
|
44
|
+
for (let i = 0; i < count; i++) {
|
|
45
|
+
fn();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -7,10 +7,6 @@ var fileProtocolRule = {
|
|
|
7
7
|
replacement: 'file://OBFUSCATED'
|
|
8
8
|
};
|
|
9
9
|
export class Obfuscator extends SharedContext {
|
|
10
|
-
constructor(parent) {
|
|
11
|
-
super(parent); // gets any allowed properties from the parent and stores them in `sharedContext`
|
|
12
|
-
}
|
|
13
|
-
|
|
14
10
|
shouldObfuscate() {
|
|
15
11
|
return getRules(this.sharedContext.agentIdentifier).length > 0;
|
|
16
12
|
}
|
|
@@ -12,7 +12,9 @@ import { documentAddEventListener } from '../event-listener/event-listener-opts'
|
|
|
12
12
|
*/
|
|
13
13
|
export function subscribeToVisibilityChange(cb) {
|
|
14
14
|
let toHiddenOnly = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
15
|
-
|
|
15
|
+
let capture = arguments.length > 2 ? arguments[2] : undefined;
|
|
16
|
+
let abortSignal = arguments.length > 3 ? arguments[3] : undefined;
|
|
17
|
+
documentAddEventListener('visibilitychange', handleVisibilityChange, capture, abortSignal);
|
|
16
18
|
return;
|
|
17
19
|
function handleVisibilityChange() {
|
|
18
20
|
if (toHiddenOnly) {
|
|
@@ -25,7 +25,7 @@ const TIMER_FNS = [SET_TIMEOUT, 'setImmediate', SET_INTERVAL, CLEAR_TIMEOUT, 'cl
|
|
|
25
25
|
* @param {Object} sharedEE - The shared event emitter on which a new scoped event emitter will be based.
|
|
26
26
|
* @returns {Object} Scoped event emitter with a debug ID of `timer`.
|
|
27
27
|
*/
|
|
28
|
-
//eslint-disable-next-line
|
|
28
|
+
// eslint-disable-next-line
|
|
29
29
|
export function wrapTimer(sharedEE) {
|
|
30
30
|
const ee = scopedEE(sharedEE);
|
|
31
31
|
|
|
@@ -9,12 +9,12 @@ import { handle } from '../../../common/event-emitter/handle';
|
|
|
9
9
|
import { getConfigurationValue, getInfo } from '../../../common/config/config';
|
|
10
10
|
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
|
|
11
11
|
import { setDenyList, shouldCollectEvent } from '../../../common/deny-list/deny-list';
|
|
12
|
-
import { AggregateBase } from '../../utils/aggregate-base';
|
|
13
12
|
import { FEATURE_NAME } from '../constants';
|
|
14
13
|
import { drain } from '../../../common/drain/drain';
|
|
15
14
|
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
16
15
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
|
|
17
|
-
|
|
16
|
+
import { FeatureBase } from '../../utils/feature-base';
|
|
17
|
+
export class Aggregate extends FeatureBase {
|
|
18
18
|
static featureName = FEATURE_NAME;
|
|
19
19
|
constructor(agentIdentifier, aggregator) {
|
|
20
20
|
super(agentIdentifier, aggregator, FEATURE_NAME);
|
|
@@ -16,11 +16,11 @@ import { mapOwn } from '../../../common/util/map-own';
|
|
|
16
16
|
import { getInfo, getConfigurationValue, getRuntime } from '../../../common/config/config';
|
|
17
17
|
import { now } from '../../../common/timing/now';
|
|
18
18
|
import { globalScope } from '../../../common/util/global-scope';
|
|
19
|
-
import { AggregateBase } from '../../utils/aggregate-base';
|
|
20
19
|
import { FEATURE_NAME } from '../constants';
|
|
21
20
|
import { drain } from '../../../common/drain/drain';
|
|
22
21
|
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
23
|
-
|
|
22
|
+
import { FeatureBase } from '../../utils/feature-base';
|
|
23
|
+
export class Aggregate extends FeatureBase {
|
|
24
24
|
static featureName = FEATURE_NAME;
|
|
25
25
|
constructor(agentIdentifier, aggregator) {
|
|
26
26
|
var _this;
|
|
@@ -210,6 +210,7 @@ export class Aggregate extends AggregateBase {
|
|
|
210
210
|
|
|
211
211
|
// still send EE events for other features such as above, but stop this one from aggregating internal data
|
|
212
212
|
if (this.blocked) return;
|
|
213
|
+
var att = getInfo(this.agentIdentifier).jsAttributes;
|
|
213
214
|
if (params._interactionId != null) {
|
|
214
215
|
// hold on to the error until the interaction finishes
|
|
215
216
|
this.errorCache[params._interactionId] = this.errorCache[params._interactionId] || [];
|
|
@@ -217,7 +218,6 @@ export class Aggregate extends AggregateBase {
|
|
|
217
218
|
} else {
|
|
218
219
|
// store custom attributes
|
|
219
220
|
var customParams = {};
|
|
220
|
-
var att = getInfo(this.agentIdentifier).jsAttributes;
|
|
221
221
|
mapOwn(att, setCustom);
|
|
222
222
|
if (customAttributes) {
|
|
223
223
|
mapOwn(customAttributes, setCustom);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { getRuntime } from '../../../common/config/config';
|
|
1
|
+
import { getRuntime, getInfo } from '../../../common/config/config';
|
|
2
2
|
import { registerHandler } from '../../../common/event-emitter/register-handler';
|
|
3
3
|
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
|
|
4
|
-
import { AggregateBase } from '../../utils/aggregate-base';
|
|
5
4
|
import { FEATURE_NAME, SUPPORTABILITY_METRIC, CUSTOM_METRIC, SUPPORTABILITY_METRIC_CHANNEL, CUSTOM_METRIC_CHANNEL } from '../constants';
|
|
6
5
|
import { drain } from '../../../common/drain/drain';
|
|
7
6
|
import { getFrameworks } from '../../../common/metrics/framework-detection';
|
|
@@ -11,7 +10,9 @@ import { VERSION } from "../../../common/constants/env.npm";
|
|
|
11
10
|
import { onDOMContentLoaded } from '../../../common/window/load';
|
|
12
11
|
import { windowAddEventListener } from '../../../common/event-listener/event-listener-opts';
|
|
13
12
|
import { isBrowserScope } from '../../../common/util/global-scope';
|
|
14
|
-
|
|
13
|
+
import { FeatureBase } from '../../utils/feature-base';
|
|
14
|
+
import { stringify } from '../../../common/util/stringify';
|
|
15
|
+
export class Aggregate extends FeatureBase {
|
|
15
16
|
static featureName = FEATURE_NAME;
|
|
16
17
|
constructor(agentIdentifier, aggregator) {
|
|
17
18
|
super(agentIdentifier, aggregator, FEATURE_NAME);
|
|
@@ -103,6 +104,7 @@ export class Aggregate extends AggregateBase {
|
|
|
103
104
|
try {
|
|
104
105
|
if (this.resourcesSent) return;
|
|
105
106
|
const agentRuntime = getRuntime(this.agentIdentifier);
|
|
107
|
+
const info = getInfo(this.agentIdentifier);
|
|
106
108
|
// make sure this only gets sent once
|
|
107
109
|
this.resourcesSent = true;
|
|
108
110
|
// differentiate between internal+external and ajax+non-ajax
|
|
@@ -128,10 +130,19 @@ export class Aggregate extends AggregateBase {
|
|
|
128
130
|
this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(endpoint.charAt(0).toUpperCase() + endpoint.slice(1), "/BytesSent"), agentRuntime.bytesSent[endpoint]);
|
|
129
131
|
});
|
|
130
132
|
|
|
133
|
+
// Capture per-agent query bytes sent for each endpoint (see harvest) and RUM call (see page_view_event aggregator).
|
|
134
|
+
Object.keys(agentRuntime.bytesSent).forEach(endpoint => {
|
|
135
|
+
this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(endpoint.charAt(0).toUpperCase() + endpoint.slice(1), "/QueryBytesSent"), agentRuntime.queryBytesSent[endpoint]);
|
|
136
|
+
});
|
|
137
|
+
|
|
131
138
|
// Capture metrics for session trace if active (`ptid` is set when returned by replay ingest).
|
|
132
139
|
if (agentRuntime.ptid) {
|
|
133
140
|
this.storeSupportabilityMetrics('PageSession/Feature/SessionTrace/DurationMs', Math.round(performance.now()));
|
|
134
141
|
}
|
|
142
|
+
|
|
143
|
+
// Capture metrics for size of custom attributes
|
|
144
|
+
const jsAttributes = stringify(info.jsAttributes);
|
|
145
|
+
this.storeSupportabilityMetrics('PageSession/Feature/CustomData/Bytes', jsAttributes === '{}' ? 0 : jsAttributes.length);
|
|
135
146
|
} catch (e) {
|
|
136
147
|
// do nothing
|
|
137
148
|
}
|
|
@@ -9,11 +9,11 @@ import { registerHandler as register } from '../../../common/event-emitter/regis
|
|
|
9
9
|
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
|
|
10
10
|
import { cleanURL } from '../../../common/url/clean-url';
|
|
11
11
|
import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config';
|
|
12
|
-
import { AggregateBase } from '../../utils/aggregate-base';
|
|
13
12
|
import { FEATURE_NAME } from '../constants';
|
|
14
13
|
import { drain } from '../../../common/drain/drain';
|
|
15
14
|
import { isBrowserScope } from '../../../common/util/global-scope';
|
|
16
|
-
|
|
15
|
+
import { FeatureBase } from '../../utils/feature-base';
|
|
16
|
+
export class Aggregate extends FeatureBase {
|
|
17
17
|
static featureName = FEATURE_NAME;
|
|
18
18
|
constructor(agentIdentifier, aggregator) {
|
|
19
19
|
var _this;
|