@tracelog/lib 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +217 -0
- package/dist/browser/tracelog.js +4040 -0
- package/dist/browser/web-vitals-CCnqwnC8.mjs +198 -0
- package/dist/cjs/api.d.ts +46 -0
- package/dist/cjs/api.js +224 -0
- package/dist/cjs/app.constants.d.ts +1 -0
- package/dist/cjs/app.constants.js +5 -0
- package/dist/cjs/app.d.ts +59 -0
- package/dist/cjs/app.js +272 -0
- package/dist/cjs/app.types.d.ts +6 -0
- package/dist/cjs/app.types.js +22 -0
- package/dist/cjs/constants/api.constants.d.ts +4 -0
- package/dist/cjs/constants/api.constants.js +18 -0
- package/dist/cjs/constants/browser.constants.d.ts +3 -0
- package/dist/cjs/constants/browser.constants.js +41 -0
- package/dist/cjs/constants/index.d.ts +8 -0
- package/dist/cjs/constants/index.js +24 -0
- package/dist/cjs/constants/initialization.constants.d.ts +40 -0
- package/dist/cjs/constants/initialization.constants.js +48 -0
- package/dist/cjs/constants/limits.constants.d.ts +25 -0
- package/dist/cjs/constants/limits.constants.js +40 -0
- package/dist/cjs/constants/security.constants.d.ts +1 -0
- package/dist/cjs/constants/security.constants.js +12 -0
- package/dist/cjs/constants/storage.constants.d.ts +9 -0
- package/dist/cjs/constants/storage.constants.js +22 -0
- package/dist/cjs/constants/timing.constants.d.ts +22 -0
- package/dist/cjs/constants/timing.constants.js +34 -0
- package/dist/cjs/constants/validation.constants.d.ts +13 -0
- package/dist/cjs/constants/validation.constants.js +31 -0
- package/dist/cjs/handlers/click.handler.d.ts +17 -0
- package/dist/cjs/handlers/click.handler.js +199 -0
- package/dist/cjs/handlers/error.handler.d.ts +15 -0
- package/dist/cjs/handlers/error.handler.js +97 -0
- package/dist/cjs/handlers/network.handler.d.ts +16 -0
- package/dist/cjs/handlers/network.handler.js +136 -0
- package/dist/cjs/handlers/page-view.handler.d.ts +15 -0
- package/dist/cjs/handlers/page-view.handler.js +83 -0
- package/dist/cjs/handlers/performance.handler.d.ts +19 -0
- package/dist/cjs/handlers/performance.handler.js +255 -0
- package/dist/cjs/handlers/scroll.handler.d.ts +16 -0
- package/dist/cjs/handlers/scroll.handler.js +138 -0
- package/dist/cjs/handlers/session.handler.d.ts +29 -0
- package/dist/cjs/handlers/session.handler.js +357 -0
- package/dist/cjs/integrations/google-analytics.integration.d.ts +18 -0
- package/dist/cjs/integrations/google-analytics.integration.js +159 -0
- package/dist/cjs/listeners/activity-listener-manager.d.ts +8 -0
- package/dist/cjs/listeners/activity-listener-manager.js +32 -0
- package/dist/cjs/listeners/index.d.ts +6 -0
- package/dist/cjs/listeners/index.js +14 -0
- package/dist/cjs/listeners/input-listener-managers.d.ts +15 -0
- package/dist/cjs/listeners/input-listener-managers.js +58 -0
- package/dist/cjs/listeners/listeners.types.d.ts +4 -0
- package/dist/cjs/listeners/listeners.types.js +2 -0
- package/dist/cjs/listeners/touch-listener-manager.d.ts +10 -0
- package/dist/cjs/listeners/touch-listener-manager.js +56 -0
- package/dist/cjs/listeners/unload-listener-manager.d.ts +8 -0
- package/dist/cjs/listeners/unload-listener-manager.js +30 -0
- package/dist/cjs/listeners/visibility-listener-manager.d.ts +12 -0
- package/dist/cjs/listeners/visibility-listener-manager.js +83 -0
- package/dist/cjs/managers/api.manager.d.ts +3 -0
- package/dist/cjs/managers/api.manager.js +14 -0
- package/dist/cjs/managers/config.manager.d.ts +7 -0
- package/dist/cjs/managers/config.manager.js +94 -0
- package/dist/cjs/managers/cross-tab-session.manager.d.ts +170 -0
- package/dist/cjs/managers/cross-tab-session.manager.js +730 -0
- package/dist/cjs/managers/event.manager.d.ts +61 -0
- package/dist/cjs/managers/event.manager.js +508 -0
- package/dist/cjs/managers/sampling.manager.d.ts +8 -0
- package/dist/cjs/managers/sampling.manager.js +53 -0
- package/dist/cjs/managers/sender.manager.d.ts +46 -0
- package/dist/cjs/managers/sender.manager.js +304 -0
- package/dist/cjs/managers/session-recovery.manager.d.ts +65 -0
- package/dist/cjs/managers/session-recovery.manager.js +237 -0
- package/dist/cjs/managers/session.manager.d.ts +72 -0
- package/dist/cjs/managers/session.manager.js +587 -0
- package/dist/cjs/managers/state.manager.d.ts +5 -0
- package/dist/cjs/managers/state.manager.js +23 -0
- package/dist/cjs/managers/storage.manager.d.ts +10 -0
- package/dist/cjs/managers/storage.manager.js +81 -0
- package/dist/cjs/managers/tags.manager.d.ts +12 -0
- package/dist/cjs/managers/tags.manager.js +289 -0
- package/dist/cjs/managers/user.manager.d.ts +7 -0
- package/dist/cjs/managers/user.manager.js +22 -0
- package/dist/cjs/public-api.d.ts +1 -0
- package/dist/cjs/public-api.js +37 -0
- package/dist/cjs/types/api.types.d.ts +21 -0
- package/dist/cjs/types/api.types.js +25 -0
- package/dist/cjs/types/common.types.d.ts +1 -0
- package/dist/cjs/types/common.types.js +2 -0
- package/dist/cjs/types/config.types.d.ts +104 -0
- package/dist/cjs/types/config.types.js +2 -0
- package/dist/cjs/types/device.types.d.ts +6 -0
- package/dist/cjs/types/device.types.js +10 -0
- package/dist/cjs/types/event.types.d.ts +104 -0
- package/dist/cjs/types/event.types.js +25 -0
- package/dist/cjs/types/index.d.ts +13 -0
- package/dist/cjs/types/index.js +29 -0
- package/dist/cjs/types/log.types.d.ts +4 -0
- package/dist/cjs/types/log.types.js +2 -0
- package/dist/cjs/types/mode.types.d.ts +7 -0
- package/dist/cjs/types/mode.types.js +11 -0
- package/dist/cjs/types/queue.types.d.ts +23 -0
- package/dist/cjs/types/queue.types.js +2 -0
- package/dist/cjs/types/session.types.d.ts +65 -0
- package/dist/cjs/types/session.types.js +2 -0
- package/dist/cjs/types/state.types.d.ts +12 -0
- package/dist/cjs/types/state.types.js +2 -0
- package/dist/cjs/types/tag.types.d.ts +43 -0
- package/dist/cjs/types/tag.types.js +31 -0
- package/dist/cjs/types/validation-error.types.d.ts +42 -0
- package/dist/cjs/types/validation-error.types.js +68 -0
- package/dist/cjs/types/web-vitals.types.d.ts +6 -0
- package/dist/cjs/types/web-vitals.types.js +2 -0
- package/dist/cjs/types/window.types.d.ts +17 -0
- package/dist/cjs/types/window.types.js +2 -0
- package/dist/cjs/utils/browser/device-detector.utils.d.ts +6 -0
- package/dist/cjs/utils/browser/device-detector.utils.js +71 -0
- package/dist/cjs/utils/browser/index.d.ts +2 -0
- package/dist/cjs/utils/browser/index.js +18 -0
- package/dist/cjs/utils/browser/utm-params.utils.d.ts +6 -0
- package/dist/cjs/utils/browser/utm-params.utils.js +37 -0
- package/dist/cjs/utils/data/index.d.ts +1 -0
- package/dist/cjs/utils/data/index.js +17 -0
- package/dist/cjs/utils/data/uuid.utils.d.ts +5 -0
- package/dist/cjs/utils/data/uuid.utils.js +18 -0
- package/dist/cjs/utils/index.d.ts +6 -0
- package/dist/cjs/utils/index.js +22 -0
- package/dist/cjs/utils/logging/debug-logger.utils.d.ts +56 -0
- package/dist/cjs/utils/logging/debug-logger.utils.js +139 -0
- package/dist/cjs/utils/logging/index.d.ts +1 -0
- package/dist/cjs/utils/logging/index.js +5 -0
- package/dist/cjs/utils/network/index.d.ts +1 -0
- package/dist/cjs/utils/network/index.js +17 -0
- package/dist/cjs/utils/network/url.utils.d.ts +20 -0
- package/dist/cjs/utils/network/url.utils.js +172 -0
- package/dist/cjs/utils/security/index.d.ts +1 -0
- package/dist/cjs/utils/security/index.js +17 -0
- package/dist/cjs/utils/security/sanitize.utils.d.ts +32 -0
- package/dist/cjs/utils/security/sanitize.utils.js +319 -0
- package/dist/cjs/utils/validations/config-validations.utils.d.ts +42 -0
- package/dist/cjs/utils/validations/config-validations.utils.js +297 -0
- package/dist/cjs/utils/validations/event-validations.utils.d.ts +12 -0
- package/dist/cjs/utils/validations/event-validations.utils.js +30 -0
- package/dist/cjs/utils/validations/index.d.ts +5 -0
- package/dist/cjs/utils/validations/index.js +21 -0
- package/dist/cjs/utils/validations/metadata-validations.utils.d.ts +22 -0
- package/dist/cjs/utils/validations/metadata-validations.utils.js +115 -0
- package/dist/cjs/utils/validations/type-guards.utils.d.ts +6 -0
- package/dist/cjs/utils/validations/type-guards.utils.js +31 -0
- package/dist/cjs/utils/validations/url-validations.utils.d.ts +15 -0
- package/dist/cjs/utils/validations/url-validations.utils.js +47 -0
- package/dist/esm/api.d.ts +46 -0
- package/dist/esm/api.js +183 -0
- package/dist/esm/app.constants.d.ts +1 -0
- package/dist/esm/app.constants.js +1 -0
- package/dist/esm/app.d.ts +59 -0
- package/dist/esm/app.js +268 -0
- package/dist/esm/app.types.d.ts +6 -0
- package/dist/esm/app.types.js +6 -0
- package/dist/esm/constants/api.constants.d.ts +4 -0
- package/dist/esm/constants/api.constants.js +14 -0
- package/dist/esm/constants/browser.constants.d.ts +3 -0
- package/dist/esm/constants/browser.constants.js +38 -0
- package/dist/esm/constants/index.d.ts +8 -0
- package/dist/esm/constants/index.js +8 -0
- package/dist/esm/constants/initialization.constants.d.ts +40 -0
- package/dist/esm/constants/initialization.constants.js +45 -0
- package/dist/esm/constants/limits.constants.d.ts +25 -0
- package/dist/esm/constants/limits.constants.js +37 -0
- package/dist/esm/constants/security.constants.d.ts +1 -0
- package/dist/esm/constants/security.constants.js +9 -0
- package/dist/esm/constants/storage.constants.d.ts +9 -0
- package/dist/esm/constants/storage.constants.js +11 -0
- package/dist/esm/constants/timing.constants.d.ts +22 -0
- package/dist/esm/constants/timing.constants.js +31 -0
- package/dist/esm/constants/validation.constants.d.ts +13 -0
- package/dist/esm/constants/validation.constants.js +28 -0
- package/dist/esm/handlers/click.handler.d.ts +17 -0
- package/dist/esm/handlers/click.handler.js +195 -0
- package/dist/esm/handlers/error.handler.d.ts +15 -0
- package/dist/esm/handlers/error.handler.js +93 -0
- package/dist/esm/handlers/network.handler.d.ts +16 -0
- package/dist/esm/handlers/network.handler.js +132 -0
- package/dist/esm/handlers/page-view.handler.d.ts +15 -0
- package/dist/esm/handlers/page-view.handler.js +79 -0
- package/dist/esm/handlers/performance.handler.d.ts +19 -0
- package/dist/esm/handlers/performance.handler.js +218 -0
- package/dist/esm/handlers/scroll.handler.d.ts +16 -0
- package/dist/esm/handlers/scroll.handler.js +134 -0
- package/dist/esm/handlers/session.handler.d.ts +29 -0
- package/dist/esm/handlers/session.handler.js +353 -0
- package/dist/esm/integrations/google-analytics.integration.d.ts +18 -0
- package/dist/esm/integrations/google-analytics.integration.js +155 -0
- package/dist/esm/listeners/activity-listener-manager.d.ts +8 -0
- package/dist/esm/listeners/activity-listener-manager.js +28 -0
- package/dist/esm/listeners/index.d.ts +6 -0
- package/dist/esm/listeners/index.js +5 -0
- package/dist/esm/listeners/input-listener-managers.d.ts +15 -0
- package/dist/esm/listeners/input-listener-managers.js +53 -0
- package/dist/esm/listeners/listeners.types.d.ts +4 -0
- package/dist/esm/listeners/listeners.types.js +1 -0
- package/dist/esm/listeners/touch-listener-manager.d.ts +10 -0
- package/dist/esm/listeners/touch-listener-manager.js +52 -0
- package/dist/esm/listeners/unload-listener-manager.d.ts +8 -0
- package/dist/esm/listeners/unload-listener-manager.js +26 -0
- package/dist/esm/listeners/visibility-listener-manager.d.ts +12 -0
- package/dist/esm/listeners/visibility-listener-manager.js +79 -0
- package/dist/esm/managers/api.manager.d.ts +3 -0
- package/dist/esm/managers/api.manager.js +10 -0
- package/dist/esm/managers/config.manager.d.ts +7 -0
- package/dist/esm/managers/config.manager.js +90 -0
- package/dist/esm/managers/cross-tab-session.manager.d.ts +170 -0
- package/dist/esm/managers/cross-tab-session.manager.js +726 -0
- package/dist/esm/managers/event.manager.d.ts +61 -0
- package/dist/esm/managers/event.manager.js +504 -0
- package/dist/esm/managers/sampling.manager.d.ts +8 -0
- package/dist/esm/managers/sampling.manager.js +49 -0
- package/dist/esm/managers/sender.manager.d.ts +46 -0
- package/dist/esm/managers/sender.manager.js +300 -0
- package/dist/esm/managers/session-recovery.manager.d.ts +65 -0
- package/dist/esm/managers/session-recovery.manager.js +233 -0
- package/dist/esm/managers/session.manager.d.ts +72 -0
- package/dist/esm/managers/session.manager.js +583 -0
- package/dist/esm/managers/state.manager.d.ts +5 -0
- package/dist/esm/managers/state.manager.js +19 -0
- package/dist/esm/managers/storage.manager.d.ts +10 -0
- package/dist/esm/managers/storage.manager.js +77 -0
- package/dist/esm/managers/tags.manager.d.ts +12 -0
- package/dist/esm/managers/tags.manager.js +285 -0
- package/dist/esm/managers/user.manager.d.ts +7 -0
- package/dist/esm/managers/user.manager.js +18 -0
- package/dist/esm/public-api.d.ts +1 -0
- package/dist/esm/public-api.js +1 -0
- package/dist/esm/types/api.types.d.ts +21 -0
- package/dist/esm/types/api.types.js +22 -0
- package/dist/esm/types/common.types.d.ts +1 -0
- package/dist/esm/types/common.types.js +1 -0
- package/dist/esm/types/config.types.d.ts +104 -0
- package/dist/esm/types/config.types.js +1 -0
- package/dist/esm/types/device.types.d.ts +6 -0
- package/dist/esm/types/device.types.js +7 -0
- package/dist/esm/types/event.types.d.ts +104 -0
- package/dist/esm/types/event.types.js +22 -0
- package/dist/esm/types/index.d.ts +13 -0
- package/dist/esm/types/index.js +13 -0
- package/dist/esm/types/log.types.d.ts +4 -0
- package/dist/esm/types/log.types.js +1 -0
- package/dist/esm/types/mode.types.d.ts +7 -0
- package/dist/esm/types/mode.types.js +8 -0
- package/dist/esm/types/queue.types.d.ts +23 -0
- package/dist/esm/types/queue.types.js +1 -0
- package/dist/esm/types/session.types.d.ts +65 -0
- package/dist/esm/types/session.types.js +1 -0
- package/dist/esm/types/state.types.d.ts +12 -0
- package/dist/esm/types/state.types.js +1 -0
- package/dist/esm/types/tag.types.d.ts +43 -0
- package/dist/esm/types/tag.types.js +28 -0
- package/dist/esm/types/validation-error.types.d.ts +42 -0
- package/dist/esm/types/validation-error.types.js +59 -0
- package/dist/esm/types/web-vitals.types.d.ts +6 -0
- package/dist/esm/types/web-vitals.types.js +1 -0
- package/dist/esm/types/window.types.d.ts +17 -0
- package/dist/esm/types/window.types.js +1 -0
- package/dist/esm/utils/browser/device-detector.utils.d.ts +6 -0
- package/dist/esm/utils/browser/device-detector.utils.js +67 -0
- package/dist/esm/utils/browser/index.d.ts +2 -0
- package/dist/esm/utils/browser/index.js +2 -0
- package/dist/esm/utils/browser/utm-params.utils.d.ts +6 -0
- package/dist/esm/utils/browser/utm-params.utils.js +33 -0
- package/dist/esm/utils/data/index.d.ts +1 -0
- package/dist/esm/utils/data/index.js +1 -0
- package/dist/esm/utils/data/uuid.utils.d.ts +5 -0
- package/dist/esm/utils/data/uuid.utils.js +14 -0
- package/dist/esm/utils/index.d.ts +6 -0
- package/dist/esm/utils/index.js +6 -0
- package/dist/esm/utils/logging/debug-logger.utils.d.ts +56 -0
- package/dist/esm/utils/logging/debug-logger.utils.js +136 -0
- package/dist/esm/utils/logging/index.d.ts +1 -0
- package/dist/esm/utils/logging/index.js +1 -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.d.ts +20 -0
- package/dist/esm/utils/network/url.utils.js +166 -0
- package/dist/esm/utils/security/index.d.ts +1 -0
- package/dist/esm/utils/security/index.js +1 -0
- package/dist/esm/utils/security/sanitize.utils.d.ts +32 -0
- package/dist/esm/utils/security/sanitize.utils.js +311 -0
- package/dist/esm/utils/validations/config-validations.utils.d.ts +42 -0
- package/dist/esm/utils/validations/config-validations.utils.js +289 -0
- package/dist/esm/utils/validations/event-validations.utils.d.ts +12 -0
- package/dist/esm/utils/validations/event-validations.utils.js +26 -0
- package/dist/esm/utils/validations/index.d.ts +5 -0
- package/dist/esm/utils/validations/index.js +5 -0
- package/dist/esm/utils/validations/metadata-validations.utils.d.ts +22 -0
- package/dist/esm/utils/validations/metadata-validations.utils.js +110 -0
- package/dist/esm/utils/validations/type-guards.utils.d.ts +6 -0
- package/dist/esm/utils/validations/type-guards.utils.js +27 -0
- package/dist/esm/utils/validations/url-validations.utils.d.ts +15 -0
- package/dist/esm/utils/validations/url-validations.utils.js +42 -0
- package/package.json +80 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { StateManager } from '../../managers/state.manager';
|
|
2
|
+
/**
|
|
3
|
+
* Debug logger class that extends StateManager for clean access to global state
|
|
4
|
+
*/
|
|
5
|
+
class DebugLogger extends StateManager {
|
|
6
|
+
/**
|
|
7
|
+
* Client-facing error - Configuration/usage errors by the client
|
|
8
|
+
* Console: qa and debug modes | Events: NODE_ENV=dev
|
|
9
|
+
*/
|
|
10
|
+
clientError(namespace, message, data) {
|
|
11
|
+
this.logMessage('CLIENT_ERROR', namespace, message, data);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Client-facing warning - Configuration/usage warnings by the client
|
|
15
|
+
* Console: qa and debug modes | Events: NODE_ENV=dev
|
|
16
|
+
*/
|
|
17
|
+
clientWarn(namespace, message, data) {
|
|
18
|
+
this.logMessage('CLIENT_WARN', namespace, message, data);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* General operational information
|
|
22
|
+
* Console: qa and debug modes | Events: NODE_ENV=dev
|
|
23
|
+
*/
|
|
24
|
+
info(namespace, message, data) {
|
|
25
|
+
this.logMessage('INFO', namespace, message, data);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Internal library errors
|
|
29
|
+
* Console: debug mode only | Events: NODE_ENV=dev
|
|
30
|
+
*/
|
|
31
|
+
error(namespace, message, data) {
|
|
32
|
+
this.logMessage('ERROR', namespace, message, data);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Internal library warnings
|
|
36
|
+
* Console: debug mode only | Events: NODE_ENV=dev
|
|
37
|
+
*/
|
|
38
|
+
warn(namespace, message, data) {
|
|
39
|
+
this.logMessage('WARN', namespace, message, data);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Strategic debug information
|
|
43
|
+
* Console: debug mode only | Events: NODE_ENV=dev
|
|
44
|
+
*/
|
|
45
|
+
debug(namespace, message, data) {
|
|
46
|
+
this.logMessage('DEBUG', namespace, message, data);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Detailed trace information
|
|
50
|
+
* Console: debug mode only | Events: NODE_ENV=dev
|
|
51
|
+
*/
|
|
52
|
+
verbose(namespace, message, data) {
|
|
53
|
+
this.logMessage('VERBOSE', namespace, message, data);
|
|
54
|
+
}
|
|
55
|
+
getCurrentMode() {
|
|
56
|
+
try {
|
|
57
|
+
return this.get('config')?.mode;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
shouldShowLog(level) {
|
|
64
|
+
const mode = this.getCurrentMode();
|
|
65
|
+
switch (mode) {
|
|
66
|
+
case 'qa':
|
|
67
|
+
return ['INFO', 'CLIENT_ERROR', 'CLIENT_WARN'].includes(level);
|
|
68
|
+
case 'debug':
|
|
69
|
+
return true;
|
|
70
|
+
default:
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
formatMessage(namespace, message) {
|
|
75
|
+
return `[TraceLog:${namespace}] ${message}`;
|
|
76
|
+
}
|
|
77
|
+
getConsoleMethod(level) {
|
|
78
|
+
switch (level) {
|
|
79
|
+
case 'CLIENT_ERROR':
|
|
80
|
+
case 'ERROR':
|
|
81
|
+
return 'error';
|
|
82
|
+
case 'CLIENT_WARN':
|
|
83
|
+
case 'WARN':
|
|
84
|
+
return 'warn';
|
|
85
|
+
case 'INFO':
|
|
86
|
+
case 'DEBUG':
|
|
87
|
+
case 'VERBOSE':
|
|
88
|
+
default:
|
|
89
|
+
return 'log';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
logMessage(level, namespace, message, data) {
|
|
93
|
+
if (!this.shouldShowLog(level)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const formattedMessage = this.formatMessage(namespace, message);
|
|
97
|
+
const consoleMethod = this.getConsoleMethod(level);
|
|
98
|
+
if (data !== undefined) {
|
|
99
|
+
console[consoleMethod](formattedMessage, data);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console[consoleMethod](formattedMessage);
|
|
103
|
+
}
|
|
104
|
+
if (process.env.NODE_ENV === 'dev') {
|
|
105
|
+
this.dispatchEvent(level, namespace, message, data);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Dispatches tracelog:log events for E2E testing and development debugging
|
|
110
|
+
*/
|
|
111
|
+
dispatchEvent(level, namespace, message, data) {
|
|
112
|
+
if (typeof window === 'undefined' || typeof CustomEvent === 'undefined') {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const event = new CustomEvent('tracelog:log', {
|
|
117
|
+
detail: {
|
|
118
|
+
timestamp: new Date().toISOString(),
|
|
119
|
+
level,
|
|
120
|
+
namespace,
|
|
121
|
+
message,
|
|
122
|
+
data,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
window.dispatchEvent(event);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
console.log(`[TraceLog:${namespace}] ${message}`, data);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Singleton debug logger instance
|
|
134
|
+
* Provides the same API as before: debugLog.clientError(), debugLog.info(), etc.
|
|
135
|
+
*/
|
|
136
|
+
export const debugLog = new DebugLogger();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { debugLog } from './debug-logger.utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { debugLog } from './debug-logger.utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './url.utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './url.utils';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates an API URL based on project ID and current domain
|
|
3
|
+
* @param id - The project ID
|
|
4
|
+
* @returns The generated API URL
|
|
5
|
+
*/
|
|
6
|
+
export declare const getApiUrl: (id: string, allowHttp?: boolean) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Normalizes a URL by removing sensitive query parameters
|
|
9
|
+
* @param url - The URL to normalize
|
|
10
|
+
* @param sensitiveQueryParams - Array of parameter names to remove
|
|
11
|
+
* @returns The normalized URL
|
|
12
|
+
*/
|
|
13
|
+
export declare const normalizeUrl: (url: string, sensitiveQueryParams?: string[]) => string;
|
|
14
|
+
/**
|
|
15
|
+
* Checks if a URL path should be excluded from tracking
|
|
16
|
+
* @param url - The URL to check
|
|
17
|
+
* @param excludedPaths - Array of patterns to match against
|
|
18
|
+
* @returns True if the URL should be excluded
|
|
19
|
+
*/
|
|
20
|
+
export declare const isUrlPathExcluded: (url: string, excludedPaths?: string[]) => boolean;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { isValidUrl } from '../validations';
|
|
2
|
+
import { debugLog } from '../logging';
|
|
3
|
+
/**
|
|
4
|
+
* Generates an API URL based on project ID and current domain
|
|
5
|
+
* @param id - The project ID
|
|
6
|
+
* @returns The generated API URL
|
|
7
|
+
*/
|
|
8
|
+
export const getApiUrl = (id, allowHttp = false) => {
|
|
9
|
+
debugLog.debug('URLUtils', 'Generating API URL', { projectId: id, allowHttp });
|
|
10
|
+
const url = new URL(window.location.href);
|
|
11
|
+
const host = url.hostname;
|
|
12
|
+
const parts = host.split('.');
|
|
13
|
+
if (parts.length === 0) {
|
|
14
|
+
debugLog.clientError('URLUtils', 'Invalid hostname - no domain parts found', { hostname: host });
|
|
15
|
+
throw new Error('Invalid URL');
|
|
16
|
+
}
|
|
17
|
+
const cleanDomain = parts.slice(-2).join('.');
|
|
18
|
+
const protocol = allowHttp && url.protocol === 'http:' ? 'http' : 'https';
|
|
19
|
+
const apiUrl = `${protocol}://${id}.${cleanDomain}`;
|
|
20
|
+
debugLog.debug('URLUtils', 'Generated API URL', {
|
|
21
|
+
originalUrl: window.location.href,
|
|
22
|
+
hostname: host,
|
|
23
|
+
domainParts: parts.length,
|
|
24
|
+
cleanDomain,
|
|
25
|
+
protocol,
|
|
26
|
+
generatedUrl: apiUrl,
|
|
27
|
+
});
|
|
28
|
+
const isValid = isValidUrl(apiUrl, allowHttp);
|
|
29
|
+
if (!isValid) {
|
|
30
|
+
debugLog.clientError('URLUtils', 'Generated API URL failed validation', {
|
|
31
|
+
apiUrl,
|
|
32
|
+
allowHttp,
|
|
33
|
+
});
|
|
34
|
+
throw new Error('Invalid URL');
|
|
35
|
+
}
|
|
36
|
+
debugLog.debug('URLUtils', 'API URL generation completed successfully', { apiUrl });
|
|
37
|
+
return apiUrl;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Normalizes a URL by removing sensitive query parameters
|
|
41
|
+
* @param url - The URL to normalize
|
|
42
|
+
* @param sensitiveQueryParams - Array of parameter names to remove
|
|
43
|
+
* @returns The normalized URL
|
|
44
|
+
*/
|
|
45
|
+
export const normalizeUrl = (url, sensitiveQueryParams = []) => {
|
|
46
|
+
debugLog.debug('URLUtils', 'Normalizing URL', {
|
|
47
|
+
urlLength: url.length,
|
|
48
|
+
sensitiveParamsCount: sensitiveQueryParams.length,
|
|
49
|
+
});
|
|
50
|
+
try {
|
|
51
|
+
const urlObject = new URL(url);
|
|
52
|
+
const searchParams = urlObject.searchParams;
|
|
53
|
+
const originalParamCount = Array.from(searchParams.keys()).length;
|
|
54
|
+
let hasChanged = false;
|
|
55
|
+
const removedParams = [];
|
|
56
|
+
sensitiveQueryParams.forEach((param) => {
|
|
57
|
+
if (searchParams.has(param)) {
|
|
58
|
+
searchParams.delete(param);
|
|
59
|
+
hasChanged = true;
|
|
60
|
+
removedParams.push(param);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
if (hasChanged) {
|
|
64
|
+
debugLog.debug('URLUtils', 'Sensitive parameters removed from URL', {
|
|
65
|
+
removedParams,
|
|
66
|
+
originalParamCount,
|
|
67
|
+
finalParamCount: Array.from(searchParams.keys()).length,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (!hasChanged && url.includes('?')) {
|
|
71
|
+
debugLog.debug('URLUtils', 'URL normalization - no changes needed');
|
|
72
|
+
return url;
|
|
73
|
+
}
|
|
74
|
+
urlObject.search = searchParams.toString();
|
|
75
|
+
const result = urlObject.toString();
|
|
76
|
+
debugLog.debug('URLUtils', 'URL normalization completed', {
|
|
77
|
+
hasChanged,
|
|
78
|
+
originalLength: url.length,
|
|
79
|
+
normalizedLength: result.length,
|
|
80
|
+
});
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
debugLog.warn('URLUtils', 'URL normalization failed, returning original', {
|
|
85
|
+
url: url.slice(0, 100),
|
|
86
|
+
error: error instanceof Error ? error.message : error,
|
|
87
|
+
});
|
|
88
|
+
return url;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Checks if a URL path should be excluded from tracking
|
|
93
|
+
* @param url - The URL to check
|
|
94
|
+
* @param excludedPaths - Array of patterns to match against
|
|
95
|
+
* @returns True if the URL should be excluded
|
|
96
|
+
*/
|
|
97
|
+
export const isUrlPathExcluded = (url, excludedPaths = []) => {
|
|
98
|
+
debugLog.debug('URLUtils', 'Checking if URL path is excluded', {
|
|
99
|
+
urlLength: url.length,
|
|
100
|
+
excludedPathsCount: excludedPaths.length,
|
|
101
|
+
});
|
|
102
|
+
if (excludedPaths.length === 0) {
|
|
103
|
+
debugLog.debug('URLUtils', 'No excluded paths configured');
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
let path;
|
|
107
|
+
try {
|
|
108
|
+
path = new URL(url, window.location.origin).pathname;
|
|
109
|
+
debugLog.debug('URLUtils', 'Extracted path from URL', { path });
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
debugLog.warn('URLUtils', 'Failed to parse URL for path exclusion check', {
|
|
113
|
+
url: url.slice(0, 100),
|
|
114
|
+
error: error instanceof Error ? error.message : error,
|
|
115
|
+
});
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
const isRegularExpression = (value) => typeof value === 'object' && value !== undefined && typeof value.test === 'function';
|
|
119
|
+
const escapeRegexString = (string_) => string_.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&');
|
|
120
|
+
const wildcardToRegex = (string_) => new RegExp('^' +
|
|
121
|
+
string_
|
|
122
|
+
.split('*')
|
|
123
|
+
.map((element) => escapeRegexString(element))
|
|
124
|
+
.join('.+') +
|
|
125
|
+
'$');
|
|
126
|
+
const matchedPattern = excludedPaths.find((pattern) => {
|
|
127
|
+
try {
|
|
128
|
+
if (isRegularExpression(pattern)) {
|
|
129
|
+
const matches = pattern.test(path);
|
|
130
|
+
if (matches) {
|
|
131
|
+
debugLog.debug('URLUtils', 'Path matched regex pattern', { path, pattern: pattern.toString() });
|
|
132
|
+
}
|
|
133
|
+
return matches;
|
|
134
|
+
}
|
|
135
|
+
if (pattern.includes('*')) {
|
|
136
|
+
const regex = wildcardToRegex(pattern);
|
|
137
|
+
const matches = regex.test(path);
|
|
138
|
+
if (matches) {
|
|
139
|
+
debugLog.debug('URLUtils', 'Path matched wildcard pattern', { path, pattern, regex: regex.toString() });
|
|
140
|
+
}
|
|
141
|
+
return matches;
|
|
142
|
+
}
|
|
143
|
+
const matches = pattern === path;
|
|
144
|
+
if (matches) {
|
|
145
|
+
debugLog.debug('URLUtils', 'Path matched exact pattern', { path, pattern });
|
|
146
|
+
}
|
|
147
|
+
return matches;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
debugLog.warn('URLUtils', 'Error testing exclusion pattern', {
|
|
151
|
+
pattern,
|
|
152
|
+
path,
|
|
153
|
+
error: error instanceof Error ? error.message : error,
|
|
154
|
+
});
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
const isExcluded = !!matchedPattern;
|
|
159
|
+
debugLog.debug('URLUtils', 'URL path exclusion check completed', {
|
|
160
|
+
path,
|
|
161
|
+
isExcluded,
|
|
162
|
+
matchedPattern: matchedPattern ?? null,
|
|
163
|
+
totalPatternsChecked: excludedPaths.length,
|
|
164
|
+
});
|
|
165
|
+
return isExcluded;
|
|
166
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './sanitize.utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './sanitize.utils';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { MetadataType } from '../../types/common.types';
|
|
2
|
+
import { ApiConfig } from '../../types/config.types';
|
|
3
|
+
/**
|
|
4
|
+
* Sanitizes a string value to prevent XSS attacks
|
|
5
|
+
* @param value - The string to sanitize
|
|
6
|
+
* @returns The sanitized string
|
|
7
|
+
*/
|
|
8
|
+
export declare const sanitizeString: (value: string) => string;
|
|
9
|
+
/**
|
|
10
|
+
* Sanitizes a path string for route exclusion checks
|
|
11
|
+
* @param value - The path string to sanitize
|
|
12
|
+
* @returns The sanitized path string
|
|
13
|
+
*/
|
|
14
|
+
export declare const sanitizePathString: (value: string) => string;
|
|
15
|
+
/**
|
|
16
|
+
* Sanitizes API configuration data with strict validation
|
|
17
|
+
* @param data - The API config data to sanitize
|
|
18
|
+
* @returns The sanitized API config
|
|
19
|
+
*/
|
|
20
|
+
export declare const sanitizeApiConfig: (data: unknown) => ApiConfig;
|
|
21
|
+
/**
|
|
22
|
+
* Sanitizes user metadata for custom events
|
|
23
|
+
* @param metadata - The metadata to sanitize
|
|
24
|
+
* @returns The sanitized metadata
|
|
25
|
+
*/
|
|
26
|
+
export declare const sanitizeMetadata: (metadata: unknown) => Record<string, MetadataType>;
|
|
27
|
+
/**
|
|
28
|
+
* Sanitizes URL strings for tracking
|
|
29
|
+
* @param url - The URL to sanitize
|
|
30
|
+
* @returns The sanitized URL
|
|
31
|
+
*/
|
|
32
|
+
export declare const sanitizeUrl: (url: string) => string;
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { ALLOWED_API_CONFIG_KEYS, MAX_ARRAY_LENGTH, MAX_OBJECT_DEPTH, MAX_STRING_LENGTH, XSS_PATTERNS, } from '../../constants';
|
|
2
|
+
import { debugLog } from '../logging';
|
|
3
|
+
/**
|
|
4
|
+
* Sanitizes a string value to prevent XSS attacks
|
|
5
|
+
* @param value - The string to sanitize
|
|
6
|
+
* @returns The sanitized string
|
|
7
|
+
*/
|
|
8
|
+
export const sanitizeString = (value) => {
|
|
9
|
+
if (!value || typeof value !== 'string' || value.trim().length === 0) {
|
|
10
|
+
debugLog.debug('Sanitize', 'String sanitization skipped - empty or invalid input', { value, type: typeof value });
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
const originalLength = value.length;
|
|
14
|
+
let sanitized = value;
|
|
15
|
+
// Limit string length
|
|
16
|
+
if (value.length > MAX_STRING_LENGTH) {
|
|
17
|
+
sanitized = value.slice(0, Math.max(0, MAX_STRING_LENGTH));
|
|
18
|
+
debugLog.warn('Sanitize', 'String truncated due to length limit', {
|
|
19
|
+
originalLength,
|
|
20
|
+
maxLength: MAX_STRING_LENGTH,
|
|
21
|
+
truncatedLength: sanitized.length,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
// Remove potential XSS patterns
|
|
25
|
+
let xssPatternMatches = 0;
|
|
26
|
+
for (const pattern of XSS_PATTERNS) {
|
|
27
|
+
const beforeReplace = sanitized;
|
|
28
|
+
sanitized = sanitized.replace(pattern, '');
|
|
29
|
+
if (beforeReplace !== sanitized) {
|
|
30
|
+
xssPatternMatches++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (xssPatternMatches > 0) {
|
|
34
|
+
debugLog.warn('Sanitize', 'XSS patterns detected and removed', {
|
|
35
|
+
patternMatches: xssPatternMatches,
|
|
36
|
+
originalValue: value.slice(0, 100), // Log first 100 chars for debugging
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Basic HTML entity encoding for critical characters
|
|
40
|
+
sanitized = sanitized
|
|
41
|
+
.replaceAll('&', '&')
|
|
42
|
+
.replaceAll('<', '<')
|
|
43
|
+
.replaceAll('>', '>')
|
|
44
|
+
.replaceAll('"', '"')
|
|
45
|
+
.replaceAll("'", ''')
|
|
46
|
+
.replaceAll('/', '/');
|
|
47
|
+
const result = sanitized.trim();
|
|
48
|
+
if (originalLength > 50 || xssPatternMatches > 0) {
|
|
49
|
+
debugLog.debug('Sanitize', 'String sanitization completed', {
|
|
50
|
+
originalLength,
|
|
51
|
+
sanitizedLength: result.length,
|
|
52
|
+
xssPatternMatches,
|
|
53
|
+
wasTruncated: originalLength > MAX_STRING_LENGTH,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Sanitizes a path string for route exclusion checks
|
|
60
|
+
* @param value - The path string to sanitize
|
|
61
|
+
* @returns The sanitized path string
|
|
62
|
+
*/
|
|
63
|
+
export const sanitizePathString = (value) => {
|
|
64
|
+
if (typeof value !== 'string') {
|
|
65
|
+
return '';
|
|
66
|
+
}
|
|
67
|
+
if (value.length > MAX_STRING_LENGTH) {
|
|
68
|
+
value = value.slice(0, Math.max(0, MAX_STRING_LENGTH));
|
|
69
|
+
}
|
|
70
|
+
let sanitized = value;
|
|
71
|
+
for (const pattern of XSS_PATTERNS) {
|
|
72
|
+
sanitized = sanitized.replace(pattern, '');
|
|
73
|
+
}
|
|
74
|
+
sanitized = sanitized
|
|
75
|
+
.replaceAll('&', '&')
|
|
76
|
+
.replaceAll('<', '<')
|
|
77
|
+
.replaceAll('>', '>')
|
|
78
|
+
.replaceAll('"', '"')
|
|
79
|
+
.replaceAll("'", ''');
|
|
80
|
+
return sanitized.trim();
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Sanitizes any value recursively with depth protection
|
|
84
|
+
* @param value - The value to sanitize
|
|
85
|
+
* @param depth - Current recursion depth
|
|
86
|
+
* @returns The sanitized value
|
|
87
|
+
*/
|
|
88
|
+
const sanitizeValue = (value, depth = 0) => {
|
|
89
|
+
// Prevent infinite recursion
|
|
90
|
+
if (depth > MAX_OBJECT_DEPTH) {
|
|
91
|
+
debugLog.warn('Sanitize', 'Maximum object depth exceeded during sanitization', {
|
|
92
|
+
depth,
|
|
93
|
+
maxDepth: MAX_OBJECT_DEPTH,
|
|
94
|
+
});
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
if (value === null || value === undefined) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (typeof value === 'string') {
|
|
101
|
+
return sanitizeString(value);
|
|
102
|
+
}
|
|
103
|
+
if (typeof value === 'number') {
|
|
104
|
+
if (!Number.isFinite(value) || value < -Number.MAX_SAFE_INTEGER || value > Number.MAX_SAFE_INTEGER) {
|
|
105
|
+
debugLog.warn('Sanitize', 'Invalid number sanitized to 0', { value, isFinite: Number.isFinite(value) });
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
if (typeof value === 'boolean') {
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(value)) {
|
|
114
|
+
const originalLength = value.length;
|
|
115
|
+
const limitedArray = value.slice(0, MAX_ARRAY_LENGTH);
|
|
116
|
+
if (originalLength > MAX_ARRAY_LENGTH) {
|
|
117
|
+
debugLog.warn('Sanitize', 'Array truncated due to length limit', {
|
|
118
|
+
originalLength,
|
|
119
|
+
maxLength: MAX_ARRAY_LENGTH,
|
|
120
|
+
depth,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const sanitizedArray = limitedArray.map((item) => sanitizeValue(item, depth + 1)).filter((item) => item !== null);
|
|
124
|
+
if (originalLength > 0 && sanitizedArray.length === 0) {
|
|
125
|
+
debugLog.warn('Sanitize', 'All array items were filtered out during sanitization', { originalLength, depth });
|
|
126
|
+
}
|
|
127
|
+
return sanitizedArray;
|
|
128
|
+
}
|
|
129
|
+
if (typeof value === 'object') {
|
|
130
|
+
const sanitizedObject = {};
|
|
131
|
+
const entries = Object.entries(value);
|
|
132
|
+
const originalKeysCount = entries.length;
|
|
133
|
+
const limitedEntries = entries.slice(0, 20);
|
|
134
|
+
if (originalKeysCount > 20) {
|
|
135
|
+
debugLog.warn('Sanitize', 'Object keys truncated due to limit', {
|
|
136
|
+
originalKeys: originalKeysCount,
|
|
137
|
+
maxKeys: 20,
|
|
138
|
+
depth,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
let filteredKeysCount = 0;
|
|
142
|
+
for (const [key, value_] of limitedEntries) {
|
|
143
|
+
const sanitizedKey = sanitizeString(key);
|
|
144
|
+
if (sanitizedKey) {
|
|
145
|
+
const sanitizedValue = sanitizeValue(value_, depth + 1);
|
|
146
|
+
if (sanitizedValue !== null) {
|
|
147
|
+
sanitizedObject[sanitizedKey] = sanitizedValue;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
filteredKeysCount++;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
filteredKeysCount++;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (filteredKeysCount > 0) {
|
|
158
|
+
debugLog.debug('Sanitize', 'Object properties filtered during sanitization', {
|
|
159
|
+
filteredKeysCount,
|
|
160
|
+
remainingKeys: Object.keys(sanitizedObject).length,
|
|
161
|
+
depth,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return sanitizedObject;
|
|
165
|
+
}
|
|
166
|
+
debugLog.debug('Sanitize', 'Unknown value type sanitized to null', { type: typeof value, depth });
|
|
167
|
+
return null;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Sanitizes API configuration data with strict validation
|
|
171
|
+
* @param data - The API config data to sanitize
|
|
172
|
+
* @returns The sanitized API config
|
|
173
|
+
*/
|
|
174
|
+
export const sanitizeApiConfig = (data) => {
|
|
175
|
+
debugLog.debug('Sanitize', 'Starting API config sanitization');
|
|
176
|
+
const safeData = {};
|
|
177
|
+
if (typeof data !== 'object' || data === null) {
|
|
178
|
+
debugLog.warn('Sanitize', 'API config data is not an object', { data, type: typeof data });
|
|
179
|
+
return safeData;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const originalKeys = Object.keys(data);
|
|
183
|
+
let processedKeys = 0;
|
|
184
|
+
let filteredKeys = 0;
|
|
185
|
+
for (const key of originalKeys) {
|
|
186
|
+
if (ALLOWED_API_CONFIG_KEYS.has(key)) {
|
|
187
|
+
const value = data[key];
|
|
188
|
+
if (key === 'excludedUrlPaths') {
|
|
189
|
+
const paths = Array.isArray(value) ? value : typeof value === 'string' ? [value] : [];
|
|
190
|
+
const originalPathsCount = paths.length;
|
|
191
|
+
safeData.excludedUrlPaths = paths.map((path) => sanitizePathString(String(path))).filter(Boolean);
|
|
192
|
+
const filteredPathsCount = originalPathsCount - safeData.excludedUrlPaths.length;
|
|
193
|
+
if (filteredPathsCount > 0) {
|
|
194
|
+
debugLog.warn('Sanitize', 'Some excluded URL paths were filtered during sanitization', {
|
|
195
|
+
originalCount: originalPathsCount,
|
|
196
|
+
filteredCount: filteredPathsCount,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (key === 'tags') {
|
|
201
|
+
if (Array.isArray(value)) {
|
|
202
|
+
safeData.tags = value;
|
|
203
|
+
debugLog.debug('Sanitize', 'Tags processed', { count: value.length });
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
debugLog.warn('Sanitize', 'Tags value is not an array', { value, type: typeof value });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
const sanitizedValue = sanitizeValue(value);
|
|
211
|
+
if (sanitizedValue !== null) {
|
|
212
|
+
safeData[key] = sanitizedValue;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
debugLog.warn('Sanitize', 'API config value sanitized to null', { key, originalValue: value });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
processedKeys++;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
filteredKeys++;
|
|
222
|
+
debugLog.debug('Sanitize', 'API config key not allowed', { key });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
debugLog.info('Sanitize', 'API config sanitization completed', {
|
|
226
|
+
originalKeys: originalKeys.length,
|
|
227
|
+
processedKeys,
|
|
228
|
+
filteredKeys,
|
|
229
|
+
finalKeys: Object.keys(safeData).length,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
debugLog.error('Sanitize', 'API config sanitization failed', {
|
|
234
|
+
error: error instanceof Error ? error.message : error,
|
|
235
|
+
});
|
|
236
|
+
throw new Error(`API config sanitization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
237
|
+
}
|
|
238
|
+
return safeData;
|
|
239
|
+
};
|
|
240
|
+
/**
|
|
241
|
+
* Sanitizes user metadata for custom events
|
|
242
|
+
* @param metadata - The metadata to sanitize
|
|
243
|
+
* @returns The sanitized metadata
|
|
244
|
+
*/
|
|
245
|
+
export const sanitizeMetadata = (metadata) => {
|
|
246
|
+
debugLog.debug('Sanitize', 'Starting metadata sanitization', { hasMetadata: metadata != null });
|
|
247
|
+
if (typeof metadata !== 'object' || metadata === null) {
|
|
248
|
+
debugLog.debug('Sanitize', 'Metadata is not an object, returning empty object', {
|
|
249
|
+
metadata,
|
|
250
|
+
type: typeof metadata,
|
|
251
|
+
});
|
|
252
|
+
return {};
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const originalKeys = Object.keys(metadata).length;
|
|
256
|
+
const sanitized = sanitizeValue(metadata);
|
|
257
|
+
const result = typeof sanitized === 'object' && sanitized !== null ? sanitized : {};
|
|
258
|
+
const finalKeys = Object.keys(result).length;
|
|
259
|
+
debugLog.debug('Sanitize', 'Metadata sanitization completed', {
|
|
260
|
+
originalKeys,
|
|
261
|
+
finalKeys,
|
|
262
|
+
keysFiltered: originalKeys - finalKeys,
|
|
263
|
+
});
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
debugLog.error('Sanitize', 'Metadata sanitization failed', {
|
|
268
|
+
error: error instanceof Error ? error.message : error,
|
|
269
|
+
});
|
|
270
|
+
throw new Error(`Metadata sanitization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
/**
|
|
274
|
+
* Sanitizes URL strings for tracking
|
|
275
|
+
* @param url - The URL to sanitize
|
|
276
|
+
* @returns The sanitized URL
|
|
277
|
+
*/
|
|
278
|
+
export const sanitizeUrl = (url) => {
|
|
279
|
+
debugLog.debug('Sanitize', 'Starting URL sanitization', { urlLength: typeof url === 'string' ? url.length : 0 });
|
|
280
|
+
if (typeof url !== 'string') {
|
|
281
|
+
debugLog.warn('Sanitize', 'URL is not a string', { url, type: typeof url });
|
|
282
|
+
return '';
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
// Basic URL validation
|
|
286
|
+
const urlObject = new URL(url);
|
|
287
|
+
// Only allow http/https protocols
|
|
288
|
+
if (!['http:', 'https:'].includes(urlObject.protocol)) {
|
|
289
|
+
debugLog.warn('Sanitize', 'URL protocol not allowed', {
|
|
290
|
+
protocol: urlObject.protocol,
|
|
291
|
+
allowedProtocols: ['http:', 'https:'],
|
|
292
|
+
});
|
|
293
|
+
return '';
|
|
294
|
+
}
|
|
295
|
+
// Sanitize the URL string
|
|
296
|
+
const result = sanitizeString(urlObject.href);
|
|
297
|
+
debugLog.debug('Sanitize', 'URL sanitization completed via URL object', {
|
|
298
|
+
originalLength: url.length,
|
|
299
|
+
sanitizedLength: result.length,
|
|
300
|
+
protocol: urlObject.protocol,
|
|
301
|
+
});
|
|
302
|
+
return result;
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
// If URL parsing fails, sanitize as string
|
|
306
|
+
debugLog.warn('Sanitize', 'URL parsing failed, falling back to string sanitization', {
|
|
307
|
+
urlPreview: url.slice(0, 100),
|
|
308
|
+
});
|
|
309
|
+
return sanitizeString(url);
|
|
310
|
+
}
|
|
311
|
+
};
|