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