@error-explorer/vue 1.1.1
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/README.md +312 -0
- package/dist/index.cjs +658 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +433 -0
- package/dist/index.d.ts +433 -0
- package/dist/index.js +639 -0
- package/dist/index.js.map +1 -0
- package/dist/router.cjs +143 -0
- package/dist/router.cjs.map +1 -0
- package/dist/router.d.cts +56 -0
- package/dist/router.d.ts +56 -0
- package/dist/router.js +140 -0
- package/dist/router.js.map +1 -0
- package/package.json +82 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
import { ErrorExplorer } from '@error-explorer/browser';
|
|
2
|
+
export { ErrorExplorer } from '@error-explorer/browser';
|
|
3
|
+
import { defineComponent, ref, onErrorCaptured, h, inject, getCurrentInstance, onMounted, onUnmounted } from 'vue';
|
|
4
|
+
|
|
5
|
+
// src/plugin.ts
|
|
6
|
+
function getComponentName(instance) {
|
|
7
|
+
if (!instance) return void 0;
|
|
8
|
+
const options = instance.$.type;
|
|
9
|
+
return options.name || options.__name || extractNameFromFile(options.__file);
|
|
10
|
+
}
|
|
11
|
+
function extractNameFromFile(file) {
|
|
12
|
+
if (!file) return void 0;
|
|
13
|
+
const match = file.match(/([^/\\]+)\.vue$/);
|
|
14
|
+
return match ? match[1] : void 0;
|
|
15
|
+
}
|
|
16
|
+
function getComponentTrace(instance) {
|
|
17
|
+
const trace = [];
|
|
18
|
+
let current = instance;
|
|
19
|
+
while (current) {
|
|
20
|
+
const name = getComponentName(current);
|
|
21
|
+
if (name) {
|
|
22
|
+
trace.push(name);
|
|
23
|
+
}
|
|
24
|
+
current = current.$.parent?.proxy ?? null;
|
|
25
|
+
}
|
|
26
|
+
return trace;
|
|
27
|
+
}
|
|
28
|
+
function serializeProps(props, maxDepth) {
|
|
29
|
+
const serialize = (value, depth) => {
|
|
30
|
+
if (depth > maxDepth) {
|
|
31
|
+
return "[Max depth reached]";
|
|
32
|
+
}
|
|
33
|
+
if (value === null || value === void 0) {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
if (typeof value === "function") {
|
|
37
|
+
return "[Function]";
|
|
38
|
+
}
|
|
39
|
+
if (typeof value === "symbol") {
|
|
40
|
+
return value.toString();
|
|
41
|
+
}
|
|
42
|
+
if (value instanceof Date) {
|
|
43
|
+
return value.toISOString();
|
|
44
|
+
}
|
|
45
|
+
if (value instanceof Error) {
|
|
46
|
+
return { name: value.name, message: value.message };
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return value.slice(0, 10).map((item) => serialize(item, depth + 1));
|
|
50
|
+
}
|
|
51
|
+
if (typeof value === "object") {
|
|
52
|
+
const serialized = {};
|
|
53
|
+
const keys = Object.keys(value).slice(0, 20);
|
|
54
|
+
for (const key of keys) {
|
|
55
|
+
serialized[key] = serialize(value[key], depth + 1);
|
|
56
|
+
}
|
|
57
|
+
return serialized;
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
};
|
|
61
|
+
return serialize(props, 0);
|
|
62
|
+
}
|
|
63
|
+
function buildVueContext(instance, info, options) {
|
|
64
|
+
const context = {
|
|
65
|
+
info
|
|
66
|
+
};
|
|
67
|
+
if (options.captureComponentName !== false && instance) {
|
|
68
|
+
context.name = getComponentName(instance);
|
|
69
|
+
const type = instance.$.type;
|
|
70
|
+
if (type.__file) {
|
|
71
|
+
context.file = type.__file;
|
|
72
|
+
}
|
|
73
|
+
context.trace = getComponentTrace(instance);
|
|
74
|
+
}
|
|
75
|
+
if (options.captureComponentProps && instance) {
|
|
76
|
+
const props = instance.$.props;
|
|
77
|
+
if (props && Object.keys(props).length > 0) {
|
|
78
|
+
context.props = serializeProps(props, options.propsDepth ?? 2);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return context;
|
|
82
|
+
}
|
|
83
|
+
var originalErrorHandler;
|
|
84
|
+
var originalWarnHandler;
|
|
85
|
+
function setupErrorHandler(app, options) {
|
|
86
|
+
if (options.vueErrorHandler === false) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
originalErrorHandler = app.config.errorHandler;
|
|
90
|
+
app.config.errorHandler = (err, instance, info) => {
|
|
91
|
+
if (options.beforeVueCapture) {
|
|
92
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
93
|
+
if (!options.beforeVueCapture(error2, instance, info)) {
|
|
94
|
+
if (originalErrorHandler) {
|
|
95
|
+
originalErrorHandler(err, instance, info);
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const vueContext = buildVueContext(instance, info, options);
|
|
101
|
+
ErrorExplorer.addBreadcrumb({
|
|
102
|
+
type: "error",
|
|
103
|
+
category: "vue.error",
|
|
104
|
+
message: err instanceof Error ? err.message : String(err),
|
|
105
|
+
level: "error",
|
|
106
|
+
data: {
|
|
107
|
+
component: vueContext.name,
|
|
108
|
+
info: vueContext.info
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
112
|
+
ErrorExplorer.captureException(error, {
|
|
113
|
+
tags: {
|
|
114
|
+
"vue.component": vueContext.name || "unknown",
|
|
115
|
+
"vue.info": info
|
|
116
|
+
},
|
|
117
|
+
extra: {
|
|
118
|
+
vue: vueContext
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
if (originalErrorHandler) {
|
|
122
|
+
originalErrorHandler(err, instance, info);
|
|
123
|
+
}
|
|
124
|
+
if (options.environment === "development" || import.meta.env?.DEV) {
|
|
125
|
+
console.error("[Vue Error]", err);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function setupWarnHandler(app, options) {
|
|
130
|
+
const enableWarn = options.vueWarnHandler ?? (options.environment === "development" || import.meta.env?.DEV);
|
|
131
|
+
if (!enableWarn) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
originalWarnHandler = app.config.warnHandler;
|
|
135
|
+
app.config.warnHandler = (msg, instance, trace) => {
|
|
136
|
+
const componentName = getComponentName(instance);
|
|
137
|
+
ErrorExplorer.addBreadcrumb({
|
|
138
|
+
type: "debug",
|
|
139
|
+
category: "vue.warn",
|
|
140
|
+
message: msg,
|
|
141
|
+
level: "warning",
|
|
142
|
+
data: {
|
|
143
|
+
component: componentName,
|
|
144
|
+
trace: trace.split("\n").slice(0, 5)
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
if (originalWarnHandler) {
|
|
148
|
+
originalWarnHandler(msg, instance, trace);
|
|
149
|
+
}
|
|
150
|
+
if (import.meta.env?.DEV) {
|
|
151
|
+
console.warn("[Vue Warn]", msg);
|
|
152
|
+
if (trace) {
|
|
153
|
+
console.warn(trace);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function restoreHandlers(app) {
|
|
159
|
+
if (originalErrorHandler !== void 0) {
|
|
160
|
+
app.config.errorHandler = originalErrorHandler;
|
|
161
|
+
originalErrorHandler = void 0;
|
|
162
|
+
}
|
|
163
|
+
if (originalWarnHandler !== void 0) {
|
|
164
|
+
app.config.warnHandler = originalWarnHandler;
|
|
165
|
+
originalWarnHandler = void 0;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function createErrorExplorerPlugin(options = {}) {
|
|
169
|
+
return {
|
|
170
|
+
install(app) {
|
|
171
|
+
if (!ErrorExplorer.isInitialized()) {
|
|
172
|
+
ErrorExplorer.init(options);
|
|
173
|
+
}
|
|
174
|
+
setupErrorHandler(app, options);
|
|
175
|
+
setupWarnHandler(app, options);
|
|
176
|
+
app.provide("errorExplorer", ErrorExplorer);
|
|
177
|
+
app.config.globalProperties.$errorExplorer = ErrorExplorer;
|
|
178
|
+
ErrorExplorer.addBreadcrumb({
|
|
179
|
+
type: "navigation",
|
|
180
|
+
category: "vue.lifecycle",
|
|
181
|
+
message: "Vue app mounted",
|
|
182
|
+
level: "info"
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function defaultGetRouteName(route) {
|
|
188
|
+
if (route.name && typeof route.name === "string") {
|
|
189
|
+
return route.name;
|
|
190
|
+
}
|
|
191
|
+
return route.path || "/";
|
|
192
|
+
}
|
|
193
|
+
function buildRouteData(route, options) {
|
|
194
|
+
const data = {
|
|
195
|
+
path: route.path,
|
|
196
|
+
name: route.name,
|
|
197
|
+
fullPath: route.fullPath
|
|
198
|
+
};
|
|
199
|
+
if (options.trackParams && Object.keys(route.params).length > 0) {
|
|
200
|
+
data.params = { ...route.params };
|
|
201
|
+
}
|
|
202
|
+
if (options.trackQuery && Object.keys(route.query).length > 0) {
|
|
203
|
+
data.query = { ...route.query };
|
|
204
|
+
}
|
|
205
|
+
if (route.meta && Object.keys(route.meta).length > 0) {
|
|
206
|
+
const safeMeta = {};
|
|
207
|
+
for (const [key, value] of Object.entries(route.meta)) {
|
|
208
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
209
|
+
safeMeta[key] = value;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (Object.keys(safeMeta).length > 0) {
|
|
213
|
+
data.meta = safeMeta;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return data;
|
|
217
|
+
}
|
|
218
|
+
function setupRouterIntegration(router, options = {}) {
|
|
219
|
+
if (options.trackNavigation === false) {
|
|
220
|
+
return () => {
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const getRouteName = options.getRouteName || defaultGetRouteName;
|
|
224
|
+
let navigationStartTime = null;
|
|
225
|
+
const beforeEachGuard = router.beforeEach((to, from) => {
|
|
226
|
+
navigationStartTime = performance.now();
|
|
227
|
+
if (from.name || from.path !== "/") {
|
|
228
|
+
const shouldAdd = options.beforeNavigationBreadcrumb ? options.beforeNavigationBreadcrumb(from, to) : true;
|
|
229
|
+
if (shouldAdd) {
|
|
230
|
+
ErrorExplorer.addBreadcrumb({
|
|
231
|
+
type: "navigation",
|
|
232
|
+
category: "router",
|
|
233
|
+
message: `Navigating from ${getRouteName(from)} to ${getRouteName(to)}`,
|
|
234
|
+
level: "info",
|
|
235
|
+
data: {
|
|
236
|
+
from: buildRouteData(from, options),
|
|
237
|
+
to: buildRouteData(to, options)
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return true;
|
|
243
|
+
});
|
|
244
|
+
const afterEachGuard = router.afterEach((to, from, failure) => {
|
|
245
|
+
const duration = navigationStartTime ? performance.now() - navigationStartTime : void 0;
|
|
246
|
+
navigationStartTime = null;
|
|
247
|
+
if (failure) {
|
|
248
|
+
ErrorExplorer.addBreadcrumb({
|
|
249
|
+
type: "navigation",
|
|
250
|
+
category: "router.error",
|
|
251
|
+
message: `Navigation failed to ${getRouteName(to)}`,
|
|
252
|
+
level: "error",
|
|
253
|
+
data: {
|
|
254
|
+
to: buildRouteData(to, options),
|
|
255
|
+
error: failure.message,
|
|
256
|
+
type: failure.type,
|
|
257
|
+
duration
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
if (failure.type !== 4) {
|
|
261
|
+
ErrorExplorer.captureException(failure, {
|
|
262
|
+
tags: {
|
|
263
|
+
"router.error": "navigation_failure",
|
|
264
|
+
"router.to": getRouteName(to)
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
ErrorExplorer.addBreadcrumb({
|
|
270
|
+
type: "navigation",
|
|
271
|
+
category: "router",
|
|
272
|
+
message: `Navigated to ${getRouteName(to)}`,
|
|
273
|
+
level: "info",
|
|
274
|
+
data: {
|
|
275
|
+
route: buildRouteData(to, options),
|
|
276
|
+
duration
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
const errorHandler = router.onError((error) => {
|
|
282
|
+
ErrorExplorer.addBreadcrumb({
|
|
283
|
+
type: "error",
|
|
284
|
+
category: "router.error",
|
|
285
|
+
message: error.message,
|
|
286
|
+
level: "error"
|
|
287
|
+
});
|
|
288
|
+
ErrorExplorer.captureException(error, {
|
|
289
|
+
tags: {
|
|
290
|
+
"router.error": "unhandled"
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
return () => {
|
|
295
|
+
beforeEachGuard();
|
|
296
|
+
afterEachGuard();
|
|
297
|
+
errorHandler();
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function createRouterIntegration(options = {}) {
|
|
301
|
+
let cleanup = null;
|
|
302
|
+
return {
|
|
303
|
+
/**
|
|
304
|
+
* Install the router integration
|
|
305
|
+
*/
|
|
306
|
+
install(router) {
|
|
307
|
+
cleanup = setupRouterIntegration(router, options);
|
|
308
|
+
},
|
|
309
|
+
/**
|
|
310
|
+
* Uninstall the router integration
|
|
311
|
+
*/
|
|
312
|
+
uninstall() {
|
|
313
|
+
if (cleanup) {
|
|
314
|
+
cleanup();
|
|
315
|
+
cleanup = null;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
var ErrorBoundary = defineComponent({
|
|
321
|
+
name: "ErrorBoundary",
|
|
322
|
+
props: {
|
|
323
|
+
/**
|
|
324
|
+
* Whether to capture the error to Error Explorer
|
|
325
|
+
*/
|
|
326
|
+
capture: {
|
|
327
|
+
type: Boolean,
|
|
328
|
+
default: true
|
|
329
|
+
},
|
|
330
|
+
/**
|
|
331
|
+
* Additional tags to add when capturing
|
|
332
|
+
*/
|
|
333
|
+
tags: {
|
|
334
|
+
type: Object,
|
|
335
|
+
default: () => ({})
|
|
336
|
+
},
|
|
337
|
+
/**
|
|
338
|
+
* Additional context to add when capturing
|
|
339
|
+
*/
|
|
340
|
+
context: {
|
|
341
|
+
type: Object,
|
|
342
|
+
default: () => ({})
|
|
343
|
+
},
|
|
344
|
+
/**
|
|
345
|
+
* Fallback component to render when an error occurs
|
|
346
|
+
*/
|
|
347
|
+
fallback: {
|
|
348
|
+
type: [Object, Function, null],
|
|
349
|
+
default: null
|
|
350
|
+
},
|
|
351
|
+
/**
|
|
352
|
+
* Whether to stop error propagation
|
|
353
|
+
*/
|
|
354
|
+
stopPropagation: {
|
|
355
|
+
type: Boolean,
|
|
356
|
+
default: true
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
emits: {
|
|
360
|
+
/**
|
|
361
|
+
* Emitted when an error is caught
|
|
362
|
+
*/
|
|
363
|
+
error: (error, info) => true,
|
|
364
|
+
/**
|
|
365
|
+
* Emitted when the error state is reset
|
|
366
|
+
*/
|
|
367
|
+
reset: () => true
|
|
368
|
+
},
|
|
369
|
+
setup(props, { slots, emit, expose }) {
|
|
370
|
+
const error = ref(null);
|
|
371
|
+
const errorInfo = ref("");
|
|
372
|
+
const reset = () => {
|
|
373
|
+
error.value = null;
|
|
374
|
+
errorInfo.value = "";
|
|
375
|
+
emit("reset");
|
|
376
|
+
};
|
|
377
|
+
onErrorCaptured((err, instance, info) => {
|
|
378
|
+
const capturedError = err instanceof Error ? err : new Error(String(err));
|
|
379
|
+
error.value = capturedError;
|
|
380
|
+
errorInfo.value = info;
|
|
381
|
+
emit("error", capturedError, info);
|
|
382
|
+
ErrorExplorer.addBreadcrumb({
|
|
383
|
+
type: "error",
|
|
384
|
+
category: "vue.errorBoundary",
|
|
385
|
+
message: capturedError.message,
|
|
386
|
+
level: "error",
|
|
387
|
+
data: {
|
|
388
|
+
info,
|
|
389
|
+
component: instance?.$.type ? instance.$.type.name : void 0
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
if (props.capture) {
|
|
393
|
+
ErrorExplorer.captureException(capturedError, {
|
|
394
|
+
tags: {
|
|
395
|
+
"errorBoundary": "true",
|
|
396
|
+
"vue.info": info,
|
|
397
|
+
...props.tags
|
|
398
|
+
},
|
|
399
|
+
extra: {
|
|
400
|
+
errorBoundary: {
|
|
401
|
+
info,
|
|
402
|
+
context: props.context
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
return props.stopPropagation;
|
|
408
|
+
});
|
|
409
|
+
expose({
|
|
410
|
+
reset,
|
|
411
|
+
error
|
|
412
|
+
});
|
|
413
|
+
return () => {
|
|
414
|
+
if (error.value) {
|
|
415
|
+
if (slots.fallback) {
|
|
416
|
+
return slots.fallback({
|
|
417
|
+
error: error.value,
|
|
418
|
+
info: errorInfo.value,
|
|
419
|
+
reset
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
if (props.fallback) {
|
|
423
|
+
if (typeof props.fallback === "function") {
|
|
424
|
+
return props.fallback();
|
|
425
|
+
}
|
|
426
|
+
return props.fallback;
|
|
427
|
+
}
|
|
428
|
+
return h("div", { class: "error-boundary-fallback" }, [
|
|
429
|
+
h("p", { style: "color: red;" }, `Error: ${error.value.message}`),
|
|
430
|
+
h(
|
|
431
|
+
"button",
|
|
432
|
+
{
|
|
433
|
+
onClick: reset,
|
|
434
|
+
style: "margin-top: 8px; padding: 4px 12px; cursor: pointer;"
|
|
435
|
+
},
|
|
436
|
+
"Try Again"
|
|
437
|
+
)
|
|
438
|
+
]);
|
|
439
|
+
}
|
|
440
|
+
return slots.default?.();
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
function withErrorBoundary(Component, options = {}) {
|
|
445
|
+
return defineComponent({
|
|
446
|
+
name: `WithErrorBoundary(${Component.name || "Component"})`,
|
|
447
|
+
setup(_, { attrs, slots }) {
|
|
448
|
+
return () => h(
|
|
449
|
+
ErrorBoundary,
|
|
450
|
+
{
|
|
451
|
+
capture: options.capture ?? true,
|
|
452
|
+
tags: options.tags ?? {},
|
|
453
|
+
context: options.context ?? {},
|
|
454
|
+
fallback: options.fallback ?? null,
|
|
455
|
+
onError: options.onError
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
default: () => h(Component, attrs, slots)
|
|
459
|
+
}
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
var ErrorExplorerKey = /* @__PURE__ */ Symbol("errorExplorer");
|
|
465
|
+
function useErrorExplorer() {
|
|
466
|
+
const injected = inject(ErrorExplorerKey, null) || inject("errorExplorer", null);
|
|
467
|
+
const errorExplorer = injected || ErrorExplorer;
|
|
468
|
+
return {
|
|
469
|
+
/**
|
|
470
|
+
* Check if Error Explorer is initialized
|
|
471
|
+
*/
|
|
472
|
+
isInitialized: () => errorExplorer.isInitialized(),
|
|
473
|
+
/**
|
|
474
|
+
* Capture an exception
|
|
475
|
+
*/
|
|
476
|
+
captureException: (error, context) => errorExplorer.captureException(error, context),
|
|
477
|
+
/**
|
|
478
|
+
* Capture a message
|
|
479
|
+
*/
|
|
480
|
+
captureMessage: (message, level) => errorExplorer.captureMessage(message, level),
|
|
481
|
+
/**
|
|
482
|
+
* Add a breadcrumb
|
|
483
|
+
*/
|
|
484
|
+
addBreadcrumb: (breadcrumb) => errorExplorer.addBreadcrumb(breadcrumb),
|
|
485
|
+
/**
|
|
486
|
+
* Set user context
|
|
487
|
+
*/
|
|
488
|
+
setUser: (user) => errorExplorer.setUser(user),
|
|
489
|
+
/**
|
|
490
|
+
* Clear user context
|
|
491
|
+
*/
|
|
492
|
+
clearUser: () => errorExplorer.clearUser(),
|
|
493
|
+
/**
|
|
494
|
+
* Set a tag
|
|
495
|
+
*/
|
|
496
|
+
setTag: (key, value) => errorExplorer.setTag(key, value),
|
|
497
|
+
/**
|
|
498
|
+
* Set multiple tags
|
|
499
|
+
*/
|
|
500
|
+
setTags: (tags) => errorExplorer.setTags(tags),
|
|
501
|
+
/**
|
|
502
|
+
* Set extra context
|
|
503
|
+
*/
|
|
504
|
+
setExtra: (extra) => errorExplorer.setExtra(extra),
|
|
505
|
+
/**
|
|
506
|
+
* Set named context
|
|
507
|
+
*/
|
|
508
|
+
setContext: (name, context) => errorExplorer.setContext(name, context),
|
|
509
|
+
/**
|
|
510
|
+
* Flush pending events
|
|
511
|
+
*/
|
|
512
|
+
flush: (timeout) => errorExplorer.flush(timeout),
|
|
513
|
+
/**
|
|
514
|
+
* Close the SDK
|
|
515
|
+
*/
|
|
516
|
+
close: (timeout) => errorExplorer.close(timeout)
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function useComponentBreadcrumbs() {
|
|
520
|
+
const instance = getCurrentInstance();
|
|
521
|
+
const componentName = instance?.type ? instance.type.name || instance.type.__name || "Unknown" : "Unknown";
|
|
522
|
+
onMounted(() => {
|
|
523
|
+
ErrorExplorer.addBreadcrumb({
|
|
524
|
+
type: "debug",
|
|
525
|
+
category: "vue.lifecycle",
|
|
526
|
+
message: `${componentName} mounted`,
|
|
527
|
+
level: "debug"
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
onUnmounted(() => {
|
|
531
|
+
ErrorExplorer.addBreadcrumb({
|
|
532
|
+
type: "debug",
|
|
533
|
+
category: "vue.lifecycle",
|
|
534
|
+
message: `${componentName} unmounted`,
|
|
535
|
+
level: "debug"
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
function useActionTracker() {
|
|
540
|
+
const instance = getCurrentInstance();
|
|
541
|
+
const componentName = instance?.type ? instance.type.name || instance.type.__name || "Unknown" : "Unknown";
|
|
542
|
+
return {
|
|
543
|
+
/**
|
|
544
|
+
* Track a user action
|
|
545
|
+
*/
|
|
546
|
+
trackAction: (action, data) => {
|
|
547
|
+
ErrorExplorer.addBreadcrumb({
|
|
548
|
+
type: "user-action",
|
|
549
|
+
category: "action",
|
|
550
|
+
message: action,
|
|
551
|
+
level: "info",
|
|
552
|
+
data: {
|
|
553
|
+
component: componentName,
|
|
554
|
+
...data
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
},
|
|
558
|
+
/**
|
|
559
|
+
* Track a UI interaction
|
|
560
|
+
*/
|
|
561
|
+
trackInteraction: (element, action, data) => {
|
|
562
|
+
ErrorExplorer.addBreadcrumb({
|
|
563
|
+
type: "user-action",
|
|
564
|
+
category: `ui.${action}`,
|
|
565
|
+
message: `${action} on ${element}`,
|
|
566
|
+
level: "info",
|
|
567
|
+
data: {
|
|
568
|
+
component: componentName,
|
|
569
|
+
element,
|
|
570
|
+
...data
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
function useErrorHandler(defaultContext) {
|
|
577
|
+
const instance = getCurrentInstance();
|
|
578
|
+
const componentName = instance?.type ? instance.type.name || instance.type.__name || "Unknown" : "Unknown";
|
|
579
|
+
const handleError = (error, context) => {
|
|
580
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
581
|
+
ErrorExplorer.captureException(err, {
|
|
582
|
+
...defaultContext,
|
|
583
|
+
...context,
|
|
584
|
+
tags: {
|
|
585
|
+
"vue.component": componentName,
|
|
586
|
+
...defaultContext?.tags,
|
|
587
|
+
...context?.tags
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
return err;
|
|
591
|
+
};
|
|
592
|
+
const wrapAsync = (fn, context) => {
|
|
593
|
+
return async (...args) => {
|
|
594
|
+
try {
|
|
595
|
+
return await fn(...args);
|
|
596
|
+
} catch (error) {
|
|
597
|
+
handleError(error, context);
|
|
598
|
+
return void 0;
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
};
|
|
602
|
+
const tryCatch = (fn, context) => {
|
|
603
|
+
try {
|
|
604
|
+
return fn();
|
|
605
|
+
} catch (error) {
|
|
606
|
+
handleError(error, context);
|
|
607
|
+
return void 0;
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
return {
|
|
611
|
+
handleError,
|
|
612
|
+
wrapAsync,
|
|
613
|
+
tryCatch
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
function useUserContext(user) {
|
|
617
|
+
const setUserFromValue = (value) => {
|
|
618
|
+
if (value) {
|
|
619
|
+
ErrorExplorer.setUser(value);
|
|
620
|
+
} else {
|
|
621
|
+
ErrorExplorer.clearUser();
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
if (user && typeof user === "object" && "value" in user) {
|
|
625
|
+
const refValue = user.value;
|
|
626
|
+
setUserFromValue(refValue);
|
|
627
|
+
} else {
|
|
628
|
+
setUserFromValue(user);
|
|
629
|
+
}
|
|
630
|
+
return {
|
|
631
|
+
setUser: (newUser) => ErrorExplorer.setUser(newUser),
|
|
632
|
+
clearUser: () => ErrorExplorer.clearUser()
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
var src_default = createErrorExplorerPlugin;
|
|
636
|
+
|
|
637
|
+
export { ErrorBoundary, ErrorExplorerKey, createErrorExplorerPlugin, createRouterIntegration, src_default as default, restoreHandlers, setupRouterIntegration, useActionTracker, useComponentBreadcrumbs, useErrorExplorer, useErrorHandler, useUserContext, withErrorBoundary };
|
|
638
|
+
//# sourceMappingURL=index.js.map
|
|
639
|
+
//# sourceMappingURL=index.js.map
|