@tracelog/lib 0.0.8 → 0.2.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 +58 -24
- package/dist/browser/tracelog.js +1934 -3226
- package/dist/cjs/api.d.ts +33 -19
- package/dist/cjs/api.js +111 -156
- package/dist/cjs/app.constants.d.ts +80 -1
- package/dist/cjs/app.constants.js +90 -3
- package/dist/cjs/app.d.ts +29 -44
- package/dist/cjs/app.js +114 -212
- package/dist/cjs/app.types.d.ts +2 -7
- package/dist/cjs/app.types.js +10 -21
- package/dist/cjs/constants/api.constants.js +11 -5
- package/dist/cjs/constants/config.constants.d.ts +75 -0
- package/dist/cjs/constants/config.constants.js +178 -0
- package/dist/cjs/constants/error.constants.d.ts +29 -0
- package/dist/cjs/constants/error.constants.js +50 -0
- package/dist/cjs/constants/index.d.ts +3 -6
- package/dist/cjs/constants/index.js +3 -6
- package/dist/cjs/constants/performance.constants.d.ts +28 -0
- package/dist/cjs/constants/performance.constants.js +43 -0
- package/dist/cjs/handlers/click.handler.d.ts +1 -0
- package/dist/cjs/handlers/click.handler.js +30 -49
- package/dist/cjs/handlers/error.handler.d.ts +11 -6
- package/dist/cjs/handlers/error.handler.js +91 -51
- package/dist/cjs/handlers/page-view.handler.js +38 -29
- package/dist/cjs/handlers/performance.handler.d.ts +3 -0
- package/dist/cjs/handlers/performance.handler.js +76 -37
- package/dist/cjs/handlers/scroll.handler.d.ts +15 -0
- package/dist/cjs/handlers/scroll.handler.js +105 -31
- package/dist/cjs/handlers/session.handler.d.ts +6 -20
- package/dist/cjs/handlers/session.handler.js +38 -326
- package/dist/cjs/integrations/google-analytics.integration.d.ts +0 -1
- package/dist/cjs/integrations/google-analytics.integration.js +27 -98
- package/dist/cjs/listeners/input-listener-managers.d.ts +18 -9
- package/dist/cjs/listeners/input-listener-managers.js +24 -33
- package/dist/cjs/listeners/touch-listener-manager.d.ts +1 -3
- package/dist/cjs/listeners/touch-listener-manager.js +1 -23
- package/dist/cjs/listeners/visibility-listener-manager.d.ts +1 -4
- package/dist/cjs/listeners/visibility-listener-manager.js +6 -42
- package/dist/cjs/managers/api.manager.d.ts +13 -3
- package/dist/cjs/managers/api.manager.js +35 -5
- package/dist/cjs/managers/config.manager.d.ts +53 -3
- package/dist/cjs/managers/config.manager.js +131 -62
- package/dist/cjs/managers/event.manager.d.ts +57 -36
- package/dist/cjs/managers/event.manager.js +266 -417
- package/dist/cjs/managers/sender.manager.d.ts +40 -22
- package/dist/cjs/managers/sender.manager.js +200 -198
- package/dist/cjs/managers/session.manager.d.ts +80 -66
- package/dist/cjs/managers/session.manager.js +267 -522
- package/dist/cjs/managers/state.manager.d.ts +33 -0
- package/dist/cjs/managers/state.manager.js +79 -6
- package/dist/cjs/managers/storage.manager.d.ts +26 -2
- package/dist/cjs/managers/storage.manager.js +67 -34
- package/dist/cjs/managers/tags.manager.d.ts +31 -7
- package/dist/cjs/managers/tags.manager.js +123 -241
- package/dist/cjs/managers/user.manager.d.ts +14 -5
- package/dist/cjs/managers/user.manager.js +17 -9
- package/dist/cjs/public-api.d.ts +10 -1
- package/dist/cjs/public-api.js +18 -24
- package/dist/cjs/test-bridge.d.ts +48 -0
- package/dist/cjs/test-bridge.js +110 -0
- package/dist/cjs/types/api.types.d.ts +21 -6
- package/dist/cjs/types/api.types.js +21 -6
- package/dist/cjs/types/config.types.d.ts +22 -84
- package/dist/cjs/types/emitter.types.d.ts +11 -0
- package/dist/cjs/types/emitter.types.js +8 -0
- package/dist/cjs/types/event.types.d.ts +8 -11
- package/dist/cjs/types/index.d.ts +3 -1
- package/dist/cjs/types/index.js +3 -1
- package/dist/cjs/types/queue.types.d.ts +1 -0
- package/dist/cjs/types/session.types.d.ts +0 -64
- package/dist/cjs/types/state.types.d.ts +1 -0
- package/dist/cjs/types/test-bridge.types.d.ts +38 -0
- package/dist/cjs/types/validation-error.types.d.ts +7 -0
- package/dist/cjs/types/validation-error.types.js +11 -1
- package/dist/cjs/types/window.types.d.ts +1 -8
- package/dist/cjs/utils/data/uuid.utils.d.ts +1 -1
- package/dist/cjs/utils/data/uuid.utils.js +7 -5
- package/dist/cjs/utils/emitter.utils.d.ts +8 -0
- package/dist/cjs/utils/emitter.utils.js +33 -0
- package/dist/cjs/utils/index.d.ts +1 -0
- package/dist/cjs/utils/index.js +1 -0
- package/dist/cjs/utils/logging/debug-logger.utils.d.ts +10 -51
- package/dist/cjs/utils/logging/debug-logger.utils.js +36 -127
- package/dist/cjs/utils/network/fetch-with-timeout.utils.d.ts +4 -0
- package/dist/cjs/utils/network/fetch-with-timeout.utils.js +25 -0
- package/dist/cjs/utils/network/index.d.ts +1 -0
- package/dist/cjs/utils/network/index.js +1 -0
- package/dist/cjs/utils/network/url.utils.js +2 -42
- package/dist/cjs/utils/security/sanitize.utils.d.ts +1 -8
- package/dist/cjs/utils/security/sanitize.utils.js +7 -41
- package/dist/cjs/utils/validations/config-validations.utils.d.ts +7 -0
- package/dist/cjs/utils/validations/config-validations.utils.js +77 -22
- package/dist/esm/api.d.ts +33 -19
- package/dist/esm/api.js +105 -118
- package/dist/esm/app.constants.d.ts +80 -1
- package/dist/esm/app.constants.js +89 -1
- package/dist/esm/app.d.ts +29 -44
- package/dist/esm/app.js +115 -213
- package/dist/esm/app.types.d.ts +2 -7
- package/dist/esm/app.types.js +1 -7
- package/dist/esm/constants/api.constants.js +10 -4
- package/dist/esm/constants/config.constants.d.ts +75 -0
- package/dist/esm/constants/config.constants.js +174 -0
- package/dist/esm/constants/error.constants.d.ts +29 -0
- package/dist/esm/constants/error.constants.js +47 -0
- package/dist/esm/constants/index.d.ts +3 -6
- package/dist/esm/constants/index.js +3 -6
- package/dist/esm/constants/performance.constants.d.ts +28 -0
- package/dist/esm/constants/performance.constants.js +40 -0
- package/dist/esm/handlers/click.handler.d.ts +1 -0
- package/dist/esm/handlers/click.handler.js +30 -49
- package/dist/esm/handlers/error.handler.d.ts +11 -6
- package/dist/esm/handlers/error.handler.js +91 -51
- package/dist/esm/handlers/page-view.handler.js +38 -29
- package/dist/esm/handlers/performance.handler.d.ts +3 -0
- package/dist/esm/handlers/performance.handler.js +71 -32
- package/dist/esm/handlers/scroll.handler.d.ts +15 -0
- package/dist/esm/handlers/scroll.handler.js +106 -32
- package/dist/esm/handlers/session.handler.d.ts +6 -20
- package/dist/esm/handlers/session.handler.js +38 -326
- package/dist/esm/integrations/google-analytics.integration.d.ts +0 -1
- package/dist/esm/integrations/google-analytics.integration.js +27 -98
- package/dist/esm/listeners/input-listener-managers.d.ts +18 -9
- package/dist/esm/listeners/input-listener-managers.js +23 -32
- package/dist/esm/listeners/touch-listener-manager.d.ts +1 -3
- package/dist/esm/listeners/touch-listener-manager.js +1 -23
- package/dist/esm/listeners/visibility-listener-manager.d.ts +1 -4
- package/dist/esm/listeners/visibility-listener-manager.js +6 -42
- package/dist/esm/managers/api.manager.d.ts +13 -3
- package/dist/esm/managers/api.manager.js +34 -3
- package/dist/esm/managers/config.manager.d.ts +53 -3
- package/dist/esm/managers/config.manager.js +133 -64
- package/dist/esm/managers/event.manager.d.ts +57 -36
- package/dist/esm/managers/event.manager.js +268 -419
- package/dist/esm/managers/sender.manager.d.ts +40 -22
- package/dist/esm/managers/sender.manager.js +201 -199
- package/dist/esm/managers/session.manager.d.ts +80 -66
- package/dist/esm/managers/session.manager.js +269 -524
- package/dist/esm/managers/state.manager.d.ts +33 -0
- package/dist/esm/managers/state.manager.js +78 -6
- package/dist/esm/managers/storage.manager.d.ts +26 -2
- package/dist/esm/managers/storage.manager.js +66 -33
- package/dist/esm/managers/tags.manager.d.ts +31 -7
- package/dist/esm/managers/tags.manager.js +124 -242
- package/dist/esm/managers/user.manager.d.ts +14 -5
- package/dist/esm/managers/user.manager.js +17 -9
- package/dist/esm/public-api.d.ts +10 -1
- package/dist/esm/public-api.js +14 -1
- package/dist/esm/test-bridge.d.ts +48 -0
- package/dist/esm/test-bridge.js +106 -0
- package/dist/esm/types/api.types.d.ts +21 -6
- package/dist/esm/types/api.types.js +21 -6
- package/dist/esm/types/config.types.d.ts +22 -84
- package/dist/esm/types/emitter.types.d.ts +11 -0
- package/dist/esm/types/emitter.types.js +5 -0
- package/dist/esm/types/event.types.d.ts +8 -11
- package/dist/esm/types/index.d.ts +3 -1
- package/dist/esm/types/index.js +3 -1
- package/dist/esm/types/queue.types.d.ts +1 -0
- package/dist/esm/types/session.types.d.ts +0 -64
- package/dist/esm/types/state.types.d.ts +1 -0
- package/dist/esm/types/test-bridge.types.d.ts +38 -0
- package/dist/esm/types/validation-error.types.d.ts +7 -0
- package/dist/esm/types/validation-error.types.js +9 -0
- package/dist/esm/types/window.types.d.ts +1 -8
- package/dist/esm/utils/data/uuid.utils.d.ts +1 -1
- package/dist/esm/utils/data/uuid.utils.js +7 -5
- package/dist/esm/utils/emitter.utils.d.ts +8 -0
- package/dist/esm/utils/emitter.utils.js +29 -0
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.js +1 -0
- package/dist/esm/utils/logging/debug-logger.utils.d.ts +10 -51
- package/dist/esm/utils/logging/debug-logger.utils.js +36 -127
- package/dist/esm/utils/network/fetch-with-timeout.utils.d.ts +4 -0
- package/dist/esm/utils/network/fetch-with-timeout.utils.js +22 -0
- package/dist/esm/utils/network/index.d.ts +1 -0
- package/dist/esm/utils/network/index.js +1 -0
- package/dist/esm/utils/network/url.utils.js +2 -42
- package/dist/esm/utils/security/sanitize.utils.d.ts +1 -8
- package/dist/esm/utils/security/sanitize.utils.js +6 -39
- package/dist/esm/utils/validations/config-validations.utils.d.ts +7 -0
- package/dist/esm/utils/validations/config-validations.utils.js +76 -22
- package/package.json +23 -16
- package/dist/browser/web-vitals-CCnqwnC8.mjs +0 -198
- package/dist/cjs/constants/browser.constants.d.ts +0 -3
- package/dist/cjs/constants/browser.constants.js +0 -41
- package/dist/cjs/constants/initialization.constants.d.ts +0 -40
- package/dist/cjs/constants/initialization.constants.js +0 -48
- package/dist/cjs/constants/limits.constants.d.ts +0 -25
- package/dist/cjs/constants/limits.constants.js +0 -40
- package/dist/cjs/constants/security.constants.d.ts +0 -1
- package/dist/cjs/constants/security.constants.js +0 -12
- package/dist/cjs/constants/timing.constants.d.ts +0 -22
- package/dist/cjs/constants/timing.constants.js +0 -34
- package/dist/cjs/constants/validation.constants.d.ts +0 -13
- package/dist/cjs/constants/validation.constants.js +0 -31
- package/dist/cjs/handlers/network.handler.d.ts +0 -16
- package/dist/cjs/handlers/network.handler.js +0 -136
- package/dist/cjs/managers/cross-tab-session.manager.d.ts +0 -170
- package/dist/cjs/managers/cross-tab-session.manager.js +0 -730
- package/dist/cjs/managers/sampling.manager.d.ts +0 -8
- package/dist/cjs/managers/sampling.manager.js +0 -53
- package/dist/cjs/managers/session-recovery.manager.d.ts +0 -65
- package/dist/cjs/managers/session-recovery.manager.js +0 -237
- package/dist/cjs/types/web-vitals.types.d.ts +0 -6
- package/dist/esm/constants/browser.constants.d.ts +0 -3
- package/dist/esm/constants/browser.constants.js +0 -38
- package/dist/esm/constants/initialization.constants.d.ts +0 -40
- package/dist/esm/constants/initialization.constants.js +0 -45
- package/dist/esm/constants/limits.constants.d.ts +0 -25
- package/dist/esm/constants/limits.constants.js +0 -37
- package/dist/esm/constants/security.constants.d.ts +0 -1
- package/dist/esm/constants/security.constants.js +0 -9
- package/dist/esm/constants/timing.constants.d.ts +0 -22
- package/dist/esm/constants/timing.constants.js +0 -31
- package/dist/esm/constants/validation.constants.d.ts +0 -13
- package/dist/esm/constants/validation.constants.js +0 -28
- package/dist/esm/handlers/network.handler.d.ts +0 -16
- package/dist/esm/handlers/network.handler.js +0 -132
- package/dist/esm/managers/cross-tab-session.manager.d.ts +0 -170
- package/dist/esm/managers/cross-tab-session.manager.js +0 -726
- package/dist/esm/managers/sampling.manager.d.ts +0 -8
- package/dist/esm/managers/sampling.manager.js +0 -49
- package/dist/esm/managers/session-recovery.manager.d.ts +0 -65
- package/dist/esm/managers/session-recovery.manager.js +0 -233
- package/dist/esm/types/web-vitals.types.d.ts +0 -6
- /package/dist/cjs/types/{web-vitals.types.js → test-bridge.types.js} +0 -0
- /package/dist/esm/types/{web-vitals.types.js → test-bridge.types.js} +0 -0
|
@@ -9,12 +9,18 @@ class ScrollHandler extends state_manager_1.StateManager {
|
|
|
9
9
|
constructor(eventManager) {
|
|
10
10
|
super();
|
|
11
11
|
this.containers = [];
|
|
12
|
+
this.limitWarningLogged = false;
|
|
13
|
+
this.minDepthChange = constants_1.MIN_SCROLL_DEPTH_CHANGE;
|
|
14
|
+
this.minIntervalMs = constants_1.SCROLL_MIN_EVENT_INTERVAL_MS;
|
|
15
|
+
this.maxEventsPerSession = constants_1.MAX_SCROLL_EVENTS_PER_SESSION;
|
|
12
16
|
this.eventManager = eventManager;
|
|
13
17
|
}
|
|
14
18
|
startTracking() {
|
|
19
|
+
this.limitWarningLogged = false;
|
|
20
|
+
this.applyConfigOverrides();
|
|
21
|
+
this.set('scrollEventCount', 0);
|
|
15
22
|
const raw = this.get('config').scrollContainerSelectors;
|
|
16
23
|
const selectors = Array.isArray(raw) ? raw : typeof raw === 'string' ? [raw] : [];
|
|
17
|
-
logging_1.debugLog.debug('ScrollHandler', 'Starting scroll tracking', { selectorsCount: selectors.length });
|
|
18
24
|
const elements = selectors
|
|
19
25
|
.map((sel) => this.safeQuerySelector(sel))
|
|
20
26
|
.filter((element) => element instanceof HTMLElement);
|
|
@@ -26,11 +32,8 @@ class ScrollHandler extends state_manager_1.StateManager {
|
|
|
26
32
|
}
|
|
27
33
|
}
|
|
28
34
|
stopTracking() {
|
|
29
|
-
logging_1.debugLog.debug('ScrollHandler', 'Stopping scroll tracking', { containersCount: this.containers.length });
|
|
30
35
|
for (const container of this.containers) {
|
|
31
|
-
|
|
32
|
-
clearTimeout(container.debounceTimer);
|
|
33
|
-
}
|
|
36
|
+
this.clearContainerTimer(container);
|
|
34
37
|
if (container.element instanceof Window) {
|
|
35
38
|
window.removeEventListener('scroll', container.listener);
|
|
36
39
|
}
|
|
@@ -39,38 +42,38 @@ class ScrollHandler extends state_manager_1.StateManager {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
this.containers.length = 0;
|
|
45
|
+
this.set('scrollEventCount', 0);
|
|
46
|
+
this.limitWarningLogged = false;
|
|
42
47
|
}
|
|
43
48
|
setupScrollContainer(element) {
|
|
44
49
|
// Skip setup for non-scrollable elements
|
|
45
50
|
if (element !== window && !this.isElementScrollable(element)) {
|
|
46
51
|
return;
|
|
47
52
|
}
|
|
48
|
-
const container = {
|
|
49
|
-
element,
|
|
50
|
-
lastScrollPos: this.getScrollTop(element),
|
|
51
|
-
debounceTimer: null,
|
|
52
|
-
listener: () => { },
|
|
53
|
-
};
|
|
54
53
|
const handleScroll = () => {
|
|
55
54
|
if (this.get('suppressNextScroll')) {
|
|
56
|
-
this.set('suppressNextScroll', false);
|
|
57
55
|
return;
|
|
58
56
|
}
|
|
59
|
-
|
|
60
|
-
clearTimeout(container.debounceTimer);
|
|
61
|
-
}
|
|
57
|
+
this.clearContainerTimer(container);
|
|
62
58
|
container.debounceTimer = window.setTimeout(() => {
|
|
63
59
|
const scrollData = this.calculateScrollData(container);
|
|
64
60
|
if (scrollData) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
scroll_data: scrollData,
|
|
68
|
-
});
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
this.processScrollEvent(container, scrollData, now);
|
|
69
63
|
}
|
|
70
64
|
container.debounceTimer = null;
|
|
71
65
|
}, constants_1.SCROLL_DEBOUNCE_TIME_MS);
|
|
72
66
|
};
|
|
73
|
-
|
|
67
|
+
const initialScrollTop = this.getScrollTop(element);
|
|
68
|
+
const container = {
|
|
69
|
+
element,
|
|
70
|
+
lastScrollPos: initialScrollTop,
|
|
71
|
+
lastDepth: this.calculateScrollDepth(initialScrollTop, this.getScrollHeight(element), this.getViewportHeight(element)),
|
|
72
|
+
lastDirection: types_1.ScrollDirection.DOWN,
|
|
73
|
+
lastEventTime: 0,
|
|
74
|
+
debounceTimer: null,
|
|
75
|
+
listener: handleScroll,
|
|
76
|
+
};
|
|
74
77
|
this.containers.push(container);
|
|
75
78
|
if (element instanceof Window) {
|
|
76
79
|
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
@@ -79,24 +82,95 @@ class ScrollHandler extends state_manager_1.StateManager {
|
|
|
79
82
|
element.addEventListener('scroll', handleScroll, { passive: true });
|
|
80
83
|
}
|
|
81
84
|
}
|
|
85
|
+
processScrollEvent(container, scrollData, timestamp) {
|
|
86
|
+
if (!this.shouldEmitScrollEvent(container, scrollData, timestamp)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
container.lastEventTime = timestamp;
|
|
90
|
+
container.lastDepth = scrollData.depth;
|
|
91
|
+
container.lastDirection = scrollData.direction;
|
|
92
|
+
const currentCount = this.get('scrollEventCount') ?? 0;
|
|
93
|
+
this.set('scrollEventCount', currentCount + 1);
|
|
94
|
+
this.eventManager.track({
|
|
95
|
+
type: types_1.EventType.SCROLL,
|
|
96
|
+
scroll_data: scrollData,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
shouldEmitScrollEvent(container, scrollData, timestamp) {
|
|
100
|
+
if (this.hasReachedSessionLimit()) {
|
|
101
|
+
this.logLimitOnce();
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (!this.hasElapsedMinimumInterval(container, timestamp)) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
if (!this.hasSignificantDepthChange(container, scrollData.depth)) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
hasReachedSessionLimit() {
|
|
113
|
+
const currentCount = this.get('scrollEventCount') ?? 0;
|
|
114
|
+
return currentCount >= this.maxEventsPerSession;
|
|
115
|
+
}
|
|
116
|
+
hasElapsedMinimumInterval(container, timestamp) {
|
|
117
|
+
if (container.lastEventTime === 0) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
return timestamp - container.lastEventTime >= this.minIntervalMs;
|
|
121
|
+
}
|
|
122
|
+
hasSignificantDepthChange(container, newDepth) {
|
|
123
|
+
return Math.abs(newDepth - container.lastDepth) >= this.minDepthChange;
|
|
124
|
+
}
|
|
125
|
+
logLimitOnce() {
|
|
126
|
+
if (this.limitWarningLogged) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.limitWarningLogged = true;
|
|
130
|
+
logging_1.debugLog.warn('ScrollHandler', 'Max scroll events per session reached', {
|
|
131
|
+
limit: this.maxEventsPerSession,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
applyConfigOverrides() {
|
|
135
|
+
this.minDepthChange = constants_1.MIN_SCROLL_DEPTH_CHANGE;
|
|
136
|
+
this.minIntervalMs = constants_1.SCROLL_MIN_EVENT_INTERVAL_MS;
|
|
137
|
+
this.maxEventsPerSession = constants_1.MAX_SCROLL_EVENTS_PER_SESSION;
|
|
138
|
+
}
|
|
139
|
+
isWindowScrollable() {
|
|
140
|
+
return document.documentElement.scrollHeight > window.innerHeight;
|
|
141
|
+
}
|
|
142
|
+
clearContainerTimer(container) {
|
|
143
|
+
if (container.debounceTimer !== null) {
|
|
144
|
+
clearTimeout(container.debounceTimer);
|
|
145
|
+
container.debounceTimer = null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
getScrollDirection(current, previous) {
|
|
149
|
+
return current > previous ? types_1.ScrollDirection.DOWN : types_1.ScrollDirection.UP;
|
|
150
|
+
}
|
|
151
|
+
calculateScrollDepth(scrollTop, scrollHeight, viewportHeight) {
|
|
152
|
+
if (scrollHeight <= viewportHeight) {
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
const maxScrollTop = scrollHeight - viewportHeight;
|
|
156
|
+
return Math.min(100, Math.max(0, Math.floor((scrollTop / maxScrollTop) * 100)));
|
|
157
|
+
}
|
|
82
158
|
calculateScrollData(container) {
|
|
83
159
|
const { element, lastScrollPos } = container;
|
|
84
160
|
const scrollTop = this.getScrollTop(element);
|
|
85
|
-
|
|
86
|
-
const scrollHeight = this.getScrollHeight(element);
|
|
87
|
-
// Check if the page is actually scrollable at runtime
|
|
88
|
-
if (element === window && scrollHeight <= viewportHeight) {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
const direction = scrollTop > lastScrollPos ? types_1.ScrollDirection.DOWN : types_1.ScrollDirection.UP;
|
|
92
|
-
const depth = scrollHeight > viewportHeight
|
|
93
|
-
? Math.min(100, Math.max(0, Math.floor((scrollTop / (scrollHeight - viewportHeight)) * 100)))
|
|
94
|
-
: 0;
|
|
95
|
-
// Only update if scroll position changed significantly
|
|
161
|
+
// Early return: check significant movement first (cheapest check)
|
|
96
162
|
const positionDelta = Math.abs(scrollTop - lastScrollPos);
|
|
97
163
|
if (positionDelta < constants_1.SIGNIFICANT_SCROLL_DELTA) {
|
|
98
164
|
return null;
|
|
99
165
|
}
|
|
166
|
+
// Early return: check if window is scrollable
|
|
167
|
+
if (element === window && !this.isWindowScrollable()) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
const viewportHeight = this.getViewportHeight(element);
|
|
171
|
+
const scrollHeight = this.getScrollHeight(element);
|
|
172
|
+
const direction = this.getScrollDirection(scrollTop, lastScrollPos);
|
|
173
|
+
const depth = this.calculateScrollDepth(scrollTop, scrollHeight, viewportHeight);
|
|
100
174
|
container.lastScrollPos = scrollTop;
|
|
101
175
|
return { depth, direction };
|
|
102
176
|
}
|
|
@@ -4,26 +4,12 @@ import { StorageManager } from '../managers/storage.manager';
|
|
|
4
4
|
export declare class SessionHandler extends StateManager {
|
|
5
5
|
private readonly eventManager;
|
|
6
6
|
private readonly storageManager;
|
|
7
|
-
private readonly sessionStorageKey;
|
|
8
7
|
private sessionManager;
|
|
9
|
-
private
|
|
10
|
-
private _crossTabSessionManager;
|
|
11
|
-
private heartbeatInterval;
|
|
12
|
-
private _isInitializingCrossTab;
|
|
13
|
-
private get crossTabSessionManager();
|
|
14
|
-
private shouldUseCrossTabs;
|
|
8
|
+
private destroyed;
|
|
15
9
|
constructor(storageManager: StorageManager, eventManager: EventManager);
|
|
16
|
-
startTracking(): void
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
private forceCleanupSession;
|
|
22
|
-
private trackSession;
|
|
23
|
-
private startInitialSession;
|
|
24
|
-
private checkOrphanedSessions;
|
|
25
|
-
private persistSession;
|
|
26
|
-
private clearPersistedSession;
|
|
27
|
-
private startHeartbeat;
|
|
28
|
-
private stopHeartbeat;
|
|
10
|
+
startTracking(): Promise<void>;
|
|
11
|
+
private isActive;
|
|
12
|
+
private cleanupSessionManager;
|
|
13
|
+
stopTracking(): Promise<void>;
|
|
14
|
+
destroy(): void;
|
|
29
15
|
}
|
|
@@ -1,357 +1,69 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SessionHandler = void 0;
|
|
4
|
-
const constants_1 = require("../constants");
|
|
5
|
-
const types_1 = require("../types");
|
|
6
4
|
const session_manager_1 = require("../managers/session.manager");
|
|
7
|
-
const session_recovery_manager_1 = require("../managers/session-recovery.manager");
|
|
8
|
-
const cross_tab_session_manager_1 = require("../managers/cross-tab-session.manager");
|
|
9
5
|
const state_manager_1 = require("../managers/state.manager");
|
|
10
6
|
const logging_1 = require("../utils/logging");
|
|
11
7
|
class SessionHandler extends state_manager_1.StateManager {
|
|
12
|
-
get crossTabSessionManager() {
|
|
13
|
-
if (!this._crossTabSessionManager && !this._isInitializingCrossTab && this.shouldUseCrossTabs()) {
|
|
14
|
-
this._isInitializingCrossTab = true;
|
|
15
|
-
try {
|
|
16
|
-
const projectId = this.get('config')?.id;
|
|
17
|
-
if (projectId) {
|
|
18
|
-
this.initializeCrossTabSessionManager(projectId);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
logging_1.debugLog.error('SessionHandler', 'Failed to initialize cross-tab session manager', {
|
|
23
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
finally {
|
|
27
|
-
this._isInitializingCrossTab = false;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return this._crossTabSessionManager;
|
|
31
|
-
}
|
|
32
|
-
shouldUseCrossTabs() {
|
|
33
|
-
// Only initialize if BroadcastChannel is supported (indicates potential for multiple tabs)
|
|
34
|
-
// and ServiceWorker is available (better cross-tab coordination)
|
|
35
|
-
return typeof BroadcastChannel !== 'undefined' && typeof navigator !== 'undefined' && 'serviceWorker' in navigator;
|
|
36
|
-
}
|
|
37
8
|
constructor(storageManager, eventManager) {
|
|
38
9
|
super();
|
|
39
10
|
this.sessionManager = null;
|
|
40
|
-
this.
|
|
41
|
-
this._crossTabSessionManager = null;
|
|
42
|
-
this.heartbeatInterval = null;
|
|
43
|
-
this._isInitializingCrossTab = false;
|
|
11
|
+
this.destroyed = false;
|
|
44
12
|
this.eventManager = eventManager;
|
|
45
13
|
this.storageManager = storageManager;
|
|
46
|
-
this.sessionStorageKey = (0, constants_1.SESSION_STORAGE_KEY)(this.get('config')?.id);
|
|
47
|
-
const projectId = this.get('config')?.id;
|
|
48
|
-
if (projectId) {
|
|
49
|
-
this.initializeSessionRecoveryManager(projectId);
|
|
50
|
-
// CrossTabSessionManager will be initialized lazily when needed via the getter
|
|
51
|
-
}
|
|
52
14
|
}
|
|
53
|
-
startTracking() {
|
|
54
|
-
if (this.
|
|
55
|
-
logging_1.debugLog.debug('SessionHandler', 'Session tracking already active');
|
|
15
|
+
async startTracking() {
|
|
16
|
+
if (this.isActive()) {
|
|
56
17
|
return;
|
|
57
18
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.set('sessionId', sessionResult.sessionId);
|
|
70
|
-
logging_1.debugLog.info('SessionHandler', '🏁 Session started', {
|
|
71
|
-
sessionId: sessionResult.sessionId,
|
|
72
|
-
recovered: sessionResult.recovered,
|
|
73
|
-
crossTabActive: !!this.crossTabSessionManager,
|
|
74
|
-
});
|
|
75
|
-
this.trackSession(types_1.EventType.SESSION_START, sessionResult.recovered);
|
|
76
|
-
this.persistSession(sessionResult.sessionId);
|
|
77
|
-
this.startHeartbeat();
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
logging_1.debugLog.error('SessionHandler', `Session creation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
81
|
-
this.forceCleanupSession();
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
const onInactivity = () => {
|
|
85
|
-
if (!this.get('sessionId')) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
if (this.crossTabSessionManager && this.crossTabSessionManager.getEffectiveSessionTimeout() > 0) {
|
|
89
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
90
|
-
logging_1.debugLog.debug('SessionHandler', 'Session kept alive by cross-tab activity');
|
|
91
|
-
}
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
this.sessionManager.endSessionManaged('inactivity')
|
|
95
|
-
.then((result) => {
|
|
96
|
-
logging_1.debugLog.info('SessionHandler', '🛑 Session ended by inactivity', {
|
|
97
|
-
sessionId: this.get('sessionId'),
|
|
98
|
-
reason: result.reason,
|
|
99
|
-
success: result.success,
|
|
100
|
-
eventsFlushed: result.eventsFlushed,
|
|
101
|
-
});
|
|
102
|
-
if (this.crossTabSessionManager) {
|
|
103
|
-
this.crossTabSessionManager.endSession('inactivity');
|
|
104
|
-
}
|
|
105
|
-
this.clearPersistedSession();
|
|
106
|
-
this.stopHeartbeat();
|
|
107
|
-
})
|
|
108
|
-
.catch((error) => {
|
|
109
|
-
logging_1.debugLog.error('SessionHandler', `Session end failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
110
|
-
this.forceCleanupSession();
|
|
111
|
-
});
|
|
112
|
-
};
|
|
113
|
-
const sessionEndConfig = {
|
|
114
|
-
enablePageUnloadHandlers: true,
|
|
115
|
-
debugMode: (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') ?? false,
|
|
116
|
-
syncTimeoutMs: constants_1.SESSION_SYNC_CONSTANTS.SYNC_TIMEOUT_MS,
|
|
117
|
-
maxRetries: constants_1.SESSION_SYNC_CONSTANTS.MAX_RETRY_ATTEMPTS,
|
|
118
|
-
};
|
|
119
|
-
this.sessionManager = new session_manager_1.SessionManager(onActivity, onInactivity, this.eventManager, this.storageManager, sessionEndConfig);
|
|
120
|
-
logging_1.debugLog.debug('SessionHandler', 'Session manager initialized');
|
|
121
|
-
this.startInitialSession();
|
|
122
|
-
}
|
|
123
|
-
stopTracking() {
|
|
124
|
-
logging_1.debugLog.info('SessionHandler', 'Stopping session tracking');
|
|
125
|
-
if (this.sessionManager) {
|
|
126
|
-
if (this.get('sessionId')) {
|
|
19
|
+
if (this.destroyed) {
|
|
20
|
+
logging_1.debugLog.warn('SessionHandler', 'Cannot start tracking on destroyed handler');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
this.sessionManager = new session_manager_1.SessionManager(this.storageManager, this.eventManager);
|
|
25
|
+
await this.sessionManager.startTracking();
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
// Cleanup on failure
|
|
29
|
+
if (this.sessionManager) {
|
|
127
30
|
try {
|
|
128
|
-
this.sessionManager.
|
|
129
|
-
this.clearPersistedSession();
|
|
130
|
-
this.stopHeartbeat();
|
|
31
|
+
this.sessionManager.destroy();
|
|
131
32
|
}
|
|
132
|
-
catch
|
|
133
|
-
|
|
134
|
-
this.forceCleanupSession();
|
|
33
|
+
catch {
|
|
34
|
+
// Ignore cleanup errors
|
|
135
35
|
}
|
|
36
|
+
this.sessionManager = null;
|
|
136
37
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this._crossTabSessionManager.destroy();
|
|
142
|
-
this._crossTabSessionManager = null;
|
|
143
|
-
}
|
|
144
|
-
// Reset cross-tab initialization flag
|
|
145
|
-
this._isInitializingCrossTab = false;
|
|
146
|
-
if (this.recoveryManager) {
|
|
147
|
-
this.recoveryManager.cleanupOldRecoveryAttempts();
|
|
148
|
-
this.recoveryManager = null;
|
|
38
|
+
logging_1.debugLog.error('SessionHandler', 'Failed to start session tracking', {
|
|
39
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
40
|
+
});
|
|
41
|
+
throw error;
|
|
149
42
|
}
|
|
150
43
|
}
|
|
151
|
-
|
|
152
|
-
this.
|
|
153
|
-
logging_1.debugLog.debug('SessionHandler', 'Session recovery manager initialized', { projectId });
|
|
154
|
-
}
|
|
155
|
-
initializeCrossTabSessionManager(projectId) {
|
|
156
|
-
const config = {
|
|
157
|
-
debugMode: (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') ?? false,
|
|
158
|
-
};
|
|
159
|
-
const onSessionStart = (sessionId) => {
|
|
160
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
161
|
-
logging_1.debugLog.debug('SessionHandler', `Cross-tab session started: ${sessionId}`);
|
|
162
|
-
}
|
|
163
|
-
this.set('sessionId', sessionId);
|
|
164
|
-
this.trackSession(types_1.EventType.SESSION_START, false);
|
|
165
|
-
this.persistSession(sessionId);
|
|
166
|
-
this.startHeartbeat();
|
|
167
|
-
};
|
|
168
|
-
const onSessionEnd = (reason) => {
|
|
169
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
170
|
-
logging_1.debugLog.debug('SessionHandler', `Cross-tab session ended: ${reason}`);
|
|
171
|
-
}
|
|
172
|
-
this.clearPersistedSession();
|
|
173
|
-
this.trackSession(types_1.EventType.SESSION_END, false, reason);
|
|
174
|
-
};
|
|
175
|
-
const onTabActivity = () => {
|
|
176
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
177
|
-
logging_1.debugLog.debug('SessionHandler', 'Cross-tab activity detected');
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
const onCrossTabConflict = () => {
|
|
181
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
182
|
-
logging_1.debugLog.warn('SessionHandler', 'Cross-tab conflict detected');
|
|
183
|
-
}
|
|
184
|
-
// Track cross-tab conflict in session health
|
|
185
|
-
if (this.sessionManager) {
|
|
186
|
-
this.sessionManager.trackSessionHealth('conflict');
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
const callbacks = {
|
|
190
|
-
onSessionStart,
|
|
191
|
-
onSessionEnd,
|
|
192
|
-
onTabActivity,
|
|
193
|
-
onCrossTabConflict,
|
|
194
|
-
};
|
|
195
|
-
this._crossTabSessionManager = new cross_tab_session_manager_1.CrossTabSessionManager(this.storageManager, projectId, config, callbacks);
|
|
196
|
-
logging_1.debugLog.debug('SessionHandler', 'Cross-tab session manager initialized', { projectId });
|
|
197
|
-
}
|
|
198
|
-
async createOrJoinSession() {
|
|
199
|
-
if (this.crossTabSessionManager) {
|
|
200
|
-
const existingSessionId = this.crossTabSessionManager.getSessionId();
|
|
201
|
-
if (existingSessionId) {
|
|
202
|
-
return { sessionId: existingSessionId, recovered: false };
|
|
203
|
-
}
|
|
204
|
-
// If cross-tab manager exists but no session, create one through regular session manager
|
|
205
|
-
// The cross-tab manager will coordinate with other tabs automatically
|
|
206
|
-
const sessionResult = this.sessionManager.startSession();
|
|
207
|
-
return { sessionId: sessionResult.sessionId, recovered: sessionResult.recovered ?? false };
|
|
208
|
-
}
|
|
209
|
-
// Fallback: create regular session when no cross-tab manager
|
|
210
|
-
const sessionResult = this.sessionManager.startSession();
|
|
211
|
-
return { sessionId: sessionResult.sessionId, recovered: sessionResult.recovered ?? false };
|
|
44
|
+
isActive() {
|
|
45
|
+
return this.sessionManager !== null && !this.destroyed;
|
|
212
46
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
// Stop heartbeat timer
|
|
219
|
-
this.stopHeartbeat();
|
|
220
|
-
// Clean up cross-tab session if exists
|
|
221
|
-
if (this.crossTabSessionManager) {
|
|
222
|
-
try {
|
|
223
|
-
this.crossTabSessionManager.endSession('orphaned_cleanup');
|
|
224
|
-
}
|
|
225
|
-
catch (error) {
|
|
226
|
-
// Silent cleanup - we're already in error recovery
|
|
227
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
228
|
-
logging_1.debugLog.warn('SessionHandler', `Cross-tab cleanup failed during force cleanup: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
// Track session end for analytics
|
|
233
|
-
try {
|
|
234
|
-
this.trackSession(types_1.EventType.SESSION_END, false, 'orphaned_cleanup');
|
|
235
|
-
}
|
|
236
|
-
catch (error) {
|
|
237
|
-
// Silent tracking failure - we're already in error recovery
|
|
238
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
239
|
-
logging_1.debugLog.warn('SessionHandler', `Session tracking failed during force cleanup: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
243
|
-
logging_1.debugLog.debug('SessionHandler', 'Forced session cleanup completed');
|
|
47
|
+
async cleanupSessionManager() {
|
|
48
|
+
if (this.sessionManager) {
|
|
49
|
+
await this.sessionManager.stopTracking();
|
|
50
|
+
this.sessionManager.destroy();
|
|
51
|
+
this.sessionManager = null;
|
|
244
52
|
}
|
|
245
53
|
}
|
|
246
|
-
|
|
247
|
-
this.
|
|
248
|
-
type: eventType,
|
|
249
|
-
...(eventType === types_1.EventType.SESSION_START &&
|
|
250
|
-
sessionStartRecovered && { session_start_recovered: sessionStartRecovered }),
|
|
251
|
-
...(eventType === types_1.EventType.SESSION_END && { session_end_reason: sessionEndReason ?? 'orphaned_cleanup' }),
|
|
252
|
-
});
|
|
54
|
+
async stopTracking() {
|
|
55
|
+
await this.cleanupSessionManager();
|
|
253
56
|
}
|
|
254
|
-
|
|
255
|
-
if (this.
|
|
256
|
-
logging_1.debugLog.debug('SessionHandler', 'Session already exists, skipping initial session creation');
|
|
57
|
+
destroy() {
|
|
58
|
+
if (this.destroyed) {
|
|
257
59
|
return;
|
|
258
60
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const existingSessionId = this.crossTabSessionManager.getSessionId();
|
|
263
|
-
if (existingSessionId) {
|
|
264
|
-
// Join existing cross-tab session
|
|
265
|
-
this.set('sessionId', existingSessionId);
|
|
266
|
-
this.persistSession(existingSessionId);
|
|
267
|
-
this.startHeartbeat();
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
// No existing cross-tab session, so trigger activity to potentially create one
|
|
271
|
-
// The cross-tab session manager will handle session creation when activity occurs
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
// Fallback: no cross-tab session manager, start regular session
|
|
275
|
-
logging_1.debugLog.debug('SessionHandler', 'Starting regular session (no cross-tab)');
|
|
276
|
-
const sessionResult = this.sessionManager.startSession();
|
|
277
|
-
this.set('sessionId', sessionResult.sessionId);
|
|
278
|
-
this.trackSession(types_1.EventType.SESSION_START, sessionResult.recovered);
|
|
279
|
-
this.persistSession(sessionResult.sessionId);
|
|
280
|
-
this.startHeartbeat();
|
|
281
|
-
}
|
|
282
|
-
checkOrphanedSessions() {
|
|
283
|
-
const storedSessionData = this.storageManager.getItem(this.sessionStorageKey);
|
|
284
|
-
if (storedSessionData) {
|
|
285
|
-
try {
|
|
286
|
-
const session = JSON.parse(storedSessionData);
|
|
287
|
-
const now = Date.now();
|
|
288
|
-
const timeSinceLastHeartbeat = now - session.lastHeartbeat;
|
|
289
|
-
const sessionTimeout = this.get('config')?.sessionTimeout ?? constants_1.DEFAULT_SESSION_TIMEOUT_MS;
|
|
290
|
-
if (timeSinceLastHeartbeat > sessionTimeout) {
|
|
291
|
-
const canRecover = this.recoveryManager?.hasRecoverableSession();
|
|
292
|
-
if (canRecover) {
|
|
293
|
-
if (this.recoveryManager) {
|
|
294
|
-
const sessionContext = {
|
|
295
|
-
sessionId: session.sessionId,
|
|
296
|
-
startTime: session.startTime,
|
|
297
|
-
lastActivity: session.lastHeartbeat,
|
|
298
|
-
tabCount: 1,
|
|
299
|
-
recoveryAttempts: 0,
|
|
300
|
-
metadata: {
|
|
301
|
-
userAgent: navigator.userAgent,
|
|
302
|
-
pageUrl: this.get('pageUrl'),
|
|
303
|
-
},
|
|
304
|
-
};
|
|
305
|
-
this.recoveryManager.storeSessionContextForRecovery(sessionContext);
|
|
306
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
307
|
-
logging_1.debugLog.debug('SessionHandler', `Orphaned session stored for recovery: ${session.sessionId}`);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
this.trackSession(types_1.EventType.SESSION_END);
|
|
312
|
-
this.clearPersistedSession();
|
|
313
|
-
if (this.get('config')?.mode === 'qa' || this.get('config')?.mode === 'debug') {
|
|
314
|
-
logging_1.debugLog.debug('SessionHandler', `Orphaned session ended: ${session.sessionId}, recovery available: ${canRecover}`);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
catch {
|
|
319
|
-
this.clearPersistedSession();
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
persistSession(sessionId) {
|
|
324
|
-
const sessionData = {
|
|
325
|
-
sessionId,
|
|
326
|
-
startTime: Date.now(),
|
|
327
|
-
lastHeartbeat: Date.now(),
|
|
328
|
-
};
|
|
329
|
-
this.storageManager.setItem(this.sessionStorageKey, JSON.stringify(sessionData));
|
|
330
|
-
}
|
|
331
|
-
clearPersistedSession() {
|
|
332
|
-
this.storageManager.removeItem(this.sessionStorageKey);
|
|
333
|
-
}
|
|
334
|
-
startHeartbeat() {
|
|
335
|
-
this.stopHeartbeat();
|
|
336
|
-
this.heartbeatInterval = setInterval(() => {
|
|
337
|
-
const storedSessionData = this.storageManager.getItem(this.sessionStorageKey);
|
|
338
|
-
if (storedSessionData) {
|
|
339
|
-
try {
|
|
340
|
-
const session = JSON.parse(storedSessionData);
|
|
341
|
-
session.lastHeartbeat = Date.now();
|
|
342
|
-
this.storageManager.setItem(this.sessionStorageKey, JSON.stringify(session));
|
|
343
|
-
}
|
|
344
|
-
catch {
|
|
345
|
-
this.clearPersistedSession();
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}, constants_1.SESSION_HEARTBEAT_INTERVAL_MS);
|
|
349
|
-
}
|
|
350
|
-
stopHeartbeat() {
|
|
351
|
-
if (this.heartbeatInterval) {
|
|
352
|
-
clearInterval(this.heartbeatInterval);
|
|
353
|
-
this.heartbeatInterval = null;
|
|
61
|
+
if (this.sessionManager) {
|
|
62
|
+
this.sessionManager.destroy();
|
|
63
|
+
this.sessionManager = null;
|
|
354
64
|
}
|
|
65
|
+
this.destroyed = true;
|
|
66
|
+
this.set('hasStartSession', false);
|
|
355
67
|
}
|
|
356
68
|
}
|
|
357
69
|
exports.SessionHandler = SessionHandler;
|
|
@@ -8,7 +8,6 @@ declare global {
|
|
|
8
8
|
}
|
|
9
9
|
export declare class GoogleAnalyticsIntegration extends StateManager {
|
|
10
10
|
private isInitialized;
|
|
11
|
-
constructor();
|
|
12
11
|
initialize(): Promise<void>;
|
|
13
12
|
trackEvent(eventName: string, metadata: Record<string, MetadataType>): void;
|
|
14
13
|
cleanup(): void;
|