@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,42 @@
|
|
|
1
|
+
import { AppConfig, Config, ApiConfig } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Validates the app configuration object (before normalization)
|
|
4
|
+
* This validates the structure and basic types but allows for normalization afterward
|
|
5
|
+
* @param config - The app configuration to validate
|
|
6
|
+
* @throws {ProjectIdValidationError} If project ID validation fails
|
|
7
|
+
* @throws {AppConfigValidationError} If other configuration validation fails
|
|
8
|
+
*/
|
|
9
|
+
export declare const validateAppConfig: (config: AppConfig) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Validates and normalizes the app configuration
|
|
12
|
+
* This is the primary validation entry point that ensures consistent behavior
|
|
13
|
+
* @param config - The app configuration to validate and normalize
|
|
14
|
+
* @returns The normalized configuration
|
|
15
|
+
* @throws {ProjectIdValidationError} If project ID validation fails after normalization
|
|
16
|
+
* @throws {AppConfigValidationError} If other configuration validation fails
|
|
17
|
+
*/
|
|
18
|
+
export declare const validateAndNormalizeConfig: (config: AppConfig) => AppConfig;
|
|
19
|
+
/**
|
|
20
|
+
* Validates a complete configuration object
|
|
21
|
+
* @param config - The configuration to validate
|
|
22
|
+
* @returns Validation result with errors and warnings
|
|
23
|
+
*/
|
|
24
|
+
export declare const validateConfig: (config: Config) => {
|
|
25
|
+
errors: string[];
|
|
26
|
+
warnings: string[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Validates the final configuration
|
|
30
|
+
* @param config - The configuration to validate
|
|
31
|
+
* @returns Validation result with errors and warnings
|
|
32
|
+
*/
|
|
33
|
+
export declare const validateFinalConfig: (config: Config) => {
|
|
34
|
+
errors: string[];
|
|
35
|
+
warnings: string[];
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Type guard to check if a JSON response is a valid API config
|
|
39
|
+
* @param json - The JSON to validate
|
|
40
|
+
* @returns True if the JSON is a valid API config
|
|
41
|
+
*/
|
|
42
|
+
export declare const isValidConfigApiResponse: (json: unknown) => json is ApiConfig;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { MAX_SESSION_TIMEOUT_MS, MIN_SESSION_TIMEOUT_MS, VALIDATION_MESSAGES } from '../../constants';
|
|
2
|
+
import { Mode } from '../../types';
|
|
3
|
+
import { ProjectIdValidationError, AppConfigValidationError, SessionTimeoutValidationError, SamplingRateValidationError, IntegrationValidationError, } from '../../types/validation-error.types';
|
|
4
|
+
import { debugLog } from '../logging';
|
|
5
|
+
/**
|
|
6
|
+
* Validates the app configuration object (before normalization)
|
|
7
|
+
* This validates the structure and basic types but allows for normalization afterward
|
|
8
|
+
* @param config - The app configuration to validate
|
|
9
|
+
* @throws {ProjectIdValidationError} If project ID validation fails
|
|
10
|
+
* @throws {AppConfigValidationError} If other configuration validation fails
|
|
11
|
+
*/
|
|
12
|
+
export const validateAppConfig = (config) => {
|
|
13
|
+
// Validate config exists and has id property
|
|
14
|
+
if (!config || typeof config !== 'object') {
|
|
15
|
+
debugLog.clientError('ConfigValidation', 'Configuration must be an object', { config });
|
|
16
|
+
throw new AppConfigValidationError('Configuration must be an object', 'config');
|
|
17
|
+
}
|
|
18
|
+
// Check if id property exists (allow falsy values to be handled by normalization)
|
|
19
|
+
if (!('id' in config)) {
|
|
20
|
+
debugLog.clientError('ConfigValidation', 'Project ID is missing from configuration');
|
|
21
|
+
throw new ProjectIdValidationError(VALIDATION_MESSAGES.MISSING_PROJECT_ID, 'config');
|
|
22
|
+
}
|
|
23
|
+
// Check basic type - null, undefined, or non-string values should fail here
|
|
24
|
+
if (config.id === null || config.id === undefined || typeof config.id !== 'string') {
|
|
25
|
+
debugLog.clientError('ConfigValidation', 'Project ID must be a non-empty string', {
|
|
26
|
+
providedId: config.id,
|
|
27
|
+
type: typeof config.id,
|
|
28
|
+
});
|
|
29
|
+
throw new ProjectIdValidationError(VALIDATION_MESSAGES.MISSING_PROJECT_ID, 'config');
|
|
30
|
+
}
|
|
31
|
+
if (config.sessionTimeout !== undefined) {
|
|
32
|
+
if (typeof config.sessionTimeout !== 'number' ||
|
|
33
|
+
config.sessionTimeout < MIN_SESSION_TIMEOUT_MS ||
|
|
34
|
+
config.sessionTimeout > MAX_SESSION_TIMEOUT_MS) {
|
|
35
|
+
debugLog.clientError('ConfigValidation', 'Invalid session timeout', {
|
|
36
|
+
provided: config.sessionTimeout,
|
|
37
|
+
min: MIN_SESSION_TIMEOUT_MS,
|
|
38
|
+
max: MAX_SESSION_TIMEOUT_MS,
|
|
39
|
+
});
|
|
40
|
+
throw new SessionTimeoutValidationError(VALIDATION_MESSAGES.INVALID_SESSION_TIMEOUT, 'config');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (config.globalMetadata !== undefined) {
|
|
44
|
+
if (typeof config.globalMetadata !== 'object' || config.globalMetadata === null) {
|
|
45
|
+
debugLog.clientError('ConfigValidation', 'Global metadata must be an object', {
|
|
46
|
+
provided: config.globalMetadata,
|
|
47
|
+
type: typeof config.globalMetadata,
|
|
48
|
+
});
|
|
49
|
+
throw new AppConfigValidationError(VALIDATION_MESSAGES.INVALID_GLOBAL_METADATA, 'config');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (config.scrollContainerSelectors !== undefined) {
|
|
53
|
+
validateScrollContainerSelectors(config.scrollContainerSelectors);
|
|
54
|
+
}
|
|
55
|
+
if (config.integrations) {
|
|
56
|
+
validateIntegrations(config.integrations);
|
|
57
|
+
}
|
|
58
|
+
if (config.sensitiveQueryParams !== undefined) {
|
|
59
|
+
if (!Array.isArray(config.sensitiveQueryParams)) {
|
|
60
|
+
debugLog.clientError('ConfigValidation', 'Sensitive query params must be an array', {
|
|
61
|
+
provided: config.sensitiveQueryParams,
|
|
62
|
+
type: typeof config.sensitiveQueryParams,
|
|
63
|
+
});
|
|
64
|
+
throw new AppConfigValidationError(VALIDATION_MESSAGES.INVALID_SENSITIVE_QUERY_PARAMS, 'config');
|
|
65
|
+
}
|
|
66
|
+
for (const param of config.sensitiveQueryParams) {
|
|
67
|
+
if (typeof param !== 'string') {
|
|
68
|
+
debugLog.clientError('ConfigValidation', 'All sensitive query params must be strings', {
|
|
69
|
+
param,
|
|
70
|
+
type: typeof param,
|
|
71
|
+
});
|
|
72
|
+
throw new AppConfigValidationError('All sensitive query params must be strings', 'config');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (config.errorSampling !== undefined) {
|
|
77
|
+
if (typeof config.errorSampling !== 'number' || config.errorSampling < 0 || config.errorSampling > 1) {
|
|
78
|
+
debugLog.clientError('ConfigValidation', 'Invalid error sampling rate', {
|
|
79
|
+
provided: config.errorSampling,
|
|
80
|
+
expected: '0-1',
|
|
81
|
+
});
|
|
82
|
+
throw new SamplingRateValidationError(VALIDATION_MESSAGES.INVALID_ERROR_SAMPLING_RATE, 'config');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Validates scroll container selectors
|
|
88
|
+
* @param selectors - CSS selectors to validate
|
|
89
|
+
*/
|
|
90
|
+
const validateScrollContainerSelectors = (selectors) => {
|
|
91
|
+
const selectorsArray = Array.isArray(selectors) ? selectors : [selectors];
|
|
92
|
+
for (const selector of selectorsArray) {
|
|
93
|
+
if (typeof selector !== 'string' || selector.trim() === '') {
|
|
94
|
+
debugLog.clientError('ConfigValidation', 'Invalid scroll container selector', {
|
|
95
|
+
selector,
|
|
96
|
+
type: typeof selector,
|
|
97
|
+
isEmpty: selector === '' || (typeof selector === 'string' && selector.trim() === ''),
|
|
98
|
+
});
|
|
99
|
+
throw new AppConfigValidationError(VALIDATION_MESSAGES.INVALID_SCROLL_CONTAINER_SELECTORS, 'config');
|
|
100
|
+
}
|
|
101
|
+
// Validate CSS selector syntax but handle invalid selectors gracefully
|
|
102
|
+
if (typeof document !== 'undefined') {
|
|
103
|
+
try {
|
|
104
|
+
document.querySelector(selector);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Invalid CSS selectors are handled gracefully
|
|
108
|
+
// they will be ignored by the ScrollHandler and it will fall back to window scrolling
|
|
109
|
+
debugLog.clientWarn('ConfigValidation', `Invalid CSS selector will be ignored: "${selector}"`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Validates integrations configuration
|
|
116
|
+
* @param integrations - Integrations configuration to validate
|
|
117
|
+
*/
|
|
118
|
+
const validateIntegrations = (integrations) => {
|
|
119
|
+
if (!integrations)
|
|
120
|
+
return;
|
|
121
|
+
if (integrations.googleAnalytics) {
|
|
122
|
+
if (!integrations.googleAnalytics.measurementId ||
|
|
123
|
+
typeof integrations.googleAnalytics.measurementId !== 'string' ||
|
|
124
|
+
integrations.googleAnalytics.measurementId.trim() === '') {
|
|
125
|
+
debugLog.clientError('ConfigValidation', 'Invalid Google Analytics measurement ID', {
|
|
126
|
+
provided: integrations.googleAnalytics.measurementId,
|
|
127
|
+
type: typeof integrations.googleAnalytics.measurementId,
|
|
128
|
+
});
|
|
129
|
+
throw new IntegrationValidationError(VALIDATION_MESSAGES.INVALID_GOOGLE_ANALYTICS_ID, 'config');
|
|
130
|
+
}
|
|
131
|
+
const measurementId = integrations.googleAnalytics.measurementId.trim();
|
|
132
|
+
if (!measurementId.match(/^(G-|UA-)/)) {
|
|
133
|
+
debugLog.clientError('ConfigValidation', 'Google Analytics measurement ID must start with "G-" or "UA-"', {
|
|
134
|
+
provided: measurementId,
|
|
135
|
+
});
|
|
136
|
+
throw new IntegrationValidationError('Google Analytics measurement ID must start with "G-" or "UA-"', 'config');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Validates and normalizes the app configuration
|
|
142
|
+
* This is the primary validation entry point that ensures consistent behavior
|
|
143
|
+
* @param config - The app configuration to validate and normalize
|
|
144
|
+
* @returns The normalized configuration
|
|
145
|
+
* @throws {ProjectIdValidationError} If project ID validation fails after normalization
|
|
146
|
+
* @throws {AppConfigValidationError} If other configuration validation fails
|
|
147
|
+
*/
|
|
148
|
+
export const validateAndNormalizeConfig = (config) => {
|
|
149
|
+
// First validate the structure and basic types
|
|
150
|
+
validateAppConfig(config);
|
|
151
|
+
// Normalize string values
|
|
152
|
+
const normalizedConfig = {
|
|
153
|
+
...config,
|
|
154
|
+
id: config.id.trim(),
|
|
155
|
+
globalMetadata: config.globalMetadata ?? {},
|
|
156
|
+
sensitiveQueryParams: config.sensitiveQueryParams ?? [],
|
|
157
|
+
};
|
|
158
|
+
// Validate normalized values - this catches whitespace-only IDs
|
|
159
|
+
if (!normalizedConfig.id) {
|
|
160
|
+
debugLog.clientError('ConfigValidation', 'Project ID is empty after trimming whitespace', {
|
|
161
|
+
originalId: config.id,
|
|
162
|
+
normalizedId: normalizedConfig.id,
|
|
163
|
+
});
|
|
164
|
+
throw new ProjectIdValidationError(VALIDATION_MESSAGES.PROJECT_ID_EMPTY_AFTER_TRIM, 'config');
|
|
165
|
+
}
|
|
166
|
+
return normalizedConfig;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Validates sampling rate
|
|
170
|
+
* @param samplingRate - The sampling rate to validate
|
|
171
|
+
* @param errors - Array to push errors to
|
|
172
|
+
*/
|
|
173
|
+
const validateSamplingRate = (samplingRate, errors) => {
|
|
174
|
+
if (samplingRate !== undefined) {
|
|
175
|
+
if (typeof samplingRate !== 'number') {
|
|
176
|
+
errors.push('samplingRate must be a number');
|
|
177
|
+
}
|
|
178
|
+
else if (samplingRate < 0 || samplingRate > 1) {
|
|
179
|
+
errors.push('samplingRate must be between 0 and 1');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Validates excluded URL paths
|
|
185
|
+
* @param excludedUrlPaths - The excluded URL paths to validate
|
|
186
|
+
* @param errors - Array to push errors to
|
|
187
|
+
* @param prefix - Optional prefix for error messages
|
|
188
|
+
*/
|
|
189
|
+
const validateExcludedUrlPaths = (excludedUrlPaths, errors, prefix = '') => {
|
|
190
|
+
if (excludedUrlPaths !== undefined) {
|
|
191
|
+
if (Array.isArray(excludedUrlPaths)) {
|
|
192
|
+
for (const [index, path] of excludedUrlPaths.entries()) {
|
|
193
|
+
if (typeof path === 'string') {
|
|
194
|
+
try {
|
|
195
|
+
new RegExp(path);
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
errors.push(`${prefix}excludedUrlPaths[${index}] is not a valid regex pattern`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
errors.push(`${prefix}excludedUrlPaths[${index}] must be a string`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
errors.push(`${prefix}excludedUrlPaths must be an array`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Validates a complete configuration object
|
|
213
|
+
* @param config - The configuration to validate
|
|
214
|
+
* @returns Validation result with errors and warnings
|
|
215
|
+
*/
|
|
216
|
+
export const validateConfig = (config) => {
|
|
217
|
+
const errors = [];
|
|
218
|
+
const warnings = [];
|
|
219
|
+
if (config.sessionTimeout !== undefined) {
|
|
220
|
+
if (typeof config.sessionTimeout !== 'number') {
|
|
221
|
+
errors.push('sessionTimeout must be a number');
|
|
222
|
+
}
|
|
223
|
+
else if (config.sessionTimeout < MIN_SESSION_TIMEOUT_MS) {
|
|
224
|
+
errors.push('sessionTimeout must be at least 30 seconds (30000ms)');
|
|
225
|
+
}
|
|
226
|
+
else if (config.sessionTimeout > MAX_SESSION_TIMEOUT_MS) {
|
|
227
|
+
warnings.push('sessionTimeout is very long (>24 hours), consider reducing it');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (config.globalMetadata !== undefined) {
|
|
231
|
+
if (typeof config.globalMetadata !== 'object' || config.globalMetadata === null) {
|
|
232
|
+
errors.push('globalMetadata must be an object');
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
const metadataSize = JSON.stringify(config.globalMetadata).length;
|
|
236
|
+
if (metadataSize > 10240) {
|
|
237
|
+
errors.push('globalMetadata is too large (max 10KB)');
|
|
238
|
+
}
|
|
239
|
+
if (Object.keys(config.globalMetadata).length > 12) {
|
|
240
|
+
errors.push('globalMetadata has too many keys (max 12)');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// No custom API endpoints supported
|
|
245
|
+
validateSamplingRate(config.samplingRate, errors);
|
|
246
|
+
if (config.tags !== undefined && !Array.isArray(config.tags)) {
|
|
247
|
+
errors.push('tags must be an array');
|
|
248
|
+
}
|
|
249
|
+
validateExcludedUrlPaths(config.excludedUrlPaths, errors);
|
|
250
|
+
return { errors, warnings };
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Validates the final configuration
|
|
254
|
+
* @param config - The configuration to validate
|
|
255
|
+
* @returns Validation result with errors and warnings
|
|
256
|
+
*/
|
|
257
|
+
export const validateFinalConfig = (config) => {
|
|
258
|
+
const errors = [];
|
|
259
|
+
const warnings = [];
|
|
260
|
+
validateSamplingRate(config.samplingRate, errors);
|
|
261
|
+
validateExcludedUrlPaths(config.excludedUrlPaths, errors);
|
|
262
|
+
// No custom API endpoints supported
|
|
263
|
+
return { errors, warnings };
|
|
264
|
+
};
|
|
265
|
+
/**
|
|
266
|
+
* Type guard to check if a JSON response is a valid API config
|
|
267
|
+
* @param json - The JSON to validate
|
|
268
|
+
* @returns True if the JSON is a valid API config
|
|
269
|
+
*/
|
|
270
|
+
export const isValidConfigApiResponse = (json) => {
|
|
271
|
+
try {
|
|
272
|
+
if (typeof json !== 'object' || !json) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
const response = json;
|
|
276
|
+
const result = {
|
|
277
|
+
mode: response['mode'] === undefined || [Mode.QA, Mode.DEBUG].includes(response['mode']),
|
|
278
|
+
samplingRate: response['samplingRate'] === undefined ||
|
|
279
|
+
(typeof response['samplingRate'] === 'number' && response['samplingRate'] > 0 && response['samplingRate'] <= 1),
|
|
280
|
+
tags: response['tags'] === undefined || Array.isArray(response['tags']),
|
|
281
|
+
excludedUrlPaths: response['excludedUrlPaths'] === undefined || Array.isArray(response['excludedUrlPaths']),
|
|
282
|
+
ipExcluded: response['ipExcluded'] === undefined || typeof response['ipExcluded'] === 'boolean',
|
|
283
|
+
};
|
|
284
|
+
return Object.values(result).every(Boolean);
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MetadataType } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Validates a complete event with name and optional metadata
|
|
4
|
+
* @param eventName - The event name to validate
|
|
5
|
+
* @param metadata - Optional metadata to validate
|
|
6
|
+
* @returns Validation result with sanitized metadata if valid
|
|
7
|
+
*/
|
|
8
|
+
export declare const isEventValid: (eventName: string, metadata?: Record<string, unknown>) => {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
error?: string;
|
|
11
|
+
sanitizedMetadata?: Record<string, MetadataType>;
|
|
12
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { isValidEventName, isValidMetadata } from './metadata-validations.utils';
|
|
2
|
+
import { debugLog } from '../logging';
|
|
3
|
+
/**
|
|
4
|
+
* Validates a complete event with name and optional metadata
|
|
5
|
+
* @param eventName - The event name to validate
|
|
6
|
+
* @param metadata - Optional metadata to validate
|
|
7
|
+
* @returns Validation result with sanitized metadata if valid
|
|
8
|
+
*/
|
|
9
|
+
export const isEventValid = (eventName, metadata) => {
|
|
10
|
+
const nameValidation = isValidEventName(eventName);
|
|
11
|
+
if (!nameValidation.valid) {
|
|
12
|
+
debugLog.clientError('EventValidation', 'Event name validation failed', { eventName, error: nameValidation.error });
|
|
13
|
+
return nameValidation;
|
|
14
|
+
}
|
|
15
|
+
if (!metadata) {
|
|
16
|
+
return { valid: true };
|
|
17
|
+
}
|
|
18
|
+
const metadataValidation = isValidMetadata(eventName, metadata, 'customEvent');
|
|
19
|
+
if (!metadataValidation.valid) {
|
|
20
|
+
debugLog.clientError('EventValidation', 'Event metadata validation failed', {
|
|
21
|
+
eventName,
|
|
22
|
+
error: metadataValidation.error,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return metadataValidation;
|
|
26
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { MetadataType } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Validates an event name
|
|
4
|
+
* @param eventName - The event name to validate
|
|
5
|
+
* @returns Validation result with error message if invalid
|
|
6
|
+
*/
|
|
7
|
+
export declare const isValidEventName: (eventName: string) => {
|
|
8
|
+
valid: boolean;
|
|
9
|
+
error?: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Validates metadata for events
|
|
13
|
+
* @param eventName - The event name (for error messages)
|
|
14
|
+
* @param metadata - The metadata to validate
|
|
15
|
+
* @param type - Type of metadata (globalMetadata or customEvent)
|
|
16
|
+
* @returns Validation result with sanitized metadata if valid
|
|
17
|
+
*/
|
|
18
|
+
export declare const isValidMetadata: (eventName: string, metadata: Record<string, unknown>, type?: "globalMetadata" | "customEvent") => {
|
|
19
|
+
valid: boolean;
|
|
20
|
+
error?: string;
|
|
21
|
+
sanitizedMetadata?: Record<string, MetadataType>;
|
|
22
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { MAX_CUSTOM_EVENT_ARRAY_SIZE, MAX_CUSTOM_EVENT_KEYS, MAX_CUSTOM_EVENT_NAME_LENGTH, MAX_CUSTOM_EVENT_STRING_SIZE, MAX_STRING_LENGTH, } from '../../constants';
|
|
2
|
+
import { sanitizeMetadata } from '../security/sanitize.utils';
|
|
3
|
+
import { isOnlyPrimitiveFields } from './type-guards.utils';
|
|
4
|
+
/**
|
|
5
|
+
* Validates an event name
|
|
6
|
+
* @param eventName - The event name to validate
|
|
7
|
+
* @returns Validation result with error message if invalid
|
|
8
|
+
*/
|
|
9
|
+
export const isValidEventName = (eventName) => {
|
|
10
|
+
if (typeof eventName !== 'string') {
|
|
11
|
+
return {
|
|
12
|
+
valid: false,
|
|
13
|
+
error: 'Event name must be a string',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (eventName.length === 0) {
|
|
17
|
+
return {
|
|
18
|
+
valid: false,
|
|
19
|
+
error: 'Event name cannot be empty',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (eventName.length > MAX_CUSTOM_EVENT_NAME_LENGTH) {
|
|
23
|
+
return {
|
|
24
|
+
valid: false,
|
|
25
|
+
error: `Event name is too long (max ${MAX_CUSTOM_EVENT_NAME_LENGTH} characters)`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (eventName.includes('<') || eventName.includes('>') || eventName.includes('&')) {
|
|
29
|
+
return {
|
|
30
|
+
valid: false,
|
|
31
|
+
error: 'Event name contains invalid characters',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const reservedWords = ['constructor', 'prototype', '__proto__', 'eval', 'function', 'var', 'let', 'const'];
|
|
35
|
+
if (reservedWords.includes(eventName.toLowerCase())) {
|
|
36
|
+
return {
|
|
37
|
+
valid: false,
|
|
38
|
+
error: 'Event name cannot be a reserved word',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return { valid: true };
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Validates metadata for events
|
|
45
|
+
* @param eventName - The event name (for error messages)
|
|
46
|
+
* @param metadata - The metadata to validate
|
|
47
|
+
* @param type - Type of metadata (globalMetadata or customEvent)
|
|
48
|
+
* @returns Validation result with sanitized metadata if valid
|
|
49
|
+
*/
|
|
50
|
+
export const isValidMetadata = (eventName, metadata, type) => {
|
|
51
|
+
const sanitizedMetadata = sanitizeMetadata(metadata);
|
|
52
|
+
const intro = type && type === 'customEvent' ? `${type} "${eventName}" metadata error` : `${eventName} metadata error`;
|
|
53
|
+
if (!isOnlyPrimitiveFields(sanitizedMetadata)) {
|
|
54
|
+
return {
|
|
55
|
+
valid: false,
|
|
56
|
+
error: `${intro}: object has invalid types. Valid types are string, number, boolean or string arrays.`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
let jsonString;
|
|
60
|
+
try {
|
|
61
|
+
jsonString = JSON.stringify(sanitizedMetadata);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return {
|
|
65
|
+
valid: false,
|
|
66
|
+
error: `${intro}: object contains circular references or cannot be serialized.`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (jsonString.length > MAX_CUSTOM_EVENT_STRING_SIZE) {
|
|
70
|
+
return {
|
|
71
|
+
valid: false,
|
|
72
|
+
error: `${intro}: object is too large (max ${MAX_CUSTOM_EVENT_STRING_SIZE / 1024} KB).`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const keyCount = Object.keys(sanitizedMetadata).length;
|
|
76
|
+
if (keyCount > MAX_CUSTOM_EVENT_KEYS) {
|
|
77
|
+
return {
|
|
78
|
+
valid: false,
|
|
79
|
+
error: `${intro}: object has too many keys (max ${MAX_CUSTOM_EVENT_KEYS} keys).`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
for (const [key, value] of Object.entries(sanitizedMetadata)) {
|
|
83
|
+
if (Array.isArray(value)) {
|
|
84
|
+
if (value.length > MAX_CUSTOM_EVENT_ARRAY_SIZE) {
|
|
85
|
+
return {
|
|
86
|
+
valid: false,
|
|
87
|
+
error: `${intro}: array property "${key}" is too large (max ${MAX_CUSTOM_EVENT_ARRAY_SIZE} items).`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
for (const item of value) {
|
|
91
|
+
if (typeof item === 'string' && item.length > 500) {
|
|
92
|
+
return {
|
|
93
|
+
valid: false,
|
|
94
|
+
error: `${intro}: array property "${key}" contains strings that are too long (max 500 characters).`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (typeof value === 'string' && value.length > MAX_STRING_LENGTH) {
|
|
100
|
+
return {
|
|
101
|
+
valid: false,
|
|
102
|
+
error: `${intro}: property "${key}" is too long (max ${MAX_STRING_LENGTH} characters).`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
valid: true,
|
|
108
|
+
sanitizedMetadata,
|
|
109
|
+
};
|
|
110
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if an object contains only primitive fields (string, number, boolean, or string arrays)
|
|
3
|
+
* @param object - The object to check
|
|
4
|
+
* @returns True if the object contains only primitive fields
|
|
5
|
+
*/
|
|
6
|
+
export declare const isOnlyPrimitiveFields: (object: Record<string, unknown>) => boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if an object contains only primitive fields (string, number, boolean, or string arrays)
|
|
3
|
+
* @param object - The object to check
|
|
4
|
+
* @returns True if the object contains only primitive fields
|
|
5
|
+
*/
|
|
6
|
+
export const isOnlyPrimitiveFields = (object) => {
|
|
7
|
+
if (typeof object !== 'object' || object === null) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
for (const value of Object.values(object)) {
|
|
11
|
+
if (value === null || value === undefined) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const type = typeof value;
|
|
15
|
+
if (type === 'string' || type === 'number' || type === 'boolean') {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (Array.isArray(value)) {
|
|
19
|
+
if (!value.every((item) => typeof item === 'string')) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates if a URL is valid and optionally allows HTTP URLs
|
|
3
|
+
* @param url - The URL to validate
|
|
4
|
+
* @param allowHttp - Whether to allow HTTP URLs (default: false)
|
|
5
|
+
* @returns True if the URL is valid, false otherwise
|
|
6
|
+
*/
|
|
7
|
+
export declare const isValidUrl: (url: string, allowHttp?: boolean) => boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Validates a URL field in configuration
|
|
10
|
+
* @param url - The URL to validate
|
|
11
|
+
* @param allowHttp - Whether to allow HTTP URLs
|
|
12
|
+
* @param fieldName - The name of the field being validated
|
|
13
|
+
* @param errors - Array to push errors to
|
|
14
|
+
*/
|
|
15
|
+
export declare const validateUrl: (url: unknown, allowHttp: boolean | undefined, fieldName: string, errors: string[]) => void;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates if a URL is valid and optionally allows HTTP URLs
|
|
3
|
+
* @param url - The URL to validate
|
|
4
|
+
* @param allowHttp - Whether to allow HTTP URLs (default: false)
|
|
5
|
+
* @returns True if the URL is valid, false otherwise
|
|
6
|
+
*/
|
|
7
|
+
export const isValidUrl = (url, allowHttp = false) => {
|
|
8
|
+
try {
|
|
9
|
+
const parsed = new URL(url);
|
|
10
|
+
const isHttps = parsed.protocol === 'https:';
|
|
11
|
+
const isHttp = parsed.protocol === 'http:';
|
|
12
|
+
return isHttps || (allowHttp && isHttp);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Validates a URL field in configuration
|
|
20
|
+
* @param url - The URL to validate
|
|
21
|
+
* @param allowHttp - Whether to allow HTTP URLs
|
|
22
|
+
* @param fieldName - The name of the field being validated
|
|
23
|
+
* @param errors - Array to push errors to
|
|
24
|
+
*/
|
|
25
|
+
export const validateUrl = (url, allowHttp, fieldName, errors) => {
|
|
26
|
+
if (url !== undefined) {
|
|
27
|
+
if (typeof url === 'string') {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = new URL(url);
|
|
30
|
+
if (parsed.protocol === 'http:' && !allowHttp) {
|
|
31
|
+
errors.push(`${fieldName} using http requires allowHttp=true`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
errors.push(`${fieldName} must be a valid URL`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
errors.push(`${fieldName} must be a string`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|