@tracelog/lib 0.4.1 → 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 +576 -610
  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 +0 -45
  26. package/dist/cjs/managers/event.manager.js +14 -67
  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 +37 -79
  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 -3
  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 +0 -45
  74. package/dist/esm/managers/event.manager.js +14 -67
  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 +37 -79
  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 -3
  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
@@ -6,7 +6,7 @@ const types_1 = require("../types");
6
6
  const logging_1 = require("../utils/logging");
7
7
  const state_manager_1 = require("./state.manager");
8
8
  class SessionManager extends state_manager_1.StateManager {
9
- constructor(storageManager, eventManager) {
9
+ constructor(storageManager, eventManager, projectId) {
10
10
  super();
11
11
  this.sessionTimeoutId = null;
12
12
  this.broadcastChannel = null;
@@ -16,10 +16,8 @@ class SessionManager extends state_manager_1.StateManager {
16
16
  this.isTracking = false;
17
17
  this.storageManager = storageManager;
18
18
  this.eventManager = eventManager;
19
+ this.projectId = projectId;
19
20
  }
20
- /**
21
- * Initialize cross-tab synchronization
22
- */
23
21
  initCrossTabSync() {
24
22
  if (typeof BroadcastChannel === 'undefined') {
25
23
  logging_1.debugLog.warn('SessionManager', 'BroadcastChannel not supported');
@@ -48,41 +46,38 @@ class SessionManager extends state_manager_1.StateManager {
48
46
  }
49
47
  };
50
48
  }
51
- /**
52
- * Share session with other tabs
53
- */
54
49
  shareSession(sessionId) {
55
- this.broadcastChannel?.postMessage({
56
- action: 'session_start',
57
- projectId: this.getProjectId(),
58
- sessionId,
59
- timestamp: Date.now(),
60
- });
50
+ if (this.broadcastChannel && typeof this.broadcastChannel.postMessage === 'function') {
51
+ this.broadcastChannel.postMessage({
52
+ action: 'session_start',
53
+ projectId: this.getProjectId(),
54
+ sessionId,
55
+ timestamp: Date.now(),
56
+ });
57
+ }
61
58
  }
62
59
  broadcastSessionEnd(sessionId, reason) {
63
60
  if (!sessionId) {
64
61
  return;
65
62
  }
66
- this.broadcastChannel?.postMessage({
67
- action: 'session_end',
68
- projectId: this.getProjectId(),
69
- sessionId,
70
- reason,
71
- timestamp: Date.now(),
72
- });
63
+ if (this.broadcastChannel && typeof this.broadcastChannel.postMessage === 'function') {
64
+ this.broadcastChannel.postMessage({
65
+ action: 'session_end',
66
+ projectId: this.getProjectId(),
67
+ sessionId,
68
+ reason,
69
+ timestamp: Date.now(),
70
+ });
71
+ }
73
72
  }
74
- /**
75
- * Cleanup cross-tab sync
76
- */
77
73
  cleanupCrossTabSync() {
78
74
  if (this.broadcastChannel) {
79
- this.broadcastChannel.close();
75
+ if (typeof this.broadcastChannel.close === 'function') {
76
+ this.broadcastChannel.close();
77
+ }
80
78
  this.broadcastChannel = null;
81
79
  }
82
80
  }
83
- /**
84
- * Recover session from localStorage if it exists and hasn't expired
85
- */
86
81
  recoverSession() {
87
82
  const storedSession = this.loadStoredSession();
88
83
  if (!storedSession) {
@@ -97,9 +92,6 @@ class SessionManager extends state_manager_1.StateManager {
97
92
  logging_1.debugLog.info('SessionManager', 'Session recovered from storage', { sessionId: storedSession.id });
98
93
  return storedSession.id;
99
94
  }
100
- /**
101
- * Persist session data to localStorage
102
- */
103
95
  persistSession(sessionId, lastActivity = Date.now()) {
104
96
  this.saveStoredSession({
105
97
  id: sessionId,
@@ -136,11 +128,8 @@ class SessionManager extends state_manager_1.StateManager {
136
128
  return (0, constants_1.SESSION_STORAGE_KEY)(this.getProjectId());
137
129
  }
138
130
  getProjectId() {
139
- return this.get('config')?.id ?? '';
131
+ return this.projectId;
140
132
  }
141
- /**
142
- * Start session tracking
143
- */
144
133
  async startTracking() {
145
134
  if (this.isTracking) {
146
135
  logging_1.debugLog.warn('SessionManager', 'Session tracking already active');
@@ -153,13 +142,11 @@ class SessionManager extends state_manager_1.StateManager {
153
142
  try {
154
143
  this.set('sessionId', sessionId);
155
144
  this.persistSession(sessionId);
156
- // Track session start event only for new sessions
157
145
  if (!isRecovered) {
158
146
  this.eventManager.track({
159
147
  type: types_1.EventType.SESSION_START,
160
148
  });
161
149
  }
162
- // Initialize components
163
150
  this.initCrossTabSync();
164
151
  this.shareSession(sessionId);
165
152
  this.setupSessionTimeout();
@@ -177,15 +164,9 @@ class SessionManager extends state_manager_1.StateManager {
177
164
  throw error;
178
165
  }
179
166
  }
180
- /**
181
- * Generate unique session ID
182
- */
183
167
  generateSessionId() {
184
168
  return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
185
169
  }
186
- /**
187
- * Setup session timeout
188
- */
189
170
  setupSessionTimeout() {
190
171
  this.clearSessionTimeout();
191
172
  const sessionTimeout = this.get('config')?.sessionTimeout ?? constants_1.DEFAULT_SESSION_TIMEOUT;
@@ -193,9 +174,6 @@ class SessionManager extends state_manager_1.StateManager {
193
174
  this.endSession('inactivity');
194
175
  }, sessionTimeout);
195
176
  }
196
- /**
197
- * Reset session timeout and update activity
198
- */
199
177
  resetSessionTimeout() {
200
178
  this.setupSessionTimeout();
201
179
  const sessionId = this.get('sessionId');
@@ -203,27 +181,18 @@ class SessionManager extends state_manager_1.StateManager {
203
181
  this.persistSession(sessionId);
204
182
  }
205
183
  }
206
- /**
207
- * Clear session timeout
208
- */
209
184
  clearSessionTimeout() {
210
185
  if (this.sessionTimeoutId) {
211
186
  clearTimeout(this.sessionTimeoutId);
212
187
  this.sessionTimeoutId = null;
213
188
  }
214
189
  }
215
- /**
216
- * Setup activity listeners to track user engagement
217
- */
218
190
  setupActivityListeners() {
219
191
  this.activityHandler = () => this.resetSessionTimeout();
220
192
  document.addEventListener('click', this.activityHandler, { passive: true });
221
193
  document.addEventListener('keydown', this.activityHandler, { passive: true });
222
194
  document.addEventListener('scroll', this.activityHandler, { passive: true });
223
195
  }
224
- /**
225
- * Clean up activity listeners
226
- */
227
196
  cleanupActivityListeners() {
228
197
  if (this.activityHandler) {
229
198
  document.removeEventListener('click', this.activityHandler);
@@ -232,9 +201,6 @@ class SessionManager extends state_manager_1.StateManager {
232
201
  this.activityHandler = null;
233
202
  }
234
203
  }
235
- /**
236
- * Setup page lifecycle listeners (visibility and unload)
237
- */
238
204
  setupLifecycleListeners() {
239
205
  if (this.visibilityChangeHandler || this.beforeUnloadHandler) {
240
206
  return;
@@ -253,9 +219,7 @@ class SessionManager extends state_manager_1.StateManager {
253
219
  this.beforeUnloadHandler = () => {
254
220
  this.endSession('page_unload');
255
221
  };
256
- // Handle tab visibility changes
257
222
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
258
- // Handle page unload
259
223
  window.addEventListener('beforeunload', this.beforeUnloadHandler);
260
224
  }
261
225
  cleanupLifecycleListeners() {
@@ -268,14 +232,11 @@ class SessionManager extends state_manager_1.StateManager {
268
232
  this.beforeUnloadHandler = null;
269
233
  }
270
234
  }
271
- /**
272
- * End current session
273
- */
274
- endSession(reason) {
235
+ async endSession(reason) {
275
236
  const sessionId = this.get('sessionId');
276
237
  if (!sessionId) {
277
238
  logging_1.debugLog.warn('SessionManager', 'endSession called without active session', { reason });
278
- this.resetSessionState();
239
+ this.resetSessionState(reason);
279
240
  return;
280
241
  }
281
242
  logging_1.debugLog.info('SessionManager', 'Ending session', { sessionId, reason });
@@ -285,42 +246,39 @@ class SessionManager extends state_manager_1.StateManager {
285
246
  });
286
247
  const finalize = () => {
287
248
  this.broadcastSessionEnd(sessionId, reason);
288
- this.resetSessionState();
249
+ this.resetSessionState(reason);
289
250
  };
290
251
  const flushResult = this.eventManager.flushImmediatelySync();
291
252
  if (flushResult) {
292
253
  finalize();
293
254
  return;
294
255
  }
295
- this.eventManager
296
- .flushImmediately()
297
- .then(finalize)
298
- .catch((error) => {
256
+ try {
257
+ await this.eventManager.flushImmediately();
258
+ finalize();
259
+ }
260
+ catch (error) {
299
261
  logging_1.debugLog.warn('SessionManager', 'Async flush failed during session end', {
300
262
  error: error instanceof Error ? error.message : 'Unknown error',
301
263
  });
302
264
  finalize();
303
- });
265
+ }
304
266
  }
305
- resetSessionState() {
267
+ resetSessionState(reason) {
306
268
  this.clearSessionTimeout();
307
269
  this.cleanupActivityListeners();
308
270
  this.cleanupLifecycleListeners();
309
271
  this.cleanupCrossTabSync();
310
- this.clearStoredSession();
272
+ if (reason !== 'page_unload') {
273
+ this.clearStoredSession();
274
+ }
311
275
  this.set('sessionId', null);
312
276
  this.set('hasStartSession', false);
313
277
  this.isTracking = false;
314
278
  }
315
- /**
316
- * Stop session tracking
317
- */
318
279
  async stopTracking() {
319
- this.endSession('manual_stop');
280
+ await this.endSession('manual_stop');
320
281
  }
321
- /**
322
- * Clean up all resources
323
- */
324
282
  destroy() {
325
283
  this.clearSessionTimeout();
326
284
  this.cleanupActivityListeners();
@@ -1,38 +1,11 @@
1
1
  import { State } from '../types';
2
- /**
3
- * Resets the global state to its initial empty state.
4
- * Used primarily for testing and cleanup scenarios.
5
- */
2
+ export declare function getGlobalState(): Readonly<State>;
6
3
  export declare function resetGlobalState(): void;
7
- /**
8
- * Abstract base class providing state management capabilities to TraceLog components.
9
- *
10
- * All managers and handlers extend this class to access and modify the shared global state.
11
- * State operations are synchronous and thread-safe within the single-threaded browser environment.
12
- */
13
4
  export declare abstract class StateManager {
14
- /**
15
- * Gets a value from the global state
16
- */
17
5
  protected get<T extends keyof State>(key: T): State[T];
18
- /**
19
- * Sets a value in the global state
20
- */
21
6
  protected set<T extends keyof State>(key: T, value: State[T]): void;
22
- /**
23
- * Gets the entire state object (for debugging purposes)
24
- */
25
7
  protected getState(): Readonly<State>;
26
- /**
27
- * Checks if a state key is considered critical for logging
28
- */
29
8
  private isCriticalStateKey;
30
- /**
31
- * Determines if a state change should be logged
32
- */
33
9
  private shouldLog;
34
- /**
35
- * Formats values for logging (avoiding large object dumps)
36
- */
37
10
  private formatLogValue;
38
11
  }
@@ -1,45 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StateManager = void 0;
4
+ exports.getGlobalState = getGlobalState;
4
5
  exports.resetGlobalState = resetGlobalState;
5
6
  const logging_1 = require("../utils/logging");
6
7
  const constants_1 = require("../constants");
7
- /**
8
- * Global state store shared across all TraceLog components
9
- */
10
8
  const globalState = {};
11
- /**
12
- * Resets the global state to its initial empty state.
13
- * Used primarily for testing and cleanup scenarios.
14
- */
9
+ function getGlobalState() {
10
+ return globalState;
11
+ }
15
12
  function resetGlobalState() {
16
13
  Object.keys(globalState).forEach((key) => {
17
14
  delete globalState[key];
18
15
  });
19
16
  }
20
- /**
21
- * Abstract base class providing state management capabilities to TraceLog components.
22
- *
23
- * All managers and handlers extend this class to access and modify the shared global state.
24
- * State operations are synchronous and thread-safe within the single-threaded browser environment.
25
- */
26
17
  class StateManager {
27
- /**
28
- * Gets a value from the global state
29
- */
30
18
  get(key) {
31
19
  return globalState[key];
32
20
  }
33
- /**
34
- * Sets a value in the global state
35
- */
36
21
  set(key, value) {
37
22
  const oldValue = globalState[key];
38
23
  if (key === 'config' && value) {
39
24
  const configValue = value;
40
25
  if (configValue) {
41
26
  const samplingRate = configValue.samplingRate ?? constants_1.DEFAULT_SAMPLING_RATE;
42
- const normalizedSamplingRate = samplingRate > 0 ? samplingRate : constants_1.DEFAULT_SAMPLING_RATE;
27
+ const normalizedSamplingRate = samplingRate < 0 || samplingRate > 1 ? constants_1.DEFAULT_SAMPLING_RATE : samplingRate;
43
28
  const hasNormalizedSampling = normalizedSamplingRate !== samplingRate;
44
29
  if (hasNormalizedSampling) {
45
30
  const normalizedConfig = { ...configValue, samplingRate: normalizedSamplingRate };
@@ -56,7 +41,6 @@ class StateManager {
56
41
  else {
57
42
  globalState[key] = value;
58
43
  }
59
- // Log critical state changes for debugging
60
44
  if (this.isCriticalStateKey(key) && this.shouldLog(oldValue, globalState[key])) {
61
45
  logging_1.debugLog.debug('StateManager', 'State updated', {
62
46
  key,
@@ -65,27 +49,15 @@ class StateManager {
65
49
  });
66
50
  }
67
51
  }
68
- /**
69
- * Gets the entire state object (for debugging purposes)
70
- */
71
52
  getState() {
72
53
  return { ...globalState };
73
54
  }
74
- /**
75
- * Checks if a state key is considered critical for logging
76
- */
77
55
  isCriticalStateKey(key) {
78
56
  return key === 'sessionId' || key === 'config' || key === 'hasStartSession';
79
57
  }
80
- /**
81
- * Determines if a state change should be logged
82
- */
83
58
  shouldLog(oldValue, newValue) {
84
59
  return oldValue !== newValue;
85
60
  }
86
- /**
87
- * Formats values for logging (avoiding large object dumps)
88
- */
89
61
  formatLogValue(key, value) {
90
62
  if (key === 'config') {
91
63
  return value ? '(configured)' : '(not configured)';
@@ -6,6 +6,7 @@
6
6
  export declare class StorageManager {
7
7
  private readonly storage;
8
8
  private readonly fallbackStorage;
9
+ private hasQuotaExceededError;
9
10
  constructor();
10
11
  /**
11
12
  * Retrieves an item from storage
@@ -27,6 +28,11 @@ export declare class StorageManager {
27
28
  * Checks if storage is available
28
29
  */
29
30
  isAvailable(): boolean;
31
+ /**
32
+ * Checks if a QuotaExceededError has occurred
33
+ * This indicates localStorage is full and data may not persist
34
+ */
35
+ hasQuotaError(): boolean;
30
36
  /**
31
37
  * Initialize localStorage with feature detection
32
38
  */
@@ -10,6 +10,7 @@ const debug_logger_utils_1 = require("../utils/logging/debug-logger.utils");
10
10
  class StorageManager {
11
11
  constructor() {
12
12
  this.fallbackStorage = new Map();
13
+ this.hasQuotaExceededError = false;
13
14
  this.storage = this.initializeStorage();
14
15
  if (!this.storage) {
15
16
  debug_logger_utils_1.debugLog.warn('StorageManager', 'localStorage not available, using memory fallback');
@@ -41,7 +42,16 @@ class StorageManager {
41
42
  }
42
43
  }
43
44
  catch (error) {
44
- debug_logger_utils_1.debugLog.warn('StorageManager', 'Failed to set item, using fallback', { key, error });
45
+ if (error instanceof DOMException && error.name === 'QuotaExceededError') {
46
+ this.hasQuotaExceededError = true;
47
+ debug_logger_utils_1.debugLog.error('StorageManager', 'localStorage quota exceeded - data will not persist after reload', {
48
+ key,
49
+ valueSize: value.length,
50
+ });
51
+ }
52
+ else {
53
+ debug_logger_utils_1.debugLog.warn('StorageManager', 'Failed to set item, using fallback', { key, error });
54
+ }
45
55
  }
46
56
  // Always update fallback for consistency
47
57
  this.fallbackStorage.set(key, value);
@@ -92,6 +102,13 @@ class StorageManager {
92
102
  isAvailable() {
93
103
  return this.storage !== null;
94
104
  }
105
+ /**
106
+ * Checks if a QuotaExceededError has occurred
107
+ * This indicates localStorage is full and data may not persist
108
+ */
109
+ hasQuotaError() {
110
+ return this.hasQuotaExceededError;
111
+ }
95
112
  /**
96
113
  * Initialize localStorage with feature detection
97
114
  */
@@ -2,7 +2,7 @@ export * from './app.constants';
2
2
  export * from './app.types';
3
3
  export declare const tracelog: {
4
4
  init: (appConfig: import("./app.types").AppConfig) => Promise<void>;
5
- event: (name: string, metadata?: Record<string, import("./app.types").MetadataType>) => void;
5
+ event: (name: string, metadata?: Record<string, import("./app.types").MetadataType> | Record<string, import("./app.types").MetadataType>[]) => void;
6
6
  on: <K extends keyof import("./types").EmitterMap>(event: K, callback: import("./types").EmitterCallback<import("./types").EmitterMap[K]>) => void;
7
7
  off: <K extends keyof import("./types").EmitterMap>(event: K, callback: import("./types").EmitterCallback<import("./types").EmitterMap[K]>) => void;
8
8
  isInitialized: () => boolean;
@@ -17,11 +17,12 @@ export declare class TestBridge extends App implements TraceLogTestBridge {
17
17
  private _isDestroying;
18
18
  constructor(isInitializing: boolean, isDestroying: boolean);
19
19
  isInitializing(): boolean;
20
- sendCustomEvent(name: string, data?: Record<string, unknown>): void;
20
+ sendCustomEvent(name: string, data?: Record<string, unknown> | Record<string, unknown>[]): void;
21
21
  getSessionData(): Record<string, unknown> | null;
22
22
  setSessionTimeout(timeout: number): void;
23
23
  getQueueLength(): number;
24
24
  forceInitLock(enabled?: boolean): void;
25
+ simulatePersistedEvents(events: any[]): void;
25
26
  get<T extends keyof State>(key: T): State[T];
26
27
  getStorageManager(): StorageManager | null;
27
28
  getEventManager(): EventManager | null;
@@ -32,7 +33,7 @@ export declare class TestBridge extends App implements TraceLogTestBridge {
32
33
  getPerformanceHandler(): PerformanceHandler | null;
33
34
  getErrorHandler(): ErrorHandler | null;
34
35
  getGoogleAnalytics(): GoogleAnalyticsIntegration | null;
35
- destroy(): Promise<void>;
36
+ destroy(force?: boolean): Promise<void>;
36
37
  /**
37
38
  * Helper to safely access managers/handlers and convert undefined to null
38
39
  */
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TestBridge = void 0;
4
4
  const app_1 = require("./app");
5
- const utils_1 = require("./utils");
6
5
  /**
7
6
  * Test bridge for E2E testing
8
7
  */
@@ -17,7 +16,10 @@ class TestBridge extends app_1.App {
17
16
  return this._isInitializing;
18
17
  }
19
18
  sendCustomEvent(name, data) {
20
- this.ensureInitialized();
19
+ // Silently ignore events after destroy instead of throwing error
20
+ if (!this.initialized) {
21
+ return;
22
+ }
21
23
  super.sendCustomEvent(name, data);
22
24
  }
23
25
  getSessionData() {
@@ -30,8 +32,7 @@ class TestBridge extends app_1.App {
30
32
  setSessionTimeout(timeout) {
31
33
  const config = this.get('config');
32
34
  if (config) {
33
- const { config: normalizedConfig } = (0, utils_1.normalizeConfig)({ ...config, sessionTimeout: timeout });
34
- this.set('config', normalizedConfig);
35
+ this.set('config', { ...config, sessionTimeout: timeout });
35
36
  }
36
37
  }
37
38
  getQueueLength() {
@@ -40,6 +41,29 @@ class TestBridge extends app_1.App {
40
41
  forceInitLock(enabled = true) {
41
42
  this._isInitializing = enabled;
42
43
  }
44
+ simulatePersistedEvents(events) {
45
+ const storageManager = this.managers?.storage;
46
+ if (!storageManager) {
47
+ throw new Error('Storage manager not available');
48
+ }
49
+ const projectId = this.get('config')?.id;
50
+ const userId = this.get('userId');
51
+ const sessionId = this.get('sessionId');
52
+ if (!projectId || !userId) {
53
+ throw new Error('Project ID or User ID not available. Initialize TraceLog first.');
54
+ }
55
+ // Build the persisted data structure matching what SenderManager expects
56
+ const persistedData = {
57
+ userId,
58
+ sessionId: sessionId || `test-session-${Date.now()}`,
59
+ device: 'desktop',
60
+ events,
61
+ timestamp: Date.now(),
62
+ };
63
+ // Store in the same format as SenderManager.persistEvents()
64
+ const storageKey = `tl:${projectId}:queue:${userId}`;
65
+ storageManager.setItem(storageKey, JSON.stringify(persistedData));
66
+ }
43
67
  get(key) {
44
68
  return super.get(key);
45
69
  }
@@ -73,12 +97,15 @@ class TestBridge extends app_1.App {
73
97
  getGoogleAnalytics() {
74
98
  return this.safeAccess(this.integrations?.googleAnalytics);
75
99
  }
76
- async destroy() {
77
- this.ensureInitialized();
100
+ async destroy(force = false) {
101
+ // If not initialized and not forcing, silently return (no-op)
102
+ if (!this.initialized && !force) {
103
+ return;
104
+ }
78
105
  this.ensureNotDestroying();
79
106
  this._isDestroying = true;
80
107
  try {
81
- await super.destroy();
108
+ await super.destroy(force);
82
109
  }
83
110
  finally {
84
111
  this._isDestroying = false;
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Special project IDs for testing and development
3
3
  *
4
- * Both automatically force mode: 'debug' but differ in HTTP behavior:
4
+ * All automatically force mode: 'debug' but differ in HTTP behavior:
5
5
  * - Skip: NO network calls (pure offline testing)
6
6
  * - Localhost: Makes network calls to local server (integration testing)
7
+ * - Fail: Makes network calls that intentionally fail (persistence testing)
7
8
  */
8
9
  export declare enum SpecialProjectId {
9
10
  /**
@@ -20,17 +21,32 @@ export declare enum SpecialProjectId {
20
21
  */
21
22
  Skip = "skip",
22
23
  /**
23
- * Value: 'localhost:' (used as prefix)
24
+ * Value: 'localhost:8080'
24
25
  *
25
- * Makes HTTP calls to local development server
26
- * Must specify full address: 'localhost:PORT' (e.g., 'localhost:3000')
27
- * Converts to http://localhost:PORT/config for requests
26
+ * Makes HTTP calls to local development server on port 8080
27
+ * Converts to http://localhost:8080/config for requests
28
28
  * Requires origin to be in ALLOWED_ORIGINS list, forces debug mode
29
29
  * Perfect for local development with running middleware
30
30
  *
31
31
  * @example
32
- * await TraceLog.init({ id: 'localhost:3000' });
33
- * // Makes requests to: http://localhost:3000/config
32
+ * await TraceLog.init({ id: SpecialProjectId.Localhost });
33
+ * // or
34
+ * await TraceLog.init({ id: 'localhost:8080' });
35
+ * // Makes requests to: http://localhost:8080/config
36
+ */
37
+ Localhost = "localhost:8080",
38
+ /**
39
+ * Value: 'localhost:9999'
40
+ *
41
+ * Makes HTTP calls to non-existent server (port 9999)
42
+ * All HTTP requests will fail naturally, triggering persistence
43
+ * Forces debug mode, perfect for testing event persistence & recovery
44
+ *
45
+ * @example
46
+ * await TraceLog.init({ id: SpecialProjectId.Fail });
47
+ * // or
48
+ * await TraceLog.init({ id: 'localhost:9999' });
49
+ * // Makes requests to: http://localhost:9999 (will fail)
34
50
  */
35
- Localhost = "localhost:"
51
+ Fail = "localhost:9999"
36
52
  }
@@ -4,9 +4,10 @@ exports.SpecialProjectId = void 0;
4
4
  /**
5
5
  * Special project IDs for testing and development
6
6
  *
7
- * Both automatically force mode: 'debug' but differ in HTTP behavior:
7
+ * All automatically force mode: 'debug' but differ in HTTP behavior:
8
8
  * - Skip: NO network calls (pure offline testing)
9
9
  * - Localhost: Makes network calls to local server (integration testing)
10
+ * - Fail: Makes network calls that intentionally fail (persistence testing)
10
11
  */
11
12
  var SpecialProjectId;
12
13
  (function (SpecialProjectId) {
@@ -24,17 +25,32 @@ var SpecialProjectId;
24
25
  */
25
26
  SpecialProjectId["Skip"] = "skip";
26
27
  /**
27
- * Value: 'localhost:' (used as prefix)
28
+ * Value: 'localhost:8080'
28
29
  *
29
- * Makes HTTP calls to local development server
30
- * Must specify full address: 'localhost:PORT' (e.g., 'localhost:3000')
31
- * Converts to http://localhost:PORT/config for requests
30
+ * Makes HTTP calls to local development server on port 8080
31
+ * Converts to http://localhost:8080/config for requests
32
32
  * Requires origin to be in ALLOWED_ORIGINS list, forces debug mode
33
33
  * Perfect for local development with running middleware
34
34
  *
35
35
  * @example
36
- * await TraceLog.init({ id: 'localhost:3000' });
37
- * // Makes requests to: http://localhost:3000/config
36
+ * await TraceLog.init({ id: SpecialProjectId.Localhost });
37
+ * // or
38
+ * await TraceLog.init({ id: 'localhost:8080' });
39
+ * // Makes requests to: http://localhost:8080/config
40
+ */
41
+ SpecialProjectId["Localhost"] = "localhost:8080";
42
+ /**
43
+ * Value: 'localhost:9999'
44
+ *
45
+ * Makes HTTP calls to non-existent server (port 9999)
46
+ * All HTTP requests will fail naturally, triggering persistence
47
+ * Forces debug mode, perfect for testing event persistence & recovery
48
+ *
49
+ * @example
50
+ * await TraceLog.init({ id: SpecialProjectId.Fail });
51
+ * // or
52
+ * await TraceLog.init({ id: 'localhost:9999' });
53
+ * // Makes requests to: http://localhost:9999 (will fail)
38
54
  */
39
- SpecialProjectId["Localhost"] = "localhost:";
55
+ SpecialProjectId["Fail"] = "localhost:9999";
40
56
  })(SpecialProjectId || (exports.SpecialProjectId = SpecialProjectId = {}));