@syntropysoft/syntropyfront 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -7,33 +7,33 @@ Object.defineProperty(exports, '__esModule', { value: true });
7
7
  * Responsabilidad única: Almacenar y gestionar breadcrumbs
8
8
  */
9
9
  class BreadcrumbManager {
10
- constructor() {
11
- this.breadcrumbs = [];
12
- }
13
-
14
- add(category, message, data = {}) {
15
- const breadcrumb = {
16
- category,
17
- message,
18
- data,
19
- timestamp: new Date().toISOString()
20
- };
10
+ constructor() {
11
+ this.breadcrumbs = [];
12
+ }
13
+
14
+ add(category, message, data = {}) {
15
+ const breadcrumb = {
16
+ category,
17
+ message,
18
+ data,
19
+ timestamp: new Date().toISOString()
20
+ };
21
21
 
22
- this.breadcrumbs.push(breadcrumb);
23
- return breadcrumb;
24
- }
22
+ this.breadcrumbs.push(breadcrumb);
23
+ return breadcrumb;
24
+ }
25
25
 
26
- getAll() {
27
- return this.breadcrumbs;
28
- }
26
+ getAll() {
27
+ return this.breadcrumbs;
28
+ }
29
29
 
30
- clear() {
31
- this.breadcrumbs = [];
32
- }
30
+ clear() {
31
+ this.breadcrumbs = [];
32
+ }
33
33
 
34
- getCount() {
35
- return this.breadcrumbs.length;
36
- }
34
+ getCount() {
35
+ return this.breadcrumbs.length;
36
+ }
37
37
  }
38
38
 
39
39
  /**
@@ -41,33 +41,33 @@ class BreadcrumbManager {
41
41
  * Responsabilidad única: Formatear y gestionar errores
42
42
  */
43
43
  class ErrorManager {
44
- constructor() {
45
- this.errors = [];
46
- }
47
-
48
- send(error, context = {}) {
49
- const errorData = {
50
- message: error.message,
51
- stack: error.stack,
52
- context,
53
- timestamp: new Date().toISOString()
54
- };
44
+ constructor() {
45
+ this.errors = [];
46
+ }
47
+
48
+ send(error, context = {}) {
49
+ const errorData = {
50
+ message: error.message,
51
+ stack: error.stack,
52
+ context,
53
+ timestamp: new Date().toISOString()
54
+ };
55
55
 
56
- this.errors.push(errorData);
57
- return errorData;
58
- }
56
+ this.errors.push(errorData);
57
+ return errorData;
58
+ }
59
59
 
60
- getAll() {
61
- return this.errors;
62
- }
60
+ getAll() {
61
+ return this.errors;
62
+ }
63
63
 
64
- clear() {
65
- this.errors = [];
66
- }
64
+ clear() {
65
+ this.errors = [];
66
+ }
67
67
 
68
- getCount() {
69
- return this.errors.length;
70
- }
68
+ getCount() {
69
+ return this.errors.length;
70
+ }
71
71
  }
72
72
 
73
73
  /**
@@ -75,48 +75,48 @@ class ErrorManager {
75
75
  * Responsabilidad única: Mostrar mensajes solo cuando hay errores
76
76
  */
