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