@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
@@ -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,12 +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
157
- this.eventManager.track({
158
- type: types_1.EventType.SESSION_START,
159
- ...(isRecovered && { session_start_recovered: true }),
160
- });
161
- // Initialize components
145
+ if (!isRecovered) {
146
+ this.eventManager.track({
147
+ type: types_1.EventType.SESSION_START,
148
+ });
149
+ }
162
150
  this.initCrossTabSync();
163
151
  this.shareSession(sessionId);
164
152
  this.setupSessionTimeout();
@@ -176,15 +164,9 @@ class SessionManager extends state_manager_1.StateManager {
176
164
  throw error;
177
165
  }
178
166
  }
179
- /**
180
- * Generate unique session ID
181
- */
182
167
  generateSessionId() {
183
168
  return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
184
169
  }
185
- /**
186
- * Setup session timeout
187
- */
188
170
  setupSessionTimeout() {
189
171
  this.clearSessionTimeout();
190
172
  const sessionTimeout = this.get('config')?.sessionTimeout ?? constants_1.DEFAULT_SESSION_TIMEOUT;
@@ -192,9 +174,6 @@ class SessionManager extends state_manager_1.StateManager {
192
174
  this.endSession('inactivity');
193
175
  }, sessionTimeout);
194
176
  }
195
- /**
196
- * Reset session timeout and update activity
197
- */
198
177
  resetSessionTimeout() {
199
178
  this.setupSessionTimeout();
200
179
  const sessionId = this.get('sessionId');
@@ -202,27 +181,18 @@ class SessionManager extends state_manager_1.StateManager {
202
181
  this.persistSession(sessionId);
203
182
  }
204
183
  }
205
- /**
206
- * Clear session timeout
207
- */
208
184
  clearSessionTimeout() {
209
185
  if (this.sessionTimeoutId) {
210
186
  clearTimeout(this.sessionTimeoutId);
211
187
  this.sessionTimeoutId = null;
212
188
  }
213
189
  }
214
- /**
215
- * Setup activity listeners to track user engagement
216
- */
217
190
  setupActivityListeners() {
218
191
  this.activityHandler = () => this.resetSessionTimeout();
219
192
  document.addEventListener('click', this.activityHandler, { passive: true });
220
193
  document.addEventListener('keydown', this.activityHandler, { passive: true });
221
194
  document.addEventListener('scroll', this.activityHandler, { passive: true });
222
195
  }
223
- /**
224
- * Clean up activity listeners
225
- */
226
196
  cleanupActivityListeners() {
227
197
  if (this.activityHandler) {
228
198
  document.removeEventListener('click', this.activityHandler);
@@ -231,9 +201,6 @@ class SessionManager extends state_manager_1.StateManager {
231
201
  this.activityHandler = null;
232
202
  }
233
203
  }
234
- /**
235
- * Setup page lifecycle listeners (visibility and unload)
236
- */
237
204
  setupLifecycleListeners() {
238
205
  if (this.visibilityChangeHandler || this.beforeUnloadHandler) {
239
206
  return;
@@ -252,9 +219,7 @@ class SessionManager extends state_manager_1.StateManager {
252
219
  this.beforeUnloadHandler = () => {
253
220
  this.endSession('page_unload');
254
221
  };
255
- // Handle tab visibility changes
256
222
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
257
- // Handle page unload
258
223
  window.addEventListener('beforeunload', this.beforeUnloadHandler);
259
224
  }
260
225
  cleanupLifecycleListeners() {
@@ -267,14 +232,11 @@ class SessionManager extends state_manager_1.StateManager {
267
232
  this.beforeUnloadHandler = null;
268
233
  }
269
234
  }
270
- /**
271
- * End current session
272
- */
273
- endSession(reason) {
235
+ async endSession(reason) {
274
236
  const sessionId = this.get('sessionId');
275
237
  if (!sessionId) {
276
238
  logging_1.debugLog.warn('SessionManager', 'endSession called without active session', { reason });
277
- this.resetSessionState();
239
+ this.resetSessionState(reason);
278
240
  return;
279
241
  }
280
242
  logging_1.debugLog.info('SessionManager', 'Ending session', { sessionId, reason });
@@ -284,42 +246,39 @@ class SessionManager extends state_manager_1.StateManager {
284
246
  });
285
247
  const finalize = () => {
286
248
  this.broadcastSessionEnd(sessionId, reason);
287
- this.resetSessionState();
249
+ this.resetSessionState(reason);
288
250
  };
289
251
  const flushResult = this.eventManager.flushImmediatelySync();
290
252
  if (flushResult) {
291
253
  finalize();
292
254
  return;
293
255
  }
294
- this.eventManager
295
- .flushImmediately()
296
- .then(finalize)
297
- .catch((error) => {
256
+ try {
257
+ await this.eventManager.flushImmediately();
258
+ finalize();
259
+ }
260
+ catch (error) {
298
261
  logging_1.debugLog.warn('SessionManager', 'Async flush failed during session end', {
299
262
  error: error instanceof Error ? error.message : 'Unknown error',
300
263
  });
301
264
  finalize();
302
- });
265
+ }
303
266
  }
304
- resetSessionState() {
267
+ resetSessionState(reason) {
305
268
  this.clearSessionTimeout();
306
269
  this.cleanupActivityListeners();
307
270
  this.cleanupLifecycleListeners();
308
271
  this.cleanupCrossTabSync();
309
- this.clearStoredSession();
272
+ if (reason !== 'page_unload') {
273
+ this.clearStoredSession();
274
+ }
310
275
  this.set('sessionId', null);
311
276
  this.set('hasStartSession', false);
312
277
  this.isTracking = false;
313
278
  }
314
- /**
315
- * Stop session tracking
316
- */
317
279
  async stopTracking() {
318
- this.endSession('manual_stop');
280
+ await this.endSession('manual_stop');
319
281
  }
320
- /**
321
- * Clean up all resources
322
- */
323
282
  destroy() {
324
283
  this.clearSessionTimeout();
325
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 = {}));