77
77
  class Logger {
78
- constructor() {
79
- this.isSilent = true; // Por defecto silente
80
- }
78
+ constructor() {
79
+ this.isSilent = true; // Por defecto silente
80
+ }
81
81
 
82
- log(message, data = null) {
83
- // No loggear nada en modo silente
84
- if (this.isSilent) return;
82
+ log(message, data = null) {
83
+ // No loggear nada en modo silente
84
+ if (this.isSilent) return;
85
85
 
86
- if (data) {
87
- console.log(message, data);
88
- } else {
89
- console.log(message);
90
- }
91
- }
92
-
93
- error(message, data = null) {
94
- // SIEMPRE loggear errores
95
- if (data) {
96
- console.error(message, data);
97
- } else {
98
- console.error(message);
99
- }
100
- }
101
-
102
- warn(message, data = null) {
103
- // Solo warnings importantes
104
- if (data) {
105
- console.warn(message, data);
106
- } else {
107
- console.warn(message);
108
- }
109
- }
110
-
111
- // Método para activar logging (solo para debug)
112
- enableLogging() {
113
- this.isSilent = false;
114
- }
115
-
116
- // Método para desactivar logging
117
- disableLogging() {
118
- this.isSilent = true;
119
- }
86
+ if (data) {
87
+ console.log(message, data);
88
+ } else {
89
+ console.log(message);
90
+ }
91
+ }
92
+
93
+ error(message, data = null) {
94
+ // SIEMPRE loggear errores (ignora modo silencioso)
95
+ if (data) {
96
+ console.error(message, data);
97
+ } else {
98
+ console.error(message);
99
+ }
100
+ }
101
+
102
+ warn(message, data = null) {
103
+ // Solo warnings importantes
104
+ if (data) {
105
+ console.warn(message, data);
106
+ } else {
107
+ console.warn(message);
108
+ }
109
+ }
110
+
111
+ // Método para activar logging (solo para debug)
112
+ enableLogging() {
113
+ this.isSilent = false;
114
+ }
115
+
116
+ // Método para desactivar logging
117
+ disableLogging() {
118
+ this.isSilent = true;
119
+ }
120
120
  }
121
121
 
122
122
  /**
@@ -125,35 +125,35 @@ class Logger {
125
125
  */
126
126
 
