@tracelog/lib 0.4.0 → 0.5.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.
Files changed (98) hide show
  1. package/dist/browser/tracelog.js +620 -658
  2. package/dist/cjs/api.d.ts +1 -53
  3. package/dist/cjs/api.js +0 -59
  4. package/dist/cjs/app.constants.d.ts +1 -1
  5. package/dist/cjs/app.d.ts +1 -5
  6. package/dist/cjs/app.js +4 -12
  7. package/dist/cjs/constants/api.constants.d.ts +5 -2
  8. package/dist/cjs/constants/api.constants.js +5 -14
  9. package/dist/cjs/constants/config.constants.d.ts +3 -3
  10. package/dist/cjs/constants/config.constants.js +3 -3
  11. package/dist/cjs/constants/error.constants.d.ts +7 -2
  12. package/dist/cjs/constants/error.constants.js +13 -2
  13. package/dist/cjs/handlers/click.handler.js +0 -6
  14. package/dist/cjs/handlers/error.handler.js +9 -0
  15. package/dist/cjs/handlers/scroll.handler.js +0 -5
  16. package/dist/cjs/handlers/session.handler.js +5 -2
  17. package/dist/cjs/integrations/google-analytics.integration.d.ts +1 -1
  18. package/dist/cjs/integrations/google-analytics.integration.js +2 -1
  19. package/dist/cjs/managers/api.manager.d.ts +1 -1
  20. package/dist/cjs/managers/api.manager.js +3 -3
  21. package/dist/cjs/managers/config.builder.d.ts +33 -0
  22. package/dist/cjs/managers/config.builder.js +116 -0
  23. package/dist/cjs/managers/config.manager.d.ts +13 -14
  24. package/dist/cjs/managers/config.manager.js +52 -58
  25. package/dist/cjs/managers/event.manager.d.ts +1 -46
  26. package/dist/cjs/managers/event.manager.js +15 -70
  27. package/dist/cjs/managers/sender.manager.d.ts +1 -28
  28. package/dist/cjs/managers/sender.manager.js +43 -73
  29. package/dist/cjs/managers/session.manager.d.ts +2 -49
  30. package/dist/cjs/managers/session.manager.js +42 -83
  31. package/dist/cjs/managers/state.manager.d.ts +1 -28
  32. package/dist/cjs/managers/state.manager.js +5 -33
  33. package/dist/cjs/managers/storage.manager.d.ts +6 -0
  34. package/dist/cjs/managers/storage.manager.js +18 -1
  35. package/dist/cjs/public-api.d.ts +1 -1
  36. package/dist/cjs/test-bridge.d.ts +3 -2
  37. package/dist/cjs/test-bridge.js +34 -7
  38. package/dist/cjs/types/api.types.d.ts +24 -8
  39. package/dist/cjs/types/api.types.js +24 -8
  40. package/dist/cjs/types/event.types.d.ts +2 -4
  41. package/dist/cjs/types/event.types.js +0 -1
  42. package/dist/cjs/types/test-bridge.types.d.ts +2 -1
  43. package/dist/cjs/utils/logging/debug-logger.utils.d.ts +1 -2
  44. package/dist/cjs/utils/logging/debug-logger.utils.js +2 -3
  45. package/dist/cjs/utils/validations/config-validations.utils.d.ts +1 -26
  46. package/dist/cjs/utils/validations/config-validations.utils.js +5 -117
  47. package/dist/cjs/utils/validations/event-validations.utils.d.ts +2 -2
  48. package/dist/cjs/utils/validations/metadata-validations.utils.d.ts +3 -3
  49. package/dist/cjs/utils/validations/metadata-validations.utils.js +41 -3
  50. package/dist/esm/api.d.ts +1 -53
  51. package/dist/esm/api.js +0 -59
  52. package/dist/esm/app.constants.d.ts +1 -1
  53. package/dist/esm/app.d.ts +1 -5
  54. package/dist/esm/app.js +5 -13
  55. package/dist/esm/constants/api.constants.d.ts +5 -2
  56. package/dist/esm/constants/api.constants.js +5 -13
  57. package/dist/esm/constants/config.constants.d.ts +3 -3
  58. package/dist/esm/constants/config.constants.js +3 -3
  59. package/dist/esm/constants/error.constants.d.ts +7 -2
  60. package/dist/esm/constants/error.constants.js +12 -1
  61. package/dist/esm/handlers/click.handler.js +0 -6
  62. package/dist/esm/handlers/error.handler.js +10 -1
  63. package/dist/esm/handlers/scroll.handler.js +0 -5
  64. package/dist/esm/handlers/session.handler.js +5 -2
  65. package/dist/esm/integrations/google-analytics.integration.d.ts +1 -1
  66. package/dist/esm/integrations/google-analytics.integration.js +2 -1
  67. package/dist/esm/managers/api.manager.d.ts +1 -1
  68. package/dist/esm/managers/api.manager.js +3 -3
  69. package/dist/esm/managers/config.builder.d.ts +33 -0
  70. package/dist/esm/managers/config.builder.js +112 -0
  71. package/dist/esm/managers/config.manager.d.ts +13 -14
  72. package/dist/esm/managers/config.manager.js +54 -60
  73. package/dist/esm/managers/event.manager.d.ts +1 -46
  74. package/dist/esm/managers/event.manager.js +15 -70
  75. package/dist/esm/managers/sender.manager.d.ts +1 -28
  76. package/dist/esm/managers/sender.manager.js +44 -74
  77. package/dist/esm/managers/session.manager.d.ts +2 -49
  78. package/dist/esm/managers/session.manager.js +42 -83
  79. package/dist/esm/managers/state.manager.d.ts +1 -28
  80. package/dist/esm/managers/state.manager.js +4 -33
  81. package/dist/esm/managers/storage.manager.d.ts +6 -0
  82. package/dist/esm/managers/storage.manager.js +18 -1
  83. package/dist/esm/public-api.d.ts +1 -1
  84. package/dist/esm/test-bridge.d.ts +3 -2
  85. package/dist/esm/test-bridge.js +34 -7
  86. package/dist/esm/types/api.types.d.ts +24 -8
  87. package/dist/esm/types/api.types.js +24 -8
  88. package/dist/esm/types/event.types.d.ts +2 -4
  89. package/dist/esm/types/event.types.js +0 -1
  90. package/dist/esm/types/test-bridge.types.d.ts +2 -1
  91. package/dist/esm/utils/logging/debug-logger.utils.d.ts +1 -2
  92. package/dist/esm/utils/logging/debug-logger.utils.js +3 -4
  93. package/dist/esm/utils/validations/config-validations.utils.d.ts +1 -26
  94. package/dist/esm/utils/validations/config-validations.utils.js +5 -114
  95. package/dist/esm/utils/validations/event-validations.utils.d.ts +2 -2
  96. package/dist/esm/utils/validations/metadata-validations.utils.d.ts +3 -3
  97. package/dist/esm/utils/validations/metadata-validations.utils.js +41 -3
  98. package/package.json +1 -1
