@tracelog/lib 0.5.4 → 0.6.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 +157 -180
- package/dist/browser/tracelog.esm.js +1007 -1357
- package/dist/browser/tracelog.js +2 -2
- package/dist/cjs/api.d.ts +12 -2
- package/dist/cjs/api.js +63 -27
- package/dist/cjs/app.d.ts +2 -2
- package/dist/cjs/app.js +26 -32
- package/dist/cjs/constants/config.constants.d.ts +4 -2
- package/dist/cjs/constants/config.constants.js +6 -18
- package/dist/cjs/constants/index.d.ts +0 -1
- package/dist/cjs/constants/index.js +0 -1
- package/dist/cjs/constants/storage.constants.d.ts +3 -2
- package/dist/cjs/constants/storage.constants.js +4 -4
- package/dist/cjs/handlers/click.handler.js +3 -6
- package/dist/cjs/handlers/error.handler.js +1 -11
- package/dist/cjs/handlers/page-view.handler.js +0 -4
- package/dist/cjs/handlers/performance.handler.js +14 -29
- package/dist/cjs/handlers/scroll.handler.js +7 -6
- package/dist/cjs/handlers/session.handler.js +7 -6
- package/dist/cjs/integrations/google-analytics.integration.js +2 -6
- package/dist/cjs/listeners/activity-listener-manager.js +3 -3
- package/dist/cjs/listeners/input-listener-managers.js +3 -3
- package/dist/cjs/listeners/touch-listener-manager.js +3 -3
- package/dist/cjs/listeners/unload-listener-manager.js +3 -3
- package/dist/cjs/listeners/visibility-listener-manager.js +3 -3
- package/dist/cjs/managers/event.manager.d.ts +2 -1
- package/dist/cjs/managers/event.manager.js +60 -38
- package/dist/cjs/managers/sender.manager.js +29 -36
- package/dist/cjs/managers/session.manager.js +5 -13
- package/dist/cjs/managers/state.manager.d.ts +0 -3
- package/dist/cjs/managers/state.manager.js +1 -43
- package/dist/cjs/managers/storage.manager.d.ts +16 -2
- package/dist/cjs/managers/storage.manager.js +73 -19
- package/dist/cjs/managers/user.manager.d.ts +1 -1
- package/dist/cjs/managers/user.manager.js +2 -2
- package/dist/cjs/public-api.d.ts +3 -3
- package/dist/cjs/public-api.js +1 -1
- package/dist/cjs/test-bridge.d.ts +1 -0
- package/dist/cjs/test-bridge.js +37 -2
- package/dist/cjs/types/config.types.d.ts +15 -18
- package/dist/cjs/types/config.types.js +6 -0
- package/dist/cjs/types/event.types.d.ts +1 -13
- package/dist/cjs/types/index.d.ts +0 -2
- package/dist/cjs/types/index.js +0 -2
- package/dist/cjs/types/mode.types.d.ts +1 -2
- package/dist/cjs/types/mode.types.js +0 -1
- package/dist/cjs/types/queue.types.d.ts +0 -6
- package/dist/cjs/types/state.types.d.ts +2 -0
- package/dist/cjs/types/test-bridge.types.d.ts +2 -2
- package/dist/cjs/types/validation-error.types.d.ts +0 -6
- package/dist/cjs/types/validation-error.types.js +1 -10
- package/dist/cjs/utils/browser/device-detector.utils.js +2 -24
- package/dist/cjs/utils/browser/index.d.ts +1 -0
- package/dist/cjs/utils/browser/index.js +1 -0
- package/dist/cjs/utils/browser/qa-mode.utils.d.ts +13 -0
- package/dist/cjs/utils/browser/qa-mode.utils.js +43 -0
- package/dist/cjs/utils/browser/utm-params.utils.js +0 -15
- package/dist/cjs/utils/data/uuid.utils.d.ts +13 -0
- package/dist/cjs/utils/data/uuid.utils.js +37 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/utils/index.js +1 -1
- package/dist/cjs/utils/logging.utils.d.ts +6 -0
- package/dist/cjs/utils/logging.utils.js +25 -0
- package/dist/cjs/utils/network/index.d.ts +0 -1
- package/dist/cjs/utils/network/index.js +0 -1
- package/dist/cjs/utils/network/url.utils.d.ts +2 -8
- package/dist/cjs/utils/network/url.utils.js +46 -90
- package/dist/cjs/utils/security/sanitize.utils.d.ts +1 -13
- package/dist/cjs/utils/security/sanitize.utils.js +15 -178
- package/dist/cjs/utils/validations/config-validations.utils.d.ts +3 -9
- package/dist/cjs/utils/validations/config-validations.utils.js +48 -94
- package/dist/cjs/utils/validations/event-validations.utils.js +11 -5
- package/dist/cjs/utils/validations/index.d.ts +0 -1
- package/dist/cjs/utils/validations/index.js +0 -1
- package/dist/cjs/utils/validations/metadata-validations.utils.js +0 -1
- package/dist/cjs/utils/validations/type-guards.utils.d.ts +2 -2
- package/dist/cjs/utils/validations/type-guards.utils.js +50 -4
- package/dist/esm/api.d.ts +12 -2
- package/dist/esm/api.js +62 -27
- package/dist/esm/app.d.ts +2 -2
- package/dist/esm/app.js +28 -34
- package/dist/esm/constants/config.constants.d.ts +4 -2
- package/dist/esm/constants/config.constants.js +4 -16
- package/dist/esm/constants/index.d.ts +0 -1
- package/dist/esm/constants/index.js +0 -1
- package/dist/esm/constants/storage.constants.d.ts +3 -2
- package/dist/esm/constants/storage.constants.js +3 -2
- package/dist/esm/handlers/click.handler.js +3 -6
- package/dist/esm/handlers/error.handler.js +1 -11
- package/dist/esm/handlers/page-view.handler.js +0 -4
- package/dist/esm/handlers/performance.handler.js +14 -29
- package/dist/esm/handlers/scroll.handler.js +7 -6
- package/dist/esm/handlers/session.handler.js +7 -6
- package/dist/esm/integrations/google-analytics.integration.js +3 -7
- package/dist/esm/listeners/activity-listener-manager.js +3 -3
- package/dist/esm/listeners/input-listener-managers.js +3 -3
- package/dist/esm/listeners/touch-listener-manager.js +3 -3
- package/dist/esm/listeners/unload-listener-manager.js +3 -3
- package/dist/esm/listeners/visibility-listener-manager.js +3 -3
- package/dist/esm/managers/event.manager.d.ts +2 -1
- package/dist/esm/managers/event.manager.js +62 -40
- package/dist/esm/managers/sender.manager.js +31 -38
- package/dist/esm/managers/session.manager.js +5 -13
- package/dist/esm/managers/state.manager.d.ts +0 -3
- package/dist/esm/managers/state.manager.js +1 -43
- package/dist/esm/managers/storage.manager.d.ts +16 -2
- package/dist/esm/managers/storage.manager.js +73 -19
- package/dist/esm/managers/user.manager.d.ts +1 -1
- package/dist/esm/managers/user.manager.js +2 -2
- package/dist/esm/public-api.d.ts +3 -3
- package/dist/esm/public-api.js +1 -1
- package/dist/esm/test-bridge.d.ts +1 -0
- package/dist/esm/test-bridge.js +37 -2
- package/dist/esm/types/config.types.d.ts +15 -18
- package/dist/esm/types/config.types.js +5 -1
- package/dist/esm/types/event.types.d.ts +1 -13
- package/dist/esm/types/index.d.ts +0 -2
- package/dist/esm/types/index.js +0 -2
- package/dist/esm/types/mode.types.d.ts +1 -2
- package/dist/esm/types/mode.types.js +0 -1
- package/dist/esm/types/queue.types.d.ts +0 -6
- package/dist/esm/types/state.types.d.ts +2 -0
- package/dist/esm/types/test-bridge.types.d.ts +2 -2
- package/dist/esm/types/validation-error.types.d.ts +0 -6
- package/dist/esm/types/validation-error.types.js +0 -8
- package/dist/esm/utils/browser/device-detector.utils.js +2 -24
- package/dist/esm/utils/browser/index.d.ts +1 -0
- package/dist/esm/utils/browser/index.js +1 -0
- package/dist/esm/utils/browser/qa-mode.utils.d.ts +13 -0
- package/dist/esm/utils/browser/qa-mode.utils.js +39 -0
- package/dist/esm/utils/browser/utm-params.utils.js +0 -15
- package/dist/esm/utils/data/uuid.utils.d.ts +13 -0
- package/dist/esm/utils/data/uuid.utils.js +35 -0
- package/dist/esm/utils/index.d.ts +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/utils/logging.utils.d.ts +6 -0
- package/dist/esm/utils/logging.utils.js +20 -0
- package/dist/esm/utils/network/index.d.ts +0 -1
- package/dist/esm/utils/network/index.js +0 -1
- package/dist/esm/utils/network/url.utils.d.ts +2 -8
- package/dist/esm/utils/network/url.utils.js +45 -88
- package/dist/esm/utils/security/sanitize.utils.d.ts +1 -13
- package/dist/esm/utils/security/sanitize.utils.js +15 -176
- package/dist/esm/utils/validations/config-validations.utils.d.ts +3 -9
- package/dist/esm/utils/validations/config-validations.utils.js +49 -94
- package/dist/esm/utils/validations/event-validations.utils.js +11 -5
- package/dist/esm/utils/validations/index.d.ts +0 -1
- package/dist/esm/utils/validations/index.js +0 -1
- package/dist/esm/utils/validations/metadata-validations.utils.js +0 -1
- package/dist/esm/utils/validations/type-guards.utils.d.ts +2 -2
- package/dist/esm/utils/validations/type-guards.utils.js +50 -4
- package/package.json +1 -1
- package/dist/cjs/app.types.d.ts +0 -2
- package/dist/cjs/app.types.js +0 -12
- package/dist/cjs/constants/api.constants.d.ts +0 -6
- package/dist/cjs/constants/api.constants.js +0 -14
- package/dist/cjs/managers/api.manager.d.ts +0 -13
- package/dist/cjs/managers/api.manager.js +0 -44
- package/dist/cjs/managers/config.builder.d.ts +0 -33
- package/dist/cjs/managers/config.builder.js +0 -116
- package/dist/cjs/managers/config.manager.d.ts +0 -56
- package/dist/cjs/managers/config.manager.js +0 -157
- package/dist/cjs/managers/tags.manager.d.ts +0 -36
- package/dist/cjs/managers/tags.manager.js +0 -171
- package/dist/cjs/types/api.types.d.ts +0 -52
- package/dist/cjs/types/api.types.js +0 -56
- package/dist/cjs/types/tag.types.d.ts +0 -43
- package/dist/cjs/types/tag.types.js +0 -31
- package/dist/cjs/utils/logging/debug-logger.utils.d.ts +0 -14
- package/dist/cjs/utils/logging/debug-logger.utils.js +0 -47
- package/dist/cjs/utils/logging/index.d.ts +0 -1
- package/dist/cjs/utils/logging/index.js +0 -5
- package/dist/cjs/utils/network/fetch-with-timeout.utils.d.ts +0 -4
- package/dist/cjs/utils/network/fetch-with-timeout.utils.js +0 -25
- package/dist/cjs/utils/validations/url-validations.utils.d.ts +0 -15
- package/dist/cjs/utils/validations/url-validations.utils.js +0 -47
- package/dist/esm/app.types.d.ts +0 -2
- package/dist/esm/app.types.js +0 -1
- package/dist/esm/constants/api.constants.d.ts +0 -6
- package/dist/esm/constants/api.constants.js +0 -11
- package/dist/esm/managers/api.manager.d.ts +0 -13
- package/dist/esm/managers/api.manager.js +0 -41
- package/dist/esm/managers/config.builder.d.ts +0 -33
- package/dist/esm/managers/config.builder.js +0 -112
- package/dist/esm/managers/config.manager.d.ts +0 -56
- package/dist/esm/managers/config.manager.js +0 -153
- package/dist/esm/managers/tags.manager.d.ts +0 -36
- package/dist/esm/managers/tags.manager.js +0 -167
- package/dist/esm/types/api.types.d.ts +0 -52
- package/dist/esm/types/api.types.js +0 -53
- package/dist/esm/types/tag.types.d.ts +0 -43
- package/dist/esm/types/tag.types.js +0 -28
- package/dist/esm/utils/logging/debug-logger.utils.d.ts +0 -14
- package/dist/esm/utils/logging/debug-logger.utils.js +0 -44
- package/dist/esm/utils/logging/index.d.ts +0 -1
- package/dist/esm/utils/logging/index.js +0 -1
- package/dist/esm/utils/network/fetch-with-timeout.utils.d.ts +0 -4
- package/dist/esm/utils/network/fetch-with-timeout.utils.js +0 -22
- package/dist/esm/utils/validations/url-validations.utils.d.ts +0 -15
- package/dist/esm/utils/validations/url-validations.utils.js +0 -42
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TouchListenerManager = void 0;
|
|
4
|
-
const
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
5
|
class TouchListenerManager {
|
|
6
6
|
constructor(onActivity) {
|
|
7
7
|
this.options = { passive: true };
|
|
@@ -15,7 +15,7 @@ class TouchListenerManager {
|
|
|
15
15
|
window.addEventListener('orientationchange', this.onActivity, this.options);
|
|
16
16
|
}
|
|
17
17
|
catch (error) {
|
|
18
|
-
|
|
18
|
+
(0, utils_1.log)('error', 'Failed to setup touch listeners', { error });
|
|
19
19
|
throw error;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -27,7 +27,7 @@ class TouchListenerManager {
|
|
|
27
27
|
window.removeEventListener('orientationchange', this.onActivity);
|
|
28
28
|
}
|
|
29
29
|
catch (error) {
|
|
30
|
-
|
|
30
|
+
(0, utils_1.log)('warn', 'Error during touch listeners cleanup', { error });
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.UnloadListenerManager = void 0;
|
|
4
|
-
const
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
5
|
class UnloadListenerManager {
|
|
6
6
|
constructor(onInactivity) {
|
|
7
7
|
this.options = { passive: true };
|
|
@@ -13,7 +13,7 @@ class UnloadListenerManager {
|
|
|
13
13
|
window.addEventListener('pagehide', this.onInactivity, this.options);
|
|
14
14
|
}
|
|
15
15
|
catch (error) {
|
|
16
|
-
|
|
16
|
+
(0, utils_1.log)('error', 'Failed to setup unload listeners', { error });
|
|
17
17
|
throw error;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -23,7 +23,7 @@ class UnloadListenerManager {
|
|
|
23
23
|
window.removeEventListener('pagehide', this.onInactivity);
|
|
24
24
|
}
|
|
25
25
|
catch (error) {
|
|
26
|
-
|
|
26
|
+
(0, utils_1.log)('warn', 'Error during unload listeners cleanup', { error });
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.VisibilityListenerManager = void 0;
|
|
4
|
-
const
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
5
|
class VisibilityListenerManager {
|
|
6
6
|
constructor(onActivity, onVisibilityChange) {
|
|
7
7
|
this.options = { passive: true };
|
|
@@ -24,7 +24,7 @@ class VisibilityListenerManager {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
catch (error) {
|
|
27
|
-
|
|
27
|
+
(0, utils_1.log)('error', 'Failed to setup visibility listeners', { error });
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
cleanup() {
|
|
@@ -40,7 +40,7 @@ class VisibilityListenerManager {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
catch (error) {
|
|
43
|
-
|
|
43
|
+
(0, utils_1.log)('warn', 'Error during visibility listeners cleanup', { error });
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -8,6 +8,7 @@ export declare class EventManager extends StateManager {
|
|
|
8
8
|
private readonly dataSender;
|
|
9
9
|
private readonly emitter;
|
|
10
10
|
private eventsQueue;
|
|
11
|
+
private pendingEventsBuffer;
|
|
11
12
|
private lastEventFingerprint;
|
|
12
13
|
private lastEventTime;
|
|
13
14
|
private sendIntervalId;
|
|
@@ -18,12 +19,12 @@ export declare class EventManager extends StateManager {
|
|
|
18
19
|
flushImmediately(): Promise<boolean>;
|
|
19
20
|
flushImmediatelySync(): boolean;
|
|
20
21
|
getQueueLength(): number;
|
|
22
|
+
flushPendingEvents(): void;
|
|
21
23
|
private clearSendInterval;
|
|
22
24
|
private flushEvents;
|
|
23
25
|
private sendEventsQueue;
|
|
24
26
|
private buildEventsPayload;
|
|
25
27
|
private buildEventPayload;
|
|
26
|
-
private isEventExcluded;
|
|
27
28
|
private isDuplicateEvent;
|
|
28
29
|
private createEventFingerprint;
|
|
29
30
|
private createEventSignature;
|
|
@@ -10,6 +10,7 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
10
10
|
constructor(storeManager, googleAnalytics = null, emitter = null) {
|
|
11
11
|
super();
|
|
12
12
|
this.eventsQueue = [];
|
|
13
|
+
this.pendingEventsBuffer = [];
|
|
13
14
|
this.lastEventFingerprint = null;
|
|
14
15
|
this.lastEventTime = 0;
|
|
15
16
|
this.sendIntervalId = null;
|
|
@@ -21,7 +22,7 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
21
22
|
await this.dataSender.recoverPersistedEvents({
|
|
22
23
|
onSuccess: (_eventCount, recoveredEvents, body) => {
|
|
23
24
|
if (recoveredEvents && recoveredEvents.length > 0) {
|
|
24
|
-
const eventIds = recoveredEvents.map((e) => e.
|
|
25
|
+
const eventIds = recoveredEvents.map((e) => e.id);
|
|
25
26
|
this.removeProcessedEvents(eventIds);
|
|
26
27
|
if (body) {
|
|
27
28
|
this.emitEventsQueue(body);
|
|
@@ -29,13 +30,27 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
29
30
|
}
|
|
30
31
|
},
|
|
31
32
|
onFailure: async () => {
|
|
32
|
-
utils_1.
|
|
33
|
+
(0, utils_1.log)('warn', 'Failed to recover persisted events');
|
|
33
34
|
},
|
|
34
35
|
});
|
|
35
36
|
}
|
|
36
37
|
track({ type, page_url, from_page_url, scroll_data, click_data, custom_event, web_vitals, error_data, session_end_reason, }) {
|
|
37
38
|
if (!type) {
|
|
38
|
-
utils_1.
|
|
39
|
+
(0, utils_1.log)('warn', 'Event type is required');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!this.get('sessionId')) {
|
|
43
|
+
this.pendingEventsBuffer.push({
|
|
44
|
+
type,
|
|
45
|
+
page_url,
|
|
46
|
+
from_page_url,
|
|
47
|
+
scroll_data,
|
|
48
|
+
click_data,
|
|
49
|
+
custom_event,
|
|
50
|
+
web_vitals,
|
|
51
|
+
error_data,
|
|
52
|
+
session_end_reason,
|
|
53
|
+
});
|
|
39
54
|
return;
|
|
40
55
|
}
|
|
41
56
|
const eventType = type;
|
|
@@ -54,21 +69,18 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
54
69
|
error_data,
|
|
55
70
|
session_end_reason,
|
|
56
71
|
});
|
|
57
|
-
if (this.isEventExcluded(payload)) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
72
|
if (!isCriticalEvent && !this.shouldSample()) {
|
|
61
73
|
return;
|
|
62
74
|
}
|
|
63
75
|
if (isSessionStart) {
|
|
64
76
|
const currentSessionId = this.get('sessionId');
|
|
65
77
|
if (!currentSessionId) {
|
|
66
|
-
utils_1.
|
|
78
|
+
(0, utils_1.log)('warn', 'Session start event ignored: missing sessionId');
|
|
67
79
|
return;
|
|
68
80
|
}
|
|
69
81
|
if (this.get('hasStartSession')) {
|
|
70
|
-
utils_1.
|
|
71
|
-
sessionId: currentSessionId,
|
|
82
|
+
(0, utils_1.log)('warn', 'Duplicate session_start detected', {
|
|
83
|
+
data: { sessionId: currentSessionId },
|
|
72
84
|
});
|
|
73
85
|
return;
|
|
74
86
|
}
|
|
@@ -77,6 +89,14 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
77
89
|
if (this.isDuplicateEvent(payload)) {
|
|
78
90
|
return;
|
|
79
91
|
}
|
|
92
|
+
if (this.get('mode') === types_1.Mode.QA && eventType === types_1.EventType.CUSTOM && custom_event) {
|
|
93
|
+
console.log('[TraceLog] Event', {
|
|
94
|
+
name: custom_event.name,
|
|
95
|
+
...(custom_event.metadata && { metadata: custom_event.metadata }),
|
|
96
|
+
});
|
|
97
|
+
this.emitEvent(payload);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
80
100
|
this.addToQueue(payload);
|
|
81
101
|
}
|
|
82
102
|
stop() {
|
|
@@ -85,6 +105,7 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
85
105
|
this.sendIntervalId = null;
|
|
86
106
|
}
|
|
87
107
|
this.eventsQueue = [];
|
|
108
|
+
this.pendingEventsBuffer = [];
|
|
88
109
|
this.lastEventFingerprint = null;
|
|
89
110
|
this.lastEventTime = 0;
|
|
90
111
|
this.dataSender.stop();
|
|
@@ -98,6 +119,20 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
98
119
|
getQueueLength() {
|
|
99
120
|
return this.eventsQueue.length;
|
|
100
121
|
}
|
|
122
|
+
flushPendingEvents() {
|
|
123
|
+
if (this.pendingEventsBuffer.length === 0) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (!this.get('sessionId')) {
|
|
127
|
+
(0, utils_1.log)('warn', 'Cannot flush pending events: session not initialized');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const bufferedEvents = [...this.pendingEventsBuffer];
|
|
131
|
+
this.pendingEventsBuffer = [];
|
|
132
|
+
bufferedEvents.forEach((event) => {
|
|
133
|
+
this.track(event);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
101
136
|
clearSendInterval() {
|
|
102
137
|
if (this.sendIntervalId) {
|
|
103
138
|
clearInterval(this.sendIntervalId);
|
|
@@ -110,7 +145,7 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
110
145
|
}
|
|
111
146
|
const body = this.buildEventsPayload();
|
|
112
147
|
const eventsToSend = [...this.eventsQueue];
|
|
113
|
-
const eventIds = eventsToSend.map((e) =>
|
|
148
|
+
const eventIds = eventsToSend.map((e) => e.id);
|
|
114
149
|
if (isSync) {
|
|
115
150
|
const success = this.dataSender.sendEventsQueueSync(body);
|
|
116
151
|
if (success) {
|
|
@@ -128,8 +163,8 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
128
163
|
this.emitEventsQueue(body);
|
|
129
164
|
},
|
|
130
165
|
onFailure: () => {
|
|
131
|
-
utils_1.
|
|
132
|
-
eventCount: eventsToSend.length,
|
|
166
|
+
(0, utils_1.log)('warn', 'Async flush failed', {
|
|
167
|
+
data: { eventCount: eventsToSend.length },
|
|
133
168
|
});
|
|
134
169
|
},
|
|
135
170
|
});
|
|
@@ -141,15 +176,15 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
141
176
|
}
|
|
142
177
|
const body = this.buildEventsPayload();
|
|
143
178
|
const eventsToSend = [...this.eventsQueue];
|
|
144
|
-
const eventIds = eventsToSend.map((e) =>
|
|
179
|
+
const eventIds = eventsToSend.map((e) => e.id);
|
|
145
180
|
await this.dataSender.sendEventsQueue(body, {
|
|
146
181
|
onSuccess: () => {
|
|
147
182
|
this.removeProcessedEvents(eventIds);
|
|
148
183
|
this.emitEventsQueue(body);
|
|
149
184
|
},
|
|
150
185
|
onFailure: async () => {
|
|
151
|
-
utils_1.
|
|
152
|
-
eventCount: eventsToSend.length,
|
|
186
|
+
(0, utils_1.log)('warn', 'Events send failed, keeping in queue', {
|
|
187
|
+
data: { eventCount: eventsToSend.length },
|
|
153
188
|
});
|
|
154
189
|
},
|
|
155
190
|
});
|
|
@@ -180,6 +215,7 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
180
215
|
const isSessionStart = data.type === types_1.EventType.SESSION_START;
|
|
181
216
|
const currentPageUrl = data.page_url ?? this.get('pageUrl');
|
|
182
217
|
const payload = {
|
|
218
|
+
id: (0, utils_1.generateEventId)(),
|
|
183
219
|
type: data.type,
|
|
184
220
|
page_url: currentPageUrl,
|
|
185
221
|
timestamp: Date.now(),
|
|
@@ -193,23 +229,8 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
193
229
|
...(data.session_end_reason && { session_end_reason: data.session_end_reason }),
|
|
194
230
|
...(isSessionStart && (0, utils_1.getUTMParameters)() && { utm: (0, utils_1.getUTMParameters)() }),
|
|
195
231
|
};
|
|
196
|
-
const projectTags = this.get('config')?.tags;
|
|
197
|
-
if (projectTags?.length) {
|
|
198
|
-
payload.tags = projectTags;
|
|
199
|
-
}
|
|
200
232
|
return payload;
|
|
201
233
|
}
|
|
202
|
-
isEventExcluded(event) {
|
|
203
|
-
const config = this.get('config');
|
|
204
|
-
const isRouteExcluded = (0, utils_1.isUrlPathExcluded)(event.page_url, config?.excludedUrlPaths ?? []);
|
|
205
|
-
const hasStartSession = this.get('hasStartSession');
|
|
206
|
-
const isSessionEndEvent = event.type === types_1.EventType.SESSION_END;
|
|
207
|
-
const isSessionStartEvent = event.type === types_1.EventType.SESSION_START;
|
|
208
|
-
if (isRouteExcluded && !isSessionStartEvent && !(isSessionEndEvent && hasStartSession)) {
|
|
209
|
-
return true;
|
|
210
|
-
}
|
|
211
|
-
return config?.ipExcluded === true;
|
|
212
|
-
}
|
|
213
234
|
isDuplicateEvent(event) {
|
|
214
235
|
const now = Date.now();
|
|
215
236
|
const fingerprint = this.createEventFingerprint(event);
|
|
@@ -250,11 +271,13 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
250
271
|
if (this.eventsQueue.length > config_constants_1.MAX_EVENTS_QUEUE_LENGTH) {
|
|
251
272
|
const nonCriticalIndex = this.eventsQueue.findIndex((e) => e.type !== types_1.EventType.SESSION_START && e.type !== types_1.EventType.SESSION_END);
|
|
252
273
|
const removedEvent = nonCriticalIndex >= 0 ? this.eventsQueue.splice(nonCriticalIndex, 1)[0] : this.eventsQueue.shift();
|
|
253
|
-
utils_1.
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
274
|
+
(0, utils_1.log)('warn', 'Event queue overflow, oldest non-critical event removed', {
|
|
275
|
+
data: {
|
|
276
|
+
maxLength: config_constants_1.MAX_EVENTS_QUEUE_LENGTH,
|
|
277
|
+
currentLength: this.eventsQueue.length,
|
|
278
|
+
removedEventType: removedEvent?.type,
|
|
279
|
+
wasCritical: removedEvent?.type === types_1.EventType.SESSION_START || removedEvent?.type === types_1.EventType.SESSION_END,
|
|
280
|
+
},
|
|
258
281
|
});
|
|
259
282
|
}
|
|
260
283
|
if (!this.sendIntervalId) {
|
|
@@ -271,7 +294,7 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
271
294
|
}
|
|
272
295
|
handleGoogleAnalyticsIntegration(event) {
|
|
273
296
|
if (this.googleAnalytics && event.type === types_1.EventType.CUSTOM && event.custom_event) {
|
|
274
|
-
if (this.get('
|
|
297
|
+
if (this.get('mode') === types_1.Mode.QA) {
|
|
275
298
|
return;
|
|
276
299
|
}
|
|
277
300
|
this.googleAnalytics.trackEvent(event.custom_event.name, event.custom_event.metadata ?? {});
|
|
@@ -284,8 +307,7 @@ class EventManager extends state_manager_1.StateManager {
|
|
|
284
307
|
removeProcessedEvents(eventIds) {
|
|
285
308
|
const eventIdSet = new Set(eventIds);
|
|
286
309
|
this.eventsQueue = this.eventsQueue.filter((event) => {
|
|
287
|
-
|
|
288
|
-
return !eventIdSet.has(eventId);
|
|
310
|
+
return !eventIdSet.has(event.id);
|
|
289
311
|
});
|
|
290
312
|
}
|
|
291
313
|
emitEvent(eventData) {
|
|
@@ -14,9 +14,8 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
14
14
|
this.storeManager = storeManager;
|
|
15
15
|
}
|
|
16
16
|
getQueueStorageKey() {
|
|
17
|
-
const projectId = this.get('config')?.id || 'default';
|
|
18
17
|
const userId = this.get('userId') || 'anonymous';
|
|
19
|
-
return
|
|
18
|
+
return (0, constants_1.QUEUE_KEY)(userId);
|
|
20
19
|
}
|
|
21
20
|
sendEventsQueueSync(body) {
|
|
22
21
|
if (this.shouldSkipSend()) {
|
|
@@ -24,9 +23,9 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
24
23
|
return true;
|
|
25
24
|
}
|
|
26
25
|
const config = this.get('config');
|
|
27
|
-
if (config?.
|
|
28
|
-
utils_1.
|
|
29
|
-
events: body.events.length,
|
|
26
|
+
if (config?.integrations?.custom?.apiUrl === types_1.SpecialApiUrl.Fail) {
|
|
27
|
+
(0, utils_1.log)('warn', 'Fail mode: simulating network failure (sync)', {
|
|
28
|
+
data: { events: body.events.length },
|
|
30
29
|
});
|
|
31
30
|
return false;
|
|
32
31
|
}
|
|
@@ -37,9 +36,11 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
37
36
|
return success;
|
|
38
37
|
}
|
|
39
38
|
async sendEventsQueue(body, callbacks) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
if (!this.shouldSkipSend()) {
|
|
40
|
+
const persisted = this.persistEvents(body);
|
|
41
|
+
if (!persisted) {
|
|
42
|
+
(0, utils_1.log)('warn', 'Failed to persist events, attempting immediate send');
|
|
43
|
+
}
|
|
43
44
|
}
|
|
44
45
|
const success = await this.send(body);
|
|
45
46
|
if (success) {
|
|
@@ -73,7 +74,7 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
catch (error) {
|
|
76
|
-
utils_1.
|
|
77
|
+
(0, utils_1.log)('error', 'Failed to recover persisted events', { error });
|
|
77
78
|
this.clearPersistedEvents();
|
|
78
79
|
}
|
|
79
80
|
}
|
|
@@ -92,9 +93,9 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
92
93
|
return this.simulateSuccessfulSend();
|
|
93
94
|
}
|
|
94
95
|
const config = this.get('config');
|
|
95
|
-
if (config?.
|
|
96
|
-
utils_1.
|
|
97
|
-
events: body.events.length,
|
|
96
|
+
if (config?.integrations?.custom?.apiUrl === types_1.SpecialApiUrl.Fail) {
|
|
97
|
+
(0, utils_1.log)('warn', 'Fail mode: simulating network failure', {
|
|
98
|
+
data: { events: body.events.length },
|
|
98
99
|
});
|
|
99
100
|
return false;
|
|
100
101
|
}
|
|
@@ -104,11 +105,12 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
104
105
|
return response.ok;
|
|
105
106
|
}
|
|
106
107
|
catch (error) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
(0, utils_1.log)('error', 'Send request failed', {
|
|
109
|
+
error,
|
|
110
|
+
data: {
|
|
111
|
+
events: body.events.length,
|
|
112
|
+
url: url.replace(/\/\/[^/]+/, '//[DOMAIN]'),
|
|
113
|
+
},
|
|
112
114
|
});
|
|
113
115
|
return false;
|
|
114
116
|
}
|
|
@@ -116,18 +118,16 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
116
118
|
async sendWithTimeout(url, payload) {
|
|
117
119
|
const controller = new AbortController();
|
|
118
120
|
const timeoutId = setTimeout(() => controller.abort(), constants_1.REQUEST_TIMEOUT_MS);
|
|
119
|
-
const config = this.get('config');
|
|
120
121
|
try {
|
|
121
122
|
const response = await fetch(url, {
|
|
122
123
|
method: 'POST',
|
|
123
|
-
headers: {
|
|
124
|
-
'Content-Type': 'application/json',
|
|
125
|
-
'X-TraceLog-Project': config?.id || 'unknown',
|
|
126
|
-
},
|
|
127
124
|
body: payload,
|
|
128
125
|
keepalive: true,
|
|
129
126
|
credentials: 'include',
|
|
130
127
|
signal: controller.signal,
|
|
128
|
+
headers: {
|
|
129
|
+
'Content-Type': 'application/json',
|
|
130
|
+
},
|
|
131
131
|
});
|
|
132
132
|
if (!response.ok) {
|
|
133
133
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
@@ -146,10 +146,10 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
146
146
|
if (success) {
|
|
147
147
|
return true;
|
|
148
148
|
}
|
|
149
|
-
utils_1.
|
|
149
|
+
(0, utils_1.log)('warn', 'sendBeacon failed, persisting events for recovery');
|
|
150
150
|
}
|
|
151
151
|
else {
|
|
152
|
-
utils_1.
|
|
152
|
+
(0, utils_1.log)('warn', 'sendBeacon not available, persisting events for recovery');
|
|
153
153
|
}
|
|
154
154
|
this.persistEventsForRecovery(body);
|
|
155
155
|
return false;
|
|
@@ -179,7 +179,7 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
catch (error) {
|
|
182
|
-
utils_1.
|
|
182
|
+
(0, utils_1.log)('warn', 'Failed to parse persisted data', { error });
|
|
183
183
|
this.clearPersistedEvents();
|
|
184
184
|
}
|
|
185
185
|
return null;
|
|
@@ -216,7 +216,7 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
216
216
|
return !!this.storeManager.getItem(storageKey);
|
|
217
217
|
}
|
|
218
218
|
catch (error) {
|
|
219
|
-
utils_1.
|
|
219
|
+
(0, utils_1.log)('warn', 'Failed to persist events', { error });
|
|
220
220
|
return false;
|
|
221
221
|
}
|
|
222
222
|
}
|
|
@@ -226,7 +226,7 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
226
226
|
this.storeManager.removeItem(key);
|
|
227
227
|
}
|
|
228
228
|
catch (error) {
|
|
229
|
-
utils_1.
|
|
229
|
+
(0, utils_1.log)('warn', 'Failed to clear persisted events', { error });
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
resetRetryState() {
|
|
@@ -239,7 +239,7 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
239
239
|
return;
|
|
240
240
|
}
|
|
241
241
|
if (this.retryCount >= constants_1.MAX_RETRIES) {
|
|
242
|
-
utils_1.
|
|
242
|
+
(0, utils_1.log)('warn', 'Max retries reached, giving up', { data: { retryCount: this.retryCount } });
|
|
243
243
|
this.clearPersistedEvents();
|
|
244
244
|
this.resetRetryState();
|
|
245
245
|
originalCallbacks?.onFailure?.();
|
|
@@ -270,16 +270,9 @@ class SenderManager extends state_manager_1.StateManager {
|
|
|
270
270
|
this.isRetrying = false;
|
|
271
271
|
}
|
|
272
272
|
}, retryDelay);
|
|
273
|
-
utils_1.debugLog.debug('SenderManager', 'Retry scheduled', {
|
|
274
|
-
attempt: this.retryCount + 1,
|
|
275
|
-
delay: retryDelay,
|
|
276
|
-
events: body.events.length,
|
|
277
|
-
});
|
|
278
273
|
}
|
|
279
274
|
shouldSkipSend() {
|
|
280
|
-
|
|
281
|
-
const { id } = config || {};
|
|
282
|
-
return id === types_1.SpecialProjectId.Skip;
|
|
275
|
+
return !this.get('apiUrl');
|
|
283
276
|
}
|
|
284
277
|
async simulateSuccessfulSend() {
|
|
285
278
|
const delay = Math.random() * 400 + 100;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SessionManager = void 0;
|
|
4
4
|
const constants_1 = require("../constants");
|
|
5
5
|
const types_1 = require("../types");
|
|
6
|
-
const
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
7
|
const state_manager_1 = require("./state.manager");
|
|
8
8
|
class SessionManager extends state_manager_1.StateManager {
|
|
9
9
|
constructor(storageManager, eventManager, projectId) {
|
|
@@ -20,7 +20,7 @@ class SessionManager extends state_manager_1.StateManager {
|
|
|
20
20
|
}
|
|
21
21
|
initCrossTabSync() {
|
|
22
22
|
if (typeof BroadcastChannel === 'undefined') {
|
|
23
|
-
|
|
23
|
+
(0, utils_1.log)('warn', 'BroadcastChannel not supported');
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
26
|
const projectId = this.getProjectId();
|
|
@@ -31,7 +31,6 @@ class SessionManager extends state_manager_1.StateManager {
|
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
if (action === 'session_end') {
|
|
34
|
-
logging_1.debugLog.debug('SessionManager', 'Session end synced from another tab');
|
|
35
34
|
this.resetSessionState();
|
|
36
35
|
return;
|
|
37
36
|
}
|
|
@@ -42,7 +41,6 @@ class SessionManager extends state_manager_1.StateManager {
|
|
|
42
41
|
if (this.isTracking) {
|
|
43
42
|
this.setupSessionTimeout();
|
|
44
43
|
}
|
|
45
|
-
logging_1.debugLog.debug('SessionManager', 'Session synced from another tab', { sessionId });
|
|
46
44
|
}
|
|
47
45
|
};
|
|
48
46
|
}
|
|
@@ -85,11 +83,9 @@ class SessionManager extends state_manager_1.StateManager {
|
|
|
85
83
|
}
|
|
86
84
|
const sessionTimeout = this.get('config')?.sessionTimeout ?? constants_1.DEFAULT_SESSION_TIMEOUT;
|
|
87
85
|
if (Date.now() - storedSession.lastActivity > sessionTimeout) {
|
|
88
|
-
logging_1.debugLog.debug('SessionManager', 'Stored session expired');
|
|
89
86
|
this.clearStoredSession();
|
|
90
87
|
return null;
|
|
91
88
|
}
|
|
92
|
-
logging_1.debugLog.info('SessionManager', 'Session recovered from storage', { sessionId: storedSession.id });
|
|
93
89
|
return storedSession.id;
|
|
94
90
|
}
|
|
95
91
|
persistSession(sessionId, lastActivity = Date.now()) {
|
|
@@ -132,7 +128,7 @@ class SessionManager extends state_manager_1.StateManager {
|
|
|
132
128
|
}
|
|
133
129
|
async startTracking() {
|
|
134
130
|
if (this.isTracking) {
|
|
135
|
-
|
|
131
|
+
(0, utils_1.log)('warn', 'Session tracking already active');
|
|
136
132
|
return;
|
|
137
133
|
}
|
|
138
134
|
const recoveredSessionId = this.recoverSession();
|
|
@@ -152,7 +148,6 @@ class SessionManager extends state_manager_1.StateManager {
|
|
|
152
148
|
this.setupSessionTimeout();
|
|
153
149
|
this.setupActivityListeners();
|
|
154
150
|
this.setupLifecycleListeners();
|
|
155
|
-
logging_1.debugLog.info('SessionManager', 'Session tracking started', { sessionId, recovered: isRecovered });
|
|
156
151
|
}
|
|
157
152
|
catch (error) {
|
|
158
153
|
this.isTracking = false;
|
|
@@ -235,11 +230,10 @@ class SessionManager extends state_manager_1.StateManager {
|
|
|
235
230
|
async endSession(reason) {
|
|
236
231
|
const sessionId = this.get('sessionId');
|
|
237
232
|
if (!sessionId) {
|
|
238
|
-
|
|
233
|
+
(0, utils_1.log)('warn', 'endSession called without active session', { data: { reason } });
|
|
239
234
|
this.resetSessionState(reason);
|
|
240
235
|
return;
|
|
241
236
|
}
|
|
242
|
-
logging_1.debugLog.info('SessionManager', 'Ending session', { sessionId, reason });
|
|
243
237
|
this.eventManager.track({
|
|
244
238
|
type: types_1.EventType.SESSION_END,
|
|
245
239
|
session_end_reason: reason,
|
|
@@ -258,9 +252,7 @@ class SessionManager extends state_manager_1.StateManager {
|
|
|
258
252
|
finalize();
|
|
259
253
|
}
|
|
260
254
|
catch (error) {
|
|
261
|
-
|
|
262
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
263
|
-
});
|
|
255
|
+
(0, utils_1.log)('warn', 'Async flush failed during session end', { error });
|
|
264
256
|
finalize();
|
|
265
257
|
}
|
|
266
258
|
}
|
|
@@ -5,7 +5,4 @@ export declare abstract class StateManager {
|
|
|
5
5
|
protected get<T extends keyof State>(key: T): State[T];
|
|
6
6
|
protected set<T extends keyof State>(key: T, value: State[T]): void;
|
|
7
7
|
protected getState(): Readonly<State>;
|
|
8
|
-
private isCriticalStateKey;
|
|
9
|
-
private shouldLog;
|
|
10
|
-
private formatLogValue;
|
|
11
8
|
}
|
|
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.StateManager = void 0;
|
|
4
4
|
exports.getGlobalState = getGlobalState;
|
|
5
5
|
exports.resetGlobalState = resetGlobalState;
|
|
6
|
-
const logging_1 = require("../utils/logging");
|
|
7
|
-
const constants_1 = require("../constants");
|
|
8
6
|
const globalState = {};
|
|
9
7
|
function getGlobalState() {
|
|
10
8
|
return globalState;
|
|
@@ -19,50 +17,10 @@ class StateManager {
|
|
|
19
17
|
return globalState[key];
|
|
20
18
|
}
|
|
21
19
|
set(key, value) {
|
|
22
|
-
|
|
23
|
-
if (key === 'config' && value) {
|
|
24
|
-
const configValue = value;
|
|
25
|
-
if (configValue) {
|
|
26
|
-
const samplingRate = configValue.samplingRate ?? constants_1.DEFAULT_SAMPLING_RATE;
|
|
27
|
-
const normalizedSamplingRate = samplingRate < 0 || samplingRate > 1 ? constants_1.DEFAULT_SAMPLING_RATE : samplingRate;
|
|
28
|
-
const hasNormalizedSampling = normalizedSamplingRate !== samplingRate;
|
|
29
|
-
if (hasNormalizedSampling) {
|
|
30
|
-
const normalizedConfig = { ...configValue, samplingRate: normalizedSamplingRate };
|
|
31
|
-
globalState[key] = normalizedConfig;
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
globalState[key] = configValue;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
globalState[key] = value;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
globalState[key] = value;
|
|
43
|
-
}
|
|
44
|
-
if (this.isCriticalStateKey(key) && this.shouldLog(oldValue, globalState[key])) {
|
|
45
|
-
logging_1.debugLog.debug('StateManager', 'State updated', {
|
|
46
|
-
key,
|
|
47
|
-
oldValue: this.formatLogValue(key, oldValue),
|
|
48
|
-
newValue: this.formatLogValue(key, globalState[key]),
|
|
49
|
-
});
|
|
50
|
-
}
|
|
20
|
+
globalState[key] = value;
|
|
51
21
|
}
|
|
52
22
|
getState() {
|
|
53
23
|
return { ...globalState };
|
|
54
24
|
}
|
|
55
|
-
isCriticalStateKey(key) {
|
|
56
|
-
return key === 'sessionId' || key === 'config' || key === 'hasStartSession';
|
|
57
|
-
}
|
|
58
|
-
shouldLog(oldValue, newValue) {
|
|
59
|
-
return oldValue !== newValue;
|
|
60
|
-
}
|
|
61
|
-
formatLogValue(key, value) {
|
|
62
|
-
if (key === 'config') {
|
|
63
|
-
return value ? '(configured)' : '(not configured)';
|
|
64
|
-
}
|
|
65
|
-
return value;
|
|
66
|
-
}
|
|
67
25
|
}
|
|
68
26
|
exports.StateManager = StateManager;
|