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