package/dist/cjs/api.d.ts CHANGED
@@ -1,60 +1,8 @@
1
1
  import { MetadataType, AppConfig, EmitterCallback, EmitterMap } from './types';
2
2
  import './types/window.types';
3
- /**
4
- * Initializes the tracelog app with the provided configuration.
5
- * If already initialized, this function returns early without error.
6
- * @param appConfig - The configuration object for the app
7
- * @throws {Error} If initialization fails or environment is invalid
8
- * @example
9
- * await tracelog.init({ id: 'my-project-id' });
10
- */
11
3
  export declare const init: (appConfig: AppConfig) => Promise<void>;
12
- /**
13
- * Sends a custom event with the specified name and metadata.
14
- * @param name - The name of the custom event.
15
- * @param metadata - Optional metadata to attach to the event.
16
- * @example
17
- * // Send a custom event with metadata
18
- * tracelog.event('user_signup', { method: 'email', plan: 'premium' });
19
- * @example
20
- * // Send a custom event without metadata
21
- * tracelog.event('user_login');
22
- * @remarks
23
- * This function should be called after the app has been initialized using the `tracelog.init` function.
24
- */
25
- export declare const event: (name: string, metadata?: Record<string, MetadataType>) => void;
26
- /**
27
- * Subscribe to events emitted by TraceLog
28
- * @param event - Event name to listen to
29
- * @param callback - Function to call when event is emitted
30
- * @example
31
- * // Listen for tracked events
32
- * tracelog.on('event', (data) => {
33
- * console.log('Event tracked:', data.type);
34
- * });
35
- *
36
- * // Listen for event queues being sent
37
- * tracelog.on('queue', (data) => {
38
- * console.log('Events sent:', data.events.length);
39
- * });
40
- */
4
+ export declare const event: (name: string, metadata?: Record<string, MetadataType> | Record<string, MetadataType>[]) => void;
41
5
  export declare const on: <K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>) => void;
42
- /**
43
- * Unsubscribe from events emitted by TraceLog
44
- * @param event - Event name to stop listening to
45
- * @param callback - The same function reference that was used in on()
46
- * @example
47
- * // Remove a specific listener
48
- * tracelog.off('event', myCallback);
49
- */
50
6
  export declare const off: <K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>) => void;
51
- /**
52
- * Checks if the app has been initialized.
53
- * @returns true if the app is initialized, false otherwise
54
- */
55
7
  export declare const isInitialized: () => boolean;
56
- /**
57
- * Destroys the current app instance and cleans up resources.
58
- * @throws {Error} If not initialized or already destroying
59
- */
60
8
  export declare const destroy: () => Promise<void>;