127
127
  class SyntropyFront {
128
- constructor() {
129
- // Basic managers
130
- this.breadcrumbManager = new BreadcrumbManager();
131
- this.errorManager = new ErrorManager();
132
- this.logger = new Logger();
128
+ constructor() {
129
+ // Basic managers
130
+ this.breadcrumbManager = new BreadcrumbManager();
131
+ this.errorManager = new ErrorManager();
132
+ this.logger = new Logger();
133
133
 
134
- // Default configuration
135
- this.maxEvents = 50;
136
- this.fetchConfig = null; // Complete fetch configuration
137
- this.onErrorCallback = null; // User-defined error handler
138
- this.isActive = false;
134
+ // Default configuration
135
+ this.maxEvents = 50;
136
+ this.fetchConfig = null; // Complete fetch configuration
137
+ this.onErrorCallback = null; // User-defined error handler
138
+ this.isActive = false;
139
139
 
140
- // Automatic capture
141
- this.originalHandlers = {};
140
+ // Automatic capture
141
+ this.originalHandlers = {};
142
142
 
143
- // Auto-initialize
144
- this.init();
145
- }
143
+ // Auto-initialize
144
+ this.init();
145
+ }
146
146
 
147
- init() {
148
- this.isActive = true;
147
+ init() {
148
+ this.isActive = true;
149
149
 
150
- // Configure automatic capture immediately
151
- this.setupAutomaticCapture();
150
+ // Configure automatic capture immediately
151
+ this.setupAutomaticCapture();
152
152
 
153
- console.log('🚀 SyntropyFront: Initialized with automatic capture');
154
- }
153
+ console.log('🚀 SyntropyFront: Initialized with automatic capture');
154
+ }
155
155
 
156
- /**
156
+ /**
157
157
  * Configure SyntropyFront
158
158
  * @param {Object} config - Configuration
159
159
  * @param {number} config.maxEvents - Maximum number of events to store
@@ -162,266 +162,266 @@ class SyntropyFront {
162
162
  * @param {Object} config.fetch.options - Fetch options (headers, method, etc.)
163
163
  * @param {Function} config.onError - User-defined error handler callback
164
164
  */
165
- configure(config = {}) {
166
- this.maxEvents = config.maxEvents || this.maxEvents;
167
- this.fetchConfig = config.fetch;
168
- this.onErrorCallback = config.onError;
165
+ configure(config = {}) {
166
+ this.maxEvents = config.maxEvents || this.maxEvents;
167
+ this.fetchConfig = config.fetch;
168
+ this.onErrorCallback = config.onError;
169
169
 
170
- if (this.onErrorCallback) {
171
- console.log(`✅ SyntropyFront: Configured - maxEvents: ${this.maxEvents}, custom error handler`);
172
- } else if (this.fetchConfig) {
173
- console.log(`✅ SyntropyFront: Configured - maxEvents: ${this.maxEvents}, endpoint: ${this.fetchConfig.url}`);
174
- } else {
175
- console.log(`✅ SyntropyFront: Configured - maxEvents: ${this.maxEvents}, console only`);
176
- }
170
+ if (this.onErrorCallback) {
171
+ console.log(`✅ SyntropyFront: Configured - maxEvents: ${this.maxEvents}, custom error handler`);
172
+ } else if (this.fetchConfig) {
173
+ console.log(`✅ SyntropyFront: Configured - maxEvents: ${this.maxEvents}, endpoint: ${this.fetchConfig.url}`);
174
+ } else {
175
+ console.log(`✅ SyntropyFront: Configured - maxEvents: ${this.maxEvents}, console only`);
177
176
  }
177
+ }
178
178
 
179
- /**
179
+ /**
180
180
  * Configure automatic event capture
181
181
  */
182
- setupAutomaticCapture() {
183
- if (typeof window === 'undefined') return;
182
+ setupAutomaticCapture() {
183
+ if (typeof window === 'undefined') return;
184
184
 
185
- // Capture clicks
186
- this.setupClickCapture();
185
+ // Capture clicks
186
+ this.setupClickCapture();
187
187
 
188
- // Capture errors
189
- this.setupErrorCapture();
188
+ // Capture errors
189
+ this.setupErrorCapture();
190
190
 
191
- // Capture HTTP calls
192
- this.setupHttpCapture();
191
+ // Capture HTTP calls
192
+ this.setupHttpCapture();
193
193
 
194
- // Capture console logs
195
- this.setupConsoleCapture();
196
- }
194
+ // Capture console logs
195
+ this.setupConsoleCapture();
196
+ }
197
197
 
198
- /**
198
+ /**
199
199
  * Capture user clicks
200
200
  */
201
- setupClickCapture() {
202
- const clickHandler = (event) => {
203
- const element = event.target;
204
- this.addBreadcrumb('user', 'click', {
205
- element: element.tagName,
206
- id: element.id,
207
- className: element.className,
208
- x: event.clientX,
209
- y: event.clientY
210
- });
211
- };
212
-
213
- document.addEventListener('click', clickHandler);
214
- }
215
-
216
- /**
201
+ setupClickCapture() {
202
+ const clickHandler = (event) => {
203
+ const element = event.target;
204
+ this.addBreadcrumb('user', 'click', {
205
+ element: element.tagName,
206
+ id: element.id,
207
+ className: element.className,
208
+ x: event.clientX,
209
+ y: event.clientY
210
+ });
211
+ };
212
+
213
+ document.addEventListener('click', clickHandler);
214
+ }
215
+
216
+ /**
217
217
  * Automatically capture errors
218
218
  */
219
- setupErrorCapture() {
220
- // Save original handlers
221
- this.originalHandlers.onerror = window.onerror;
222
- this.originalHandlers.onunhandledrejection = window.onunhandledrejection;
223
-
224
- // Intercept errors
225
- window.onerror = (message, source, lineno, colno, error) => {
226
- const errorPayload = {
227
- type: 'uncaught_exception',
228
- error: { message, source, lineno, colno, stack: error?.stack },
229
- breadcrumbs: this.getBreadcrumbs(),
230
- timestamp: new Date().toISOString()
231
- };
232
-
233
- this.handleError(errorPayload);
219
+ setupErrorCapture() {
220
+ // Save original handlers
221
+ this.originalHandlers.onerror = window.onerror;
222
+ this.originalHandlers.onunhandledrejection = window.onunhandledrejection;
223
+
224
+ // Intercept errors
225
+ window.onerror = (message, source, lineno, colno, error) => {
226
+ const errorPayload = {
227
+ type: 'uncaught_exception',
228
+ error: { message, source, lineno, colno, stack: error?.stack },
229
+ breadcrumbs: this.getBreadcrumbs(),
230
+ timestamp: new Date().toISOString()
231
+ };
232
+
233
+ this.handleError(errorPayload);
234
234
 
235
- // Call original handler
236
- if (this.originalHandlers.onerror) {
237
- return this.originalHandlers.onerror(message, source, lineno, colno, error);
238
- }
235
+ // Call original handler
236
+ if (this.originalHandlers.onerror) {
237
+ return this.originalHandlers.onerror(message, source, lineno, colno, error);
238
+ }
239
239
 
240
- return false;
241
- };
242
-
243
- // Intercept rejected promises
244
- window.onunhandledrejection = (event) => {
245
- const errorPayload = {
246
- type: 'unhandled_rejection',
247
- error: {
248
- message: event.reason?.message || 'Promise rejection without message',
249
- stack: event.reason?.stack,
250
- },
251
- breadcrumbs: this.getBreadcrumbs(),
252
- timestamp: new Date().toISOString()
253
- };
254
-
255
- this.handleError(errorPayload);
240
+ return false;
241
+ };
242
+
243
+ // Intercept rejected promises
244
+ window.onunhandledrejection = (event) => {
245
+ const errorPayload = {
246
+ type: 'unhandled_rejection',
247
+ error: {
248
+ message: event.reason?.message || 'Promise rejection without message',
249
+ stack: event.reason?.stack,
250
+ },
251
+ breadcrumbs: this.getBreadcrumbs(),
252
+ timestamp: new Date().toISOString()
253
+ };
254
+
255
+ this.handleError(errorPayload);
256
256
 
257
- // Call original handler
258
- if (this.originalHandlers.onunhandledrejection) {
259
- this.originalHandlers.onunhandledrejection(event);
260
- }
261
- };
262
- }
263
-
264
- /**
257
+ // Call original handler
258
+ if (this.originalHandlers.onunhandledrejection) {
259
+ this.originalHandlers.onunhandledrejection(event);
260
+ }
261
+ };
262
+ }
263
+
264
+ /**
265
265
  * Capture HTTP calls
266
266
  */
267
- setupHttpCapture() {
268
- // Intercept fetch
269
- const originalFetch = window.fetch;
270
- window.fetch = (...args) => {
271
- const [url, options] = args;
267
+ setupHttpCapture() {
268
+ // Intercept fetch
269
+ const originalFetch = window.fetch;
270
+ window.fetch = (...args) => {
271
+ const [url, options] = args;
272
272
 
273
- this.addBreadcrumb('http', 'fetch', {
274
- url,
275
- method: options?.method || 'GET'
276
- });
277
-
278
- return originalFetch(...args).then(response => {
279
- this.addBreadcrumb('http', 'fetch_response', {
280
- url,
281
- status: response.status
282
- });
283
- return response;
284
- }).catch(error => {
285
- this.addBreadcrumb('http', 'fetch_error', {
286
- url,
287
- error: error.message
288
- });
289
- throw error;
290
- });
291
- };
292
- }
273
+ this.addBreadcrumb('http', 'fetch', {
274
+ url,
275
+ method: options?.method || 'GET'
276
+ });
277
+
278
+ return originalFetch(...args).then(response => {
279
+ this.addBreadcrumb('http', 'fetch_response', {
280
+ url,
281
+ status: response.status
282
+ });
283
+ return response;
284
+ }).catch(error => {
285
+ this.addBreadcrumb('http', 'fetch_error', {
286
+ url,
287
+ error: error.message
288
+ });
289
+ throw error;
290
+ });
291
+ };
292
+ }
293
293
 
294
- /**
294
+ /**
295
295
  * Capture console logs
296
296
  */
297
- setupConsoleCapture() {
298
- const originalLog = console.log;
299
- const originalError = console.error;
300
- const originalWarn = console.warn;
301
-
302
- console.log = (...args) => {
303
- this.addBreadcrumb('console', 'log', { message: args.join(' ') });
304
- originalLog.apply(console, args);
305
- };
306
-
307
- console.error = (...args) => {
308
- this.addBreadcrumb('console', 'error', { message: args.join(' ') });
309
- originalError.apply(console, args);
310
- };
311
-
312
- console.warn = (...args) => {
313
- this.addBreadcrumb('console', 'warn', { message: args.join(' ') });
314
- originalWarn.apply(console, args);
315
- };
316
- }
317
-
318
- /**
297
+ setupConsoleCapture() {
298
+ const originalLog = console.log;
299
+ const originalError = console.error;
300
+ const originalWarn = console.warn;
301
+
302
+ console.log = (...args) => {
303
+ this.addBreadcrumb('console', 'log', { message: args.join(' ') });
304
+ originalLog.apply(console, args);
305
+ };
306
+
307
+ console.error = (...args) => {
308
+ this.addBreadcrumb('console', 'error', { message: args.join(' ') });
309
+ originalError.apply(console, args);
310
+ };
311
+
312
+ console.warn = (...args) => {
313
+ this.addBreadcrumb('console', 'warn', { message: args.join(' ') });
314
+ originalWarn.apply(console, args);
315
+ };
316
+ }
317
+
318
+ /**
319
319
  * Handle errors - priority: onError callback > fetch > console
320
320
  */
321
- handleError(errorPayload) {
322
- // Default log
323
- this.logger.error('❌ Error:', errorPayload);
324
-
325
- // Priority 1: User-defined callback (maximum flexibility)
326
- if (this.onErrorCallback) {
327
- try {
328
- this.onErrorCallback(errorPayload);
329
- } catch (callbackError) {
330
- console.warn('SyntropyFront: Error in user callback:', callbackError);
331
- }
332
- return;
333
- }
321
+ handleError(errorPayload) {
322
+ // Default log
323
+ this.logger.error('❌ Error:', errorPayload);
334
324
 
335
- // Priority 2: Fetch to endpoint
336
- if (this.fetchConfig) {
337
- this.postToEndpoint(errorPayload);
338
- return;
339
- }
325
+ // Priority 1: User-defined callback (maximum flexibility)
326
+ if (this.onErrorCallback) {
327
+ try {
328
+ this.onErrorCallback(errorPayload);
329
+ } catch (callbackError) {
330
+ console.warn('SyntropyFront: Error in user callback:', callbackError);
331
+ }
332
+ return;
333
+ }
340
334
 
341
- // Priority 3: Console only (default)
342
- // Already logged above
335
+ // Priority 2: Fetch to endpoint
336
+ if (this.fetchConfig) {
337
+ this.postToEndpoint(errorPayload);
338
+ return;
343
339
  }
340
+
341
+ // Priority 3: Console only (default)
342
+ // Already logged above
343
+ }
344
344
 
345
- /**
345
+ /**
346
346
  * Post error object using fetch configuration
347
347
  */
348
- postToEndpoint(errorPayload) {
349
- const { url, options = {} } = this.fetchConfig;
348
+ postToEndpoint(errorPayload) {
349
+ const { url, options = {} } = this.fetchConfig;
350
350
 
351
- // Default configuration
352
- const defaultOptions = {
353
- method: 'POST',
354
- headers: {
355
- 'Content-Type': 'application/json',
356
- ...options.headers
357
- },
358
- body: JSON.stringify(errorPayload),
359
- ...options
360
- };
361
-
362
- fetch(url, defaultOptions).catch(error => {
363
- console.warn('SyntropyFront: Error posting to endpoint:', error);
364
- });
365
- }
366
-
367
- // Public API
368
- addBreadcrumb(category, message, data = {}) {
369
- if (!this.isActive) return;
370
-
371
- const breadcrumb = this.breadcrumbManager.add(category, message, data);
351
+ // Default configuration
352
+ const defaultOptions = {
353
+ method: 'POST',
354
+ headers: {
355
+ 'Content-Type': 'application/json',
356
+ ...options.headers
357
+ },
358
+ body: JSON.stringify(errorPayload),
359
+ ...options
360
+ };
361
+
362
+ fetch(url, defaultOptions).catch(error => {
363
+ console.warn('SyntropyFront: Error posting to endpoint:', error);
364
+ });
365
+ }
366
+
367
+ // Public API
368
+ addBreadcrumb(category, message, data = {}) {
369
+ if (!this.isActive) return;
372
370
 
373
- // Keep only the last maxEvents
374
- const breadcrumbs = this.breadcrumbManager.getAll();
375
- if (breadcrumbs.length > this.maxEvents) {
376
- this.breadcrumbManager.clear();
377
- breadcrumbs.slice(-this.maxEvents).forEach(b => this.breadcrumbManager.add(b.category, b.message, b.data));
378
- }
371
+ const breadcrumb = this.breadcrumbManager.add(category, message, data);
379
372
 
380
- return breadcrumb;
373
+ // Keep only the last maxEvents
374
+ const breadcrumbs = this.breadcrumbManager.getAll();
375
+ if (breadcrumbs.length > this.maxEvents) {
376
+ this.breadcrumbManager.clear();
377
+ breadcrumbs.slice(-this.maxEvents).forEach(b => this.breadcrumbManager.add(b.category, b.message, b.data));
381
378
  }
379
+
380
+ return breadcrumb;
381
+ }
382
382
 
383
- getBreadcrumbs() {
384
- return this.breadcrumbManager.getAll();
385
- }
383
+ getBreadcrumbs() {
384
+ return this.breadcrumbManager.getAll();
385
+ }
386
386
 
387
- clearBreadcrumbs() {
388
- this.breadcrumbManager.clear();
389
- }
387
+ clearBreadcrumbs() {
388
+ this.breadcrumbManager.clear();
389
+ }
390
390
 
391
- sendError(error, context = {}) {
392
- if (!this.isActive) return;
391
+ sendError(error, context = {}) {
392
+ if (!this.isActive) return;
393
393
 
394
- const errorData = this.errorManager.send(error, context);
395
- const errorPayload = {
396
- ...errorData,
397
- breadcrumbs: this.getBreadcrumbs(),
398
- timestamp: new Date().toISOString()
399
- };
394
+ const errorData = this.errorManager.send(error, context);
395
+ const errorPayload = {
396
+ ...errorData,
397
+ breadcrumbs: this.getBreadcrumbs(),
398
+ timestamp: new Date().toISOString()
399
+ };
400
400
 
401
- this.handleError(errorPayload);
402
- return errorData;
403
- }
404
-
405
- getErrors() {
406
- return this.errorManager.getAll();
407
- }
408
-
409
- clearErrors() {
410
- this.errorManager.clear();
411
- }
412
-
413
- // Utility methods
414
- getStats() {
415
- return {
416
- breadcrumbs: this.breadcrumbManager.getCount(),
417
- errors: this.errorManager.getCount(),
418
- isActive: this.isActive,
419
- maxEvents: this.maxEvents,
420
- hasFetchConfig: !!this.fetchConfig,
421
- hasErrorCallback: !!this.onErrorCallback,
422
- endpoint: this.fetchConfig?.url || 'console'
423
- };
424
- }
401
+ this.handleError(errorPayload);
402
+ return errorData;
403
+ }
404
+
405
+ getErrors() {
406
+ return this.errorManager.getAll();
407
+ }
408
+
409
+ clearErrors() {
410
+ this.errorManager.clear();
411
+ }
412
+
413
+ // Utility methods
414
+ getStats() {
415
+ return {
416
+ breadcrumbs: this.breadcrumbManager.getCount(),
417
+ errors: this.errorManager.getCount(),
418
+ isActive: this.isActive,
419
+ maxEvents: this.maxEvents,
420
+ hasFetchConfig: !!this.fetchConfig,
421
+ hasErrorCallback: !!this.onErrorCallback,
422
+ endpoint: this.fetchConfig?.url || 'console'
423
+ };
424
+ }
425
425
  }
426
426
 
427
427
  // Single instance - auto-initializes