package/dist/cjs/api.js CHANGED
@@ -8,29 +8,17 @@ require("./types/window.types");
8
8
  let app = null;
9
9
  let isInitializing = false;
10
10
  let isDestroying = false;
11
- /**
12
- * Initializes the tracelog app with the provided configuration.
13
- * If already initialized, this function returns early without error.
14
- * @param appConfig - The configuration object for the app
15
- * @throws {Error} If initialization fails or environment is invalid
16
- * @example
17
- * await tracelog.init({ id: 'my-project-id' });
18
- */
19
11
  const init = async (appConfig) => {
20
- // Browser environment check
21
12
  if (typeof window === 'undefined' || typeof document === 'undefined') {
22
13
  throw new Error('This library can only be used in a browser environment');
23
14
  }
24
- // Check if TraceLog is disabled
25
15
  if (window.__traceLogDisabled) {
26
16
  return;
27
17
  }
28
- // Already initialized - safe to return
29
18
  if (app) {
30
19
  utils_1.debugLog.debug('API', 'Library already initialized, skipping duplicate initialization');
31
20
  return;
32
21
  }
33
- // Prevent concurrent initialization
34
22
  if (isInitializing) {
35
23
  utils_1.debugLog.warn('API', 'Initialization already in progress');
36
24
  throw new Error('Initialization already in progress');
@@ -65,19 +53,6 @@ const init = async (appConfig) => {
65
53
  }
66
54
  };
67
55
  exports.init = init;
68
- /**
69
- * Sends a custom event with the specified name and metadata.
70
- * @param name - The name of the custom event.
71
- * @param metadata - Optional metadata to attach to the event.
72
- * @example
73
- * // Send a custom event with metadata
74
- * tracelog.event('user_signup', { method: 'email', plan: 'premium' });
75
- * @example
76
- * // Send a custom event without metadata
77
- * tracelog.event('user_login');
78
- * @remarks
79
- * This function should be called after the app has been initialized using the `tracelog.init` function.
80
- */
81
56
  const event = (name, metadata) => {
82
57
  if (!app) {
83
58
  throw new Error('TraceLog not initialized. Please call init() first.');
@@ -91,21 +66,6 @@ const event = (name, metadata) => {
91
66
  }
92
67
  };
93
68
  exports.event = event;
94
- /**
95
- * Subscribe to events emitted by TraceLog
96
- * @param event - Event name to listen to
97
- * @param callback - Function to call when event is emitted
98
- * @example
99
- * // Listen for tracked events
100
- * tracelog.on('event', (data) => {
101
- * console.log('Event tracked:', data.type);
102
- * });
103
- *
104
- * // Listen for event queues being sent
105
- * tracelog.on('queue', (data) => {
106
- * console.log('Events sent:', data.events.length);
107
- * });
108
- */
109
69
  const on = (event, callback) => {
110
70
  if (!app) {
111
71
  throw new Error('TraceLog not initialized. Please call init() first.');
@@ -113,14 +73,6 @@ const on = (event, callback) => {
113
73
  app.on(event, callback);
114
74
  };
115
75
  exports.on = on;
116
- /**
117
- * Unsubscribe from events emitted by TraceLog
118
- * @param event - Event name to stop listening to
119
- * @param callback - The same function reference that was used in on()
120
- * @example
121
- * // Remove a specific listener
122
- * tracelog.off('event', myCallback);
123
- */
124
76
  const off = (event, callback) => {
125
77
  if (!app) {
126
78
  throw new Error('TraceLog not initialized. Please call init() first.');
@@ -128,24 +80,14 @@ const off = (event, callback) => {
128
80
  app.off(event, callback);
129
81
  };
130
82
  exports.off = off;
131
- /**
132
- * Checks if the app has been initialized.
133
- * @returns true if the app is initialized, false otherwise
134
- */
135
83
  const isInitialized = () => {
136
84
  return app !== null;
137
85
  };
138
86
  exports.isInitialized = isInitialized;
139
- /**
140
- * Destroys the current app instance and cleans up resources.
141
- * @throws {Error} If not initialized or already destroying
142
- */
143
87
  const destroy = async () => {
144
- // Check if app was never initialized
145
88
  if (!app) {
146
89
  throw new Error('App not initialized');
147
90
  }
148
- // Prevent concurrent destroy operations
149
91
  if (isDestroying) {
150
92
  throw new Error('Destroy operation already in progress');
151
93
  }
@@ -169,7 +111,6 @@ const destroy = async () => {
169
111
  }
170
112
  };
171
113
  exports.destroy = destroy;
172
- // Auto-inject testing bridge in development environments
173
114
  if (process.env.NODE_ENV === 'dev' && typeof window !== 'undefined') {
174
115
  const injectTestingBridge = () => {
175
116
  window.__traceLogBridge = new test_bridge_1.TestBridge(isInitializing, isDestroying);
@@ -2,7 +2,7 @@ export declare const PERFORMANCE_CONFIG: {
2
2
  readonly WEB_VITALS_THRESHOLDS: Record<import("./types").WebVitalType, number>;
3
3
  };
4
4
  export declare const DATA_PROTECTION: {
5
- readonly PII_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp];
5
+ readonly PII_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp];
6
6
  };
7
7
  export declare const ENGAGEMENT_THRESHOLDS: {
8
8
  readonly LOW_ACTIVITY_EVENT_COUNT: 50;
package/dist/cjs/app.d.ts CHANGED
@@ -9,10 +9,6 @@ import { GoogleAnalyticsIntegration } from './integrations/google-analytics.inte
9
9
  import { StorageManager } from './managers/storage.manager';
10
10
  import { PerformanceHandler } from './handlers/performance.handler';
11
11
  import { ErrorHandler } from './handlers/error.handler';
12
- /**
13
- * Main application class for TraceLog analytics
14
- * Orchestrates event tracking, session management, and integrations
15
- */
16
12
  export declare class App extends StateManager {
17
13
  private isInitialized;
18
14
  private suppressNextScrollTimer;
@@ -34,7 +30,7 @@ export declare class App extends StateManager {
34
30
  };
35
31
  get initialized(): boolean;
36
32
  init(appConfig: AppConfig): Promise<void>;
37
- sendCustomEvent(name: string, metadata?: Record<string, unknown>): void;
33
+ sendCustomEvent(name: string, metadata?: Record<string, unknown> | Record<string, unknown>[]): void;
38
34
  on<K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>): void;
39
35
  off<K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>): void;
40
36
  destroy(force?: boolean): Promise<void>;
package/dist/cjs/app.js CHANGED
@@ -17,10 +17,6 @@ const storage_manager_1 = require("./managers/storage.manager");
17
17
  const config_constants_1 = require("./constants/config.constants");
18
18
  const performance_handler_1 = require("./handlers/performance.handler");
19
19
  const error_handler_1 = require("./handlers/error.handler");
20
- /**
21
- * Main application class for TraceLog analytics
22
- * Orchestrates event tracking, session management, and integrations
23
- */
24
20
  class App extends state_manager_1.StateManager {
25
21
  constructor() {
26
22
  super(...arguments);
@@ -103,6 +99,7 @@ class App extends state_manager_1.StateManager {
103
99
  clearTimeout(this.suppressNextScrollTimer);
104
100
  this.suppressNextScrollTimer = null;
105
101
  }
102
+ this.managers.event?.flushImmediatelySync();
106
103
  this.managers.event?.stop();
107
104
  this.emitter.removeAllListeners();
108
105
  this.set('hasStartSession', false);
@@ -112,20 +109,15 @@ class App extends state_manager_1.StateManager {
112
109
  this.handlers = {};
113
110
  }
114
111
  async setupState(appConfig) {
115
- // Set API URL
116
112
  const apiUrl = (0, api_manager_1.getApiUrlForProject)(appConfig.id, appConfig.allowHttp);
117
113
  this.set('apiUrl', apiUrl);
118
- // Get remote configuration
119
114
  const configManager = new config_manager_1.ConfigManager();
120
115
  const config = await configManager.get(apiUrl, appConfig);
121
- const { config: normalizedConfig } = (0, utils_1.normalizeConfig)(config);
122
- this.set('config', normalizedConfig);
123
- // Set user ID
124
- const userId = user_manager_1.UserManager.getId(this.managers.storage, normalizedConfig.id);
116
+ this.set('config', config);
117
+ const userId = user_manager_1.UserManager.getId(this.managers.storage, config.id);
125
118
  this.set('userId', userId);
126
- // Set device and page info
127
119
  this.set('device', (0, utils_1.getDeviceType)());
128
- const pageUrl = (0, utils_1.normalizeUrl)(window.location.href, normalizedConfig.sensitiveQueryParams);
120
+ const pageUrl = (0, utils_1.normalizeUrl)(window.location.href, config.sensitiveQueryParams);
129
121
  this.set('pageUrl', pageUrl);
130
122
  }
131
123
  async setupIntegrations() {
@@ -1,3 +1,6 @@
1
- import { ApiConfig, Config } from '../types';
1
+ import { ApiConfig } from '../types';
2
+ /**
3
+ * Default API configuration values
4
+ * Used as fallback when API config is not available or incomplete
5
+ */
2
6
  export declare const DEFAULT_API_CONFIG: ApiConfig;
3
- export declare const DEFAULT_CONFIG: (config: Config) => Config;
@@ -1,23 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_CONFIG = exports.DEFAULT_API_CONFIG = void 0;
3
+ exports.DEFAULT_API_CONFIG = void 0;
4
4
  const config_constants_1 = require("./config.constants");
5
+ /**
6
+ * Default API configuration values
7
+ * Used as fallback when API config is not available or incomplete
8
+ */
5
9
  exports.DEFAULT_API_CONFIG = {
6
10
  samplingRate: config_constants_1.DEFAULT_SAMPLING_RATE,
7
11
  excludedUrlPaths: [],
8
12
  tags: [],
9
13
  ipExcluded: false,
10
14
  };
11
- const DEFAULT_CONFIG = (config) => ({
12
- ...exports.DEFAULT_API_CONFIG,
13
- ...config,
14
- allowHttp: false,
15
- sessionTimeout: config_constants_1.DEFAULT_SESSION_TIMEOUT,
16
- samplingRate: config.samplingRate && config.samplingRate > config_constants_1.MIN_SAMPLING_RATE && config.samplingRate <= config_constants_1.MAX_SAMPLING_RATE
17
- ? config.samplingRate
18
- : config_constants_1.DEFAULT_SAMPLING_RATE,
19
- excludedUrlPaths: config.excludedUrlPaths ?? [],
20
- tags: config.tags ?? [],
21
- ipExcluded: config.ipExcluded ?? false,
22
- });
23
- exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
@@ -3,13 +3,13 @@
3
3
  * This file centralizes all timing, limits, browser, and initialization constants
4
4
  */
5
5
  export declare const DEFAULT_SESSION_TIMEOUT: number;
6
- export declare const DUPLICATE_EVENT_THRESHOLD_MS = 1000;
6
+ export declare const DUPLICATE_EVENT_THRESHOLD_MS = 500;
7
7
  export declare const EVENT_SENT_INTERVAL_MS = 10000;
8
8
  export declare const SCROLL_DEBOUNCE_TIME_MS = 250;
9
9
  export declare const DEFAULT_VISIBILITY_TIMEOUT_MS = 2000;
10
10
  export declare const EVENT_EXPIRY_HOURS = 24;
11
11
  export declare const EVENT_PERSISTENCE_MAX_AGE_MS: number;
12
- export declare const MAX_EVENTS_QUEUE_LENGTH = 500;
12
+ export declare const MAX_EVENTS_QUEUE_LENGTH = 100;
13
13
  export declare const MAX_RETRIES = 3;
14
14
  export declare const RETRY_DELAY_MS = 5000;
15
15
  export declare const REQUEST_TIMEOUT_MS = 10000;
@@ -65,7 +65,7 @@ export declare const VALIDATION_MESSAGES: {
65
65
  readonly MISSING_PROJECT_ID: "Project ID is required";
66
66
  readonly PROJECT_ID_EMPTY_AFTER_TRIM: "Project ID is required";
67
67
  readonly INVALID_SESSION_TIMEOUT: "Session timeout must be between 30000ms (30 seconds) and 86400000ms (24 hours)";
68
- readonly INVALID_SAMPLING_RATE: "Sampling rate must be greater than 0 and less than or equal to 1";
68
+ readonly INVALID_SAMPLING_RATE: "Sampling rate must be between 0 and 1";
69
69
  readonly INVALID_ERROR_SAMPLING_RATE: "Error sampling must be between 0 and 1";
70
70
  readonly INVALID_GOOGLE_ANALYTICS_ID: "Google Analytics measurement ID is required when integration is enabled";
71
71
  readonly INVALID_SCROLL_CONTAINER_SELECTORS: "Scroll container selectors must be valid CSS selectors";
@@ -10,7 +10,7 @@ exports.XSS_PATTERNS = exports.VALIDATION_MESSAGES = exports.ALLOWED_API_CONFIG_
10
10
  // SESSION & TIMING
11
11
  // ============================================================================
12
12
  exports.DEFAULT_SESSION_TIMEOUT = 15 * 60 * 1000; // 15 minutes
13
- exports.DUPLICATE_EVENT_THRESHOLD_MS = 1000; // 1 second
13
+ exports.DUPLICATE_EVENT_THRESHOLD_MS = 500; // 500ms
14
14
  exports.EVENT_SENT_INTERVAL_MS = 10000; // 10 seconds
15
15
  // Throttling and debouncing
16
16
  exports.SCROLL_DEBOUNCE_TIME_MS = 250;
@@ -21,7 +21,7 @@ exports.EVENT_PERSISTENCE_MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24 hours
21
21
  // ============================================================================
22
22
  // LIMITS & RETRIES
23
23
  // ============================================================================
24
- exports.MAX_EVENTS_QUEUE_LENGTH = 500;
24
+ exports.MAX_EVENTS_QUEUE_LENGTH = 100;
25
25
  exports.MAX_RETRIES = 3;
26
26
  exports.RETRY_DELAY_MS = 5000;
27
27
  exports.REQUEST_TIMEOUT_MS = 10000;
@@ -153,7 +153,7 @@ exports.VALIDATION_MESSAGES = {
153
153
  // Session timeout validation
154
154
  INVALID_SESSION_TIMEOUT: `Session timeout must be between ${exports.MIN_SESSION_TIMEOUT_MS}ms (30 seconds) and ${exports.MAX_SESSION_TIMEOUT_MS}ms (24 hours)`,
155
155
  // Sampling rate validation
156
- INVALID_SAMPLING_RATE: 'Sampling rate must be greater than 0 and less than or equal to 1',
156
+ INVALID_SAMPLING_RATE: 'Sampling rate must be between 0 and 1',
157
157
  INVALID_ERROR_SAMPLING_RATE: 'Error sampling must be between 0 and 1',
158
158
  // Integration validation
159
159
  INVALID_GOOGLE_ANALYTICS_ID: 'Google Analytics measurement ID is required when integration is enabled',
@@ -6,7 +6,7 @@
6
6
  * Regular expressions for detecting and sanitizing Personally Identifiable Information (PII)
7
7
  * These patterns are used to replace sensitive information with [REDACTED] in error messages
8
8
  */
9
- export declare const PII_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp];
9
+ export declare const PII_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp];
10
10
  /**
11
11
  * Maximum length for error messages before truncation
12
12
  * Prevents extremely long error messages from consuming excessive storage
@@ -16,12 +16,17 @@ export declare const MAX_ERROR_MESSAGE_LENGTH = 500;
16
16
  * Time window for error suppression in milliseconds
17
17
  * Prevents duplicate errors from flooding the system within this timeframe
18
18
  */
19
- export declare const ERROR_SUPPRESSION_WINDOW_MS = 60000;
19
+ export declare const ERROR_SUPPRESSION_WINDOW_MS = 5000;
20
20
  /**
21
21
  * Maximum number of unique errors to track for suppression
22
22
  * Prevents memory usage from growing indefinitely
23
23
  */
24
24
  export declare const MAX_TRACKED_ERRORS = 50;
25
+ /**
26
+ * Hard limit for error tracking before aggressive cleanup
27
+ * If this limit is exceeded, the entire error map is cleared
28
+ */
29
+ export declare const MAX_TRACKED_ERRORS_HARD_LIMIT: number;
25
30
  /**
26
31
  * Default error sampling rate
27
32
  * Controls what percentage of errors are actually reported
@@ -4,7 +4,7 @@
4
4
  * Centralizes patterns and limits for error tracking and data protection
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.DEFAULT_ERROR_SAMPLING_RATE = exports.MAX_TRACKED_ERRORS = exports.ERROR_SUPPRESSION_WINDOW_MS = exports.MAX_ERROR_MESSAGE_LENGTH = exports.PII_PATTERNS = void 0;
7
+ exports.DEFAULT_ERROR_SAMPLING_RATE = exports.MAX_TRACKED_ERRORS_HARD_LIMIT = exports.MAX_TRACKED_ERRORS = exports.ERROR_SUPPRESSION_WINDOW_MS = exports.MAX_ERROR_MESSAGE_LENGTH = exports.PII_PATTERNS = void 0;
8
8
  // ============================================================================
9
9
  // PII SANITIZATION PATTERNS
10
10
  // ============================================================================
@@ -21,6 +21,12 @@ exports.PII_PATTERNS = [
21
21
  /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,
22
22
  // IBAN (International Bank Account Number)
23
23
  /\b[A-Z]{2}\d{2}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/gi,
24
+ // API keys/tokens (sk_test_, sk_live_, pk_test_, pk_live_, etc.)
25
+ /\b[sp]k_(test|live)_[a-zA-Z0-9]{10,}\b/gi,
26
+ // Bearer tokens (JWT-like patterns - matches complete and partial tokens)
27
+ /Bearer\s+[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)?(?:\.[A-Za-z0-9_-]+)?/gi,
28
+ // Passwords in connection strings (protocol://user:password@host)
29
+ /:\/\/[^:/]+:([^@]+)@/gi,
24
30
  ];
25
31
  // ============================================================================
26
32
  // ERROR TRACKING LIMITS
@@ -34,12 +40,17 @@ exports.MAX_ERROR_MESSAGE_LENGTH = 500;
34
40
  * Time window for error suppression in milliseconds
35
41
  * Prevents duplicate errors from flooding the system within this timeframe
36
42
  */
37
- exports.ERROR_SUPPRESSION_WINDOW_MS = 60000; // 1 minute
43
+ exports.ERROR_SUPPRESSION_WINDOW_MS = 5000; // 5 seconds
38
44
  /**
39
45
  * Maximum number of unique errors to track for suppression
40
46
  * Prevents memory usage from growing indefinitely
41
47
  */
42
48
  exports.MAX_TRACKED_ERRORS = 50;
49
+ /**
50
+ * Hard limit for error tracking before aggressive cleanup
51
+ * If this limit is exceeded, the entire error map is cleared
52
+ */
53
+ exports.MAX_TRACKED_ERRORS_HARD_LIMIT = exports.MAX_TRACKED_ERRORS * 2;
43
54
  // ============================================================================
44
55
  // ERROR SAMPLING
45
56
  // ============================================================================
@@ -66,11 +66,9 @@ class ClickHandler extends state_manager_1.StateManager {
66
66
  getRelevantClickElement(element) {
67
67
  for (const selector of constants_1.INTERACTIVE_SELECTORS) {
68
68
  try {
69
- // First check if the element itself matches
70
69
  if (element.matches(selector)) {
71
70
  return element;
72
71
  }
73
- // If not, search for matching ancestors
74
72
  const parent = element.closest(selector);
75
73
  if (parent) {
76
74
  return parent;
@@ -133,19 +131,15 @@ class ClickHandler extends state_manager_1.StateManager {
133
131
  getRelevantText(clickedElement, relevantElement) {
134
132
  const clickedText = clickedElement.textContent?.trim() ?? '';
135
133
  const relevantText = relevantElement.textContent?.trim() ?? '';
136
- // No text available
137
134
  if (!clickedText && !relevantText) {
138
135
  return '';
139
136
  }
140
- // Prefer clicked element text if it's reasonable length
141
137
  if (clickedText && clickedText.length <= constants_1.MAX_TEXT_LENGTH) {
142
138
  return clickedText;
143
139
  }
144
- // Use relevant element text if it fits
145
140
  if (relevantText.length <= constants_1.MAX_TEXT_LENGTH) {
146
141
  return relevantText;
147
142
  }
148
- // Truncate relevant text if too long
149
143
  return relevantText.slice(0, constants_1.MAX_TEXT_LENGTH - 3) + '...';
150
144
  }
151
145
  extractElementAttributes(element) {
@@ -109,6 +109,15 @@ class ErrorHandler extends state_manager_1.StateManager {
109
109
  return true;
110
110
  }
111
111
  this.recentErrors.set(key, now);
112
+ if (this.recentErrors.size > error_constants_1.MAX_TRACKED_ERRORS_HARD_LIMIT) {
113
+ logging_1.debugLog.warn('ErrorHandler', 'Hard limit exceeded, clearing all tracked errors', {
114
+ size: this.recentErrors.size,
115
+ limit: error_constants_1.MAX_TRACKED_ERRORS_HARD_LIMIT,
116
+ });
117
+ this.recentErrors.clear();
118
+ this.recentErrors.set(key, now);
119
+ return false;
120
+ }
112
121
  if (this.recentErrors.size > error_constants_1.MAX_TRACKED_ERRORS) {
113
122
  this.pruneOldErrors();
114
123
  }
@@ -64,7 +64,6 @@ class ScrollHandler extends state_manager_1.StateManager {
64
64
  }
65
65
  }
66
66
  setupScrollContainer(element) {
67
- // Skip setup for non-scrollable elements
68
67
  if (element !== window && !this.isElementScrollable(element)) {
69
68
  return;
70
69
  }
@@ -176,12 +175,10 @@ class ScrollHandler extends state_manager_1.StateManager {
176
175
  calculateScrollData(container) {
177
176
  const { element, lastScrollPos } = container;
178
177
  const scrollTop = this.getScrollTop(element);
179
- // Early return: check significant movement first (cheapest check)
180
178
  const positionDelta = Math.abs(scrollTop - lastScrollPos);
181
179
  if (positionDelta < constants_1.SIGNIFICANT_SCROLL_DELTA) {
182
180
  return null;
183
181
  }
184
- // Early return: check if window is scrollable
185
182
  if (element === window && !this.isWindowScrollable()) {
186
183
  return null;
187
184
  }
@@ -209,7 +206,6 @@ class ScrollHandler extends state_manager_1.StateManager {
209
206
  style.overflowX === 'scroll' ||
210
207
  style.overflow === 'auto' ||
211
208
  style.overflow === 'scroll';
212
- // Element must have scrollable overflow AND content that exceeds the container
213
209
  const hasOverflowContent = element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
214
210
  return hasScrollableOverflow && hasOverflowContent;
215
211
  }
@@ -218,7 +214,6 @@ class ScrollHandler extends state_manager_1.StateManager {
218
214
  return document.querySelector(selector);
219
215
  }
220
216
  catch (error) {
221
- // Invalid CSS selector - log warning and continue
222
217
  logging_1.debugLog.clientWarn('ScrollHandler', 'Invalid CSS selector', {
223
218
  selector,
224
219
  error: error instanceof Error ? error.message : 'Unknown error',
@@ -20,12 +20,15 @@ class SessionHandler extends state_manager_1.StateManager {
20
20
  logging_1.debugLog.warn('SessionHandler', 'Cannot start tracking on destroyed handler');
21
21
  return;
22
22
  }
23
+ const projectId = this.get('config')?.id;
24
+ if (!projectId) {
25
+ throw new Error('Cannot start session tracking: config not available');
26
+ }
23
27
  try {
24
- this.sessionManager = new session_manager_1.SessionManager(this.storageManager, this.eventManager);
28
+ this.sessionManager = new session_manager_1.SessionManager(this.storageManager, this.eventManager, projectId);
25
29
  await this.sessionManager.startTracking();
26
30
  }
27
31
  catch (error) {
28
- // Cleanup on failure
29
32
  if (this.sessionManager) {
30
33
  try {
31
34
  this.sessionManager.destroy();
@@ -9,7 +9,7 @@ declare global {
9
9
  export declare class GoogleAnalyticsIntegration extends StateManager {
10
10
  private isInitialized;
11
11
  initialize(): Promise<void>;
12
- trackEvent(eventName: string, metadata: Record<string, MetadataType>): void;
12
+ trackEvent(eventName: string, metadata: Record<string, MetadataType> | Record<string, MetadataType>[]): void;
13
13
  cleanup(): void;
14
14
  private isScriptAlreadyLoaded;
15
15
  private loadScript;
@@ -37,7 +37,8 @@ class GoogleAnalyticsIntegration extends state_manager_1.StateManager {
37
37
  return;
38
38
  }
39
39
  try {
40
- window.gtag('event', eventName, metadata);
40
+ const normalizedMetadata = Array.isArray(metadata) ? { items: metadata } : metadata;
41
+ window.gtag('event', eventName, normalizedMetadata);
41
42
  }
42
43
  catch (error) {
43
44
  utils_1.debugLog.error('GoogleAnalyticsIntegration', 'Event tracking failed', {
@@ -2,7 +2,7 @@
2
2
  * Generates API URL for TraceLog service based on project ID
3
3
  *
4
4
  * Handles two special cases:
5
- * - 'localhost:PORT' - for local development (generates http://localhost:PORT)
5
+ * - 'localhost:8080' or 'localhost:9999' - for local development (generates http://localhost:PORT)
6
6
  * - Regular project IDs - generates subdomain URLs via getApiUrl utility
7
7
  *
8
8
  * @param id Project ID or localhost address
@@ -8,7 +8,7 @@ const logging_1 = require("../utils/logging");
8
8
  * Generates API URL for TraceLog service based on project ID
9
9
  *
10
10
  * Handles two special cases:
11
- * - 'localhost:PORT' - for local development (generates http://localhost:PORT)
11
+ * - 'localhost:8080' or 'localhost:9999' - for local development (generates http://localhost:PORT)
12
12
  * - Regular project IDs - generates subdomain URLs via getApiUrl utility
13
13
  *
14
14
  * @param id Project ID or localhost address
@@ -18,8 +18,8 @@ const logging_1 = require("../utils/logging");
18
18
  */
19
19
  function getApiUrlForProject(id, allowHttp = false) {
20
20
  try {
21
- // Handle localhost development case
22
- if (id.startsWith(types_1.SpecialProjectId.Localhost)) {
21
+ // Handle localhost development case (localhost:8080 or localhost:9999)
22
+ if (id === types_1.SpecialProjectId.Localhost || id === types_1.SpecialProjectId.Fail) {
23
23
  const url = `http://${id}`;
24
24
  if (!(0, utils_1.isValidUrl)(url, true)) {
25
25
  throw new Error(`Invalid localhost URL format: ${id}`);
@@ -0,0 +1,33 @@
1
+ import { AppConfig, ApiConfig, Config } from '../types';
2
+ /**
3
+ * Centralized configuration builder
4
+ * Single source of truth for merging and building final configuration
5
+ */
6
+ export declare class ConfigBuilder {
7
+ /**
8
+ * Builds final configuration from app config and API config
9
+ * Applies clear precedence: API overrides client, with defaults as fallback
10
+ */
11
+ static build(appConfig: AppConfig, apiConfig?: ApiConfig): Config;
12
+ /**
13
+ * Resolves session timeout with validation
14
+ * Returns default if undefined or out of valid range
15
+ */
16
+ private static resolveSessionTimeout;
17
+ /**
18
+ * Resolves sampling rate with validation
19
+ * Priority: API config > app config > default
20
+ */
21
+ private static resolveSamplingRate;
22
+ /**
23
+ * Resolves error sampling rate based on mode
24
+ * In debug/qa modes: uses provided value or defaults to full sampling (1.0)
25
+ * In production: uses provided value or defaults to 10% sampling (0.1)
26
+ */
27
+ private static resolveErrorSampling;
28
+ /**
29
+ * Resolves mode with special project ID handling
30
+ * Priority: Special project ID > API mode > app mode
31
+ */
32
+ private static resolveMode;
33
+ }