@booboo.dev/js 0.1.0
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/chunk-5PWHK5SB.js +365 -0
- package/dist/chunk-O4OOPXTS.cjs +365 -0
- package/dist/index.cjs +16 -0
- package/dist/index.d.cts +71 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +16 -0
- package/dist/react.cjs +43 -0
- package/dist/react.d.cts +19 -0
- package/dist/react.d.ts +19 -0
- package/dist/react.js +43 -0
- package/dist/vue.cjs +31 -0
- package/dist/vue.d.cts +10 -0
- package/dist/vue.d.ts +10 -0
- package/dist/vue.js +31 -0
- package/package.json +51 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
// src/stacktrace.ts
|
|
2
|
+
var CHROME_RE = /^\s*at\s+(?:(new\s+)?(.+?)\s+\((.+?):(\d+):(\d+)\)|(.+?):(\d+):(\d+))\s*$/;
|
|
3
|
+
var FIREFOX_RE = /^\s*(.+?)@(.+?):(\d+):(\d+)\s*$/;
|
|
4
|
+
function parseStack(error) {
|
|
5
|
+
const stack = error.stack;
|
|
6
|
+
if (!stack) return [];
|
|
7
|
+
const lines = stack.split("\n");
|
|
8
|
+
const frames = [];
|
|
9
|
+
for (const line of lines) {
|
|
10
|
+
let match = CHROME_RE.exec(line);
|
|
11
|
+
if (match) {
|
|
12
|
+
if (match[3]) {
|
|
13
|
+
frames.push({
|
|
14
|
+
filename: match[3],
|
|
15
|
+
function: match[2] || "<anonymous>",
|
|
16
|
+
lineno: parseInt(match[4], 10),
|
|
17
|
+
colno: parseInt(match[5], 10)
|
|
18
|
+
});
|
|
19
|
+
} else {
|
|
20
|
+
frames.push({
|
|
21
|
+
filename: match[6],
|
|
22
|
+
function: "<anonymous>",
|
|
23
|
+
lineno: parseInt(match[7], 10),
|
|
24
|
+
colno: parseInt(match[8], 10)
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
match = FIREFOX_RE.exec(line);
|
|
30
|
+
if (match) {
|
|
31
|
+
frames.push({
|
|
32
|
+
filename: match[2],
|
|
33
|
+
function: match[1] || "<anonymous>",
|
|
34
|
+
lineno: parseInt(match[3], 10),
|
|
35
|
+
colno: parseInt(match[4], 10)
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return frames.reverse();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/breadcrumbs.ts
|
|
43
|
+
var DEFAULT_MAX = 30;
|
|
44
|
+
var breadcrumbBuffer = [];
|
|
45
|
+
var maxBreadcrumbs = DEFAULT_MAX;
|
|
46
|
+
function getBreadcrumbs() {
|
|
47
|
+
return breadcrumbBuffer.slice();
|
|
48
|
+
}
|
|
49
|
+
function addBreadcrumb(crumb) {
|
|
50
|
+
breadcrumbBuffer.push({
|
|
51
|
+
...crumb,
|
|
52
|
+
timestamp: crumb.timestamp ?? Date.now()
|
|
53
|
+
});
|
|
54
|
+
if (breadcrumbBuffer.length > maxBreadcrumbs) {
|
|
55
|
+
breadcrumbBuffer = breadcrumbBuffer.slice(-maxBreadcrumbs);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function clearBreadcrumbs() {
|
|
59
|
+
breadcrumbBuffer = [];
|
|
60
|
+
}
|
|
61
|
+
function instrumentConsole() {
|
|
62
|
+
const originals = {
|
|
63
|
+
log: console.log,
|
|
64
|
+
warn: console.warn,
|
|
65
|
+
error: console.error,
|
|
66
|
+
info: console.info,
|
|
67
|
+
debug: console.debug
|
|
68
|
+
};
|
|
69
|
+
for (const level of Object.keys(originals)) {
|
|
70
|
+
const original = originals[level];
|
|
71
|
+
console[level] = function(...args) {
|
|
72
|
+
addBreadcrumb({
|
|
73
|
+
type: "console",
|
|
74
|
+
category: level,
|
|
75
|
+
message: args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")
|
|
76
|
+
});
|
|
77
|
+
return original.apply(console, args);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return () => {
|
|
81
|
+
for (const level of Object.keys(originals)) {
|
|
82
|
+
console[level] = originals[level];
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function instrumentClicks() {
|
|
87
|
+
const handler = (event) => {
|
|
88
|
+
const target = event.target;
|
|
89
|
+
if (!target) return;
|
|
90
|
+
const tag = target.tagName?.toLowerCase() || "";
|
|
91
|
+
const text = target.innerText?.slice(0, 50) || "";
|
|
92
|
+
const id = target.id ? `#${target.id}` : "";
|
|
93
|
+
const cls = target.className && typeof target.className === "string" ? `.${target.className.split(" ").slice(0, 2).join(".")}` : "";
|
|
94
|
+
addBreadcrumb({
|
|
95
|
+
type: "click",
|
|
96
|
+
category: "ui",
|
|
97
|
+
message: `${tag}${id}${cls}` + (text ? ` "${text}"` : "")
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
document.addEventListener("click", handler, true);
|
|
101
|
+
return () => document.removeEventListener("click", handler, true);
|
|
102
|
+
}
|
|
103
|
+
function instrumentNavigation() {
|
|
104
|
+
const origPushState = history.pushState;
|
|
105
|
+
const origReplaceState = history.replaceState;
|
|
106
|
+
const record = (from, to) => {
|
|
107
|
+
addBreadcrumb({
|
|
108
|
+
type: "navigation",
|
|
109
|
+
category: "navigation",
|
|
110
|
+
message: `${from} -> ${to}`,
|
|
111
|
+
data: { from, to }
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
history.pushState = function(...args) {
|
|
115
|
+
const from = location.href;
|
|
116
|
+
origPushState.apply(this, args);
|
|
117
|
+
record(from, location.href);
|
|
118
|
+
};
|
|
119
|
+
history.replaceState = function(...args) {
|
|
120
|
+
const from = location.href;
|
|
121
|
+
origReplaceState.apply(this, args);
|
|
122
|
+
record(from, location.href);
|
|
123
|
+
};
|
|
124
|
+
const popHandler = () => {
|
|
125
|
+
addBreadcrumb({
|
|
126
|
+
type: "navigation",
|
|
127
|
+
category: "navigation",
|
|
128
|
+
message: `popstate -> ${location.href}`
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
window.addEventListener("popstate", popHandler);
|
|
132
|
+
return () => {
|
|
133
|
+
history.pushState = origPushState;
|
|
134
|
+
history.replaceState = origReplaceState;
|
|
135
|
+
window.removeEventListener("popstate", popHandler);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function instrumentFetch() {
|
|
139
|
+
const origFetch = window.fetch;
|
|
140
|
+
window.fetch = async function(input, init2) {
|
|
141
|
+
const method = init2?.method?.toUpperCase() || "GET";
|
|
142
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
143
|
+
const start = Date.now();
|
|
144
|
+
try {
|
|
145
|
+
const response = await origFetch.apply(this, [input, init2]);
|
|
146
|
+
addBreadcrumb({
|
|
147
|
+
type: "fetch",
|
|
148
|
+
category: "http",
|
|
149
|
+
message: `${method} ${url} [${response.status}]`,
|
|
150
|
+
data: { method, url, status: response.status, duration: Date.now() - start }
|
|
151
|
+
});
|
|
152
|
+
return response;
|
|
153
|
+
} catch (err) {
|
|
154
|
+
addBreadcrumb({
|
|
155
|
+
type: "fetch",
|
|
156
|
+
category: "http",
|
|
157
|
+
message: `${method} ${url} [failed]`,
|
|
158
|
+
data: { method, url, duration: Date.now() - start }
|
|
159
|
+
});
|
|
160
|
+
throw err;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
return () => {
|
|
164
|
+
window.fetch = origFetch;
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function setupBreadcrumbs(options, max) {
|
|
168
|
+
maxBreadcrumbs = max ?? DEFAULT_MAX;
|
|
169
|
+
breadcrumbBuffer = [];
|
|
170
|
+
const teardowns = [];
|
|
171
|
+
const opts = typeof options === "boolean" ? { console: true, clicks: true, navigation: true, fetch: true } : options;
|
|
172
|
+
if (opts.console !== false) teardowns.push(instrumentConsole());
|
|
173
|
+
if (opts.clicks !== false) teardowns.push(instrumentClicks());
|
|
174
|
+
if (opts.navigation !== false) teardowns.push(instrumentNavigation());
|
|
175
|
+
if (opts.fetch !== false) teardowns.push(instrumentFetch());
|
|
176
|
+
return () => {
|
|
177
|
+
for (const fn of teardowns) fn();
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/transport.ts
|
|
182
|
+
var Transport = class {
|
|
183
|
+
constructor(endpoint, dsn) {
|
|
184
|
+
this.queue = [];
|
|
185
|
+
this.flushing = false;
|
|
186
|
+
this.endpoint = endpoint;
|
|
187
|
+
this.dsn = dsn;
|
|
188
|
+
if (typeof document !== "undefined") {
|
|
189
|
+
document.addEventListener("visibilitychange", () => {
|
|
190
|
+
if (document.visibilityState === "hidden") this.flush();
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
if (typeof window !== "undefined") {
|
|
194
|
+
window.addEventListener("pagehide", () => this.flush());
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
send(event) {
|
|
198
|
+
this.queue.push(event);
|
|
199
|
+
this.drain();
|
|
200
|
+
}
|
|
201
|
+
async drain() {
|
|
202
|
+
if (this.flushing) return;
|
|
203
|
+
this.flushing = true;
|
|
204
|
+
while (this.queue.length > 0) {
|
|
205
|
+
const event = this.queue.shift();
|
|
206
|
+
try {
|
|
207
|
+
await fetch(this.endpoint, {
|
|
208
|
+
method: "POST",
|
|
209
|
+
headers: {
|
|
210
|
+
"Content-Type": "application/json",
|
|
211
|
+
"X-Booboo-DSN": this.dsn
|
|
212
|
+
},
|
|
213
|
+
body: JSON.stringify(event),
|
|
214
|
+
keepalive: true
|
|
215
|
+
});
|
|
216
|
+
} catch {
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
this.flushing = false;
|
|
220
|
+
}
|
|
221
|
+
flush() {
|
|
222
|
+
while (this.queue.length > 0) {
|
|
223
|
+
const event = this.queue.shift();
|
|
224
|
+
try {
|
|
225
|
+
fetch(this.endpoint, {
|
|
226
|
+
method: "POST",
|
|
227
|
+
headers: {
|
|
228
|
+
"Content-Type": "application/json",
|
|
229
|
+
"X-Booboo-DSN": this.dsn
|
|
230
|
+
},
|
|
231
|
+
body: JSON.stringify(event),
|
|
232
|
+
keepalive: true
|
|
233
|
+
});
|
|
234
|
+
} catch {
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/client.ts
|
|
241
|
+
var DEFAULT_ENDPOINT = "https://api.booboo.dev/ingest/";
|
|
242
|
+
var BoobooClient = class {
|
|
243
|
+
constructor(options) {
|
|
244
|
+
this.options = options;
|
|
245
|
+
const endpoint = options.endpoint || DEFAULT_ENDPOINT;
|
|
246
|
+
this.transport = new Transport(endpoint, options.dsn);
|
|
247
|
+
this.prevOnError = window.onerror;
|
|
248
|
+
window.onerror = (message, source, lineno, colno, error) => {
|
|
249
|
+
if (error) {
|
|
250
|
+
this.captureException(error);
|
|
251
|
+
} else {
|
|
252
|
+
this.captureMessage(String(message));
|
|
253
|
+
}
|
|
254
|
+
if (typeof this.prevOnError === "function") {
|
|
255
|
+
this.prevOnError(message, source, lineno, colno, error);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
this.prevOnUnhandledRejection = window.onunhandledrejection;
|
|
259
|
+
window.onunhandledrejection = (event) => {
|
|
260
|
+
const reason = event.reason;
|
|
261
|
+
if (reason instanceof Error) {
|
|
262
|
+
this.captureException(reason);
|
|
263
|
+
} else {
|
|
264
|
+
this.captureMessage(String(reason));
|
|
265
|
+
}
|
|
266
|
+
if (typeof this.prevOnUnhandledRejection === "function") {
|
|
267
|
+
this.prevOnUnhandledRejection(event);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
if (options.breadcrumbs !== false) {
|
|
271
|
+
this.teardownBreadcrumbs = setupBreadcrumbs(
|
|
272
|
+
options.breadcrumbs ?? true,
|
|
273
|
+
options.maxBreadcrumbs
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
captureException(error, extra) {
|
|
278
|
+
const frames = parseStack(error);
|
|
279
|
+
const event = this.buildEvent(
|
|
280
|
+
error.message,
|
|
281
|
+
error.constructor.name || "Error",
|
|
282
|
+
frames,
|
|
283
|
+
extra
|
|
284
|
+
);
|
|
285
|
+
this.sendEvent(event);
|
|
286
|
+
}
|
|
287
|
+
captureMessage(message, level = "error") {
|
|
288
|
+
const event = this.buildEvent(message, "Error", [], void 0, level);
|
|
289
|
+
this.sendEvent(event);
|
|
290
|
+
}
|
|
291
|
+
addBreadcrumb(crumb) {
|
|
292
|
+
addBreadcrumb(crumb);
|
|
293
|
+
}
|
|
294
|
+
destroy() {
|
|
295
|
+
window.onerror = this.prevOnError ?? null;
|
|
296
|
+
window.onunhandledrejection = this.prevOnUnhandledRejection ?? null;
|
|
297
|
+
this.teardownBreadcrumbs?.();
|
|
298
|
+
clearBreadcrumbs();
|
|
299
|
+
}
|
|
300
|
+
buildEvent(message, exceptionType, stacktrace, extra, level = "error") {
|
|
301
|
+
return {
|
|
302
|
+
message,
|
|
303
|
+
level,
|
|
304
|
+
exception_type: exceptionType,
|
|
305
|
+
stacktrace,
|
|
306
|
+
context: {
|
|
307
|
+
...this.options.context,
|
|
308
|
+
...extra,
|
|
309
|
+
breadcrumbs: getBreadcrumbs(),
|
|
310
|
+
browser: {
|
|
311
|
+
url: window.location.href,
|
|
312
|
+
userAgent: navigator.userAgent,
|
|
313
|
+
screen: `${screen.width}x${screen.height}`,
|
|
314
|
+
viewport: `${window.innerWidth}x${window.innerHeight}`
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
request: {
|
|
318
|
+
url: window.location.href,
|
|
319
|
+
headers: {
|
|
320
|
+
"User-Agent": navigator.userAgent
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
tags: { ...this.options.tags, runtime: "browser" }
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
sendEvent(event) {
|
|
327
|
+
if (this.options.beforeSend) {
|
|
328
|
+
const modified = this.options.beforeSend(event);
|
|
329
|
+
if (modified === null) return;
|
|
330
|
+
event = modified;
|
|
331
|
+
}
|
|
332
|
+
this.transport.send(event);
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
// src/index.ts
|
|
337
|
+
var client = null;
|
|
338
|
+
function init(options) {
|
|
339
|
+
if (client) {
|
|
340
|
+
client.destroy();
|
|
341
|
+
}
|
|
342
|
+
client = new BoobooClient(options);
|
|
343
|
+
return client;
|
|
344
|
+
}
|
|
345
|
+
function captureException(error, extra) {
|
|
346
|
+
client?.captureException(error, extra);
|
|
347
|
+
}
|
|
348
|
+
function captureMessage(message, level) {
|
|
349
|
+
client?.captureMessage(message, level);
|
|
350
|
+
}
|
|
351
|
+
function addBreadcrumb2(crumb) {
|
|
352
|
+
client?.addBreadcrumb(crumb);
|
|
353
|
+
}
|
|
354
|
+
function getClient() {
|
|
355
|
+
return client;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export {
|
|
359
|
+
parseStack,
|
|
360
|
+
init,
|
|
361
|
+
captureException,
|
|
362
|
+
captureMessage,
|
|
363
|
+
addBreadcrumb2 as addBreadcrumb,
|
|
364
|
+
getClient
|
|
365
|
+
};
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/stacktrace.ts
|
|
2
|
+
var CHROME_RE = /^\s*at\s+(?:(new\s+)?(.+?)\s+\((.+?):(\d+):(\d+)\)|(.+?):(\d+):(\d+))\s*$/;
|
|
3
|
+
var FIREFOX_RE = /^\s*(.+?)@(.+?):(\d+):(\d+)\s*$/;
|
|
4
|
+
function parseStack(error) {
|
|
5
|
+
const stack = error.stack;
|
|
6
|
+
if (!stack) return [];
|
|
7
|
+
const lines = stack.split("\n");
|
|
8
|
+
const frames = [];
|
|
9
|
+
for (const line of lines) {
|
|
10
|
+
let match = CHROME_RE.exec(line);
|
|
11
|
+
if (match) {
|
|
12
|
+
if (match[3]) {
|
|
13
|
+
frames.push({
|
|
14
|
+
filename: match[3],
|
|
15
|
+
function: match[2] || "<anonymous>",
|
|
16
|
+
lineno: parseInt(match[4], 10),
|
|
17
|
+
colno: parseInt(match[5], 10)
|
|
18
|
+
});
|
|
19
|
+
} else {
|
|
20
|
+
frames.push({
|
|
21
|
+
filename: match[6],
|
|
22
|
+
function: "<anonymous>",
|
|
23
|
+
lineno: parseInt(match[7], 10),
|
|
24
|
+
colno: parseInt(match[8], 10)
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
match = FIREFOX_RE.exec(line);
|
|
30
|
+
if (match) {
|
|
31
|
+
frames.push({
|
|
32
|
+
filename: match[2],
|
|
33
|
+
function: match[1] || "<anonymous>",
|
|
34
|
+
lineno: parseInt(match[3], 10),
|
|
35
|
+
colno: parseInt(match[4], 10)
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return frames.reverse();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/breadcrumbs.ts
|
|
43
|
+
var DEFAULT_MAX = 30;
|
|
44
|
+
var breadcrumbBuffer = [];
|
|
45
|
+
var maxBreadcrumbs = DEFAULT_MAX;
|
|
46
|
+
function getBreadcrumbs() {
|
|
47
|
+
return breadcrumbBuffer.slice();
|
|
48
|
+
}
|
|
49
|
+
function addBreadcrumb(crumb) {
|
|
50
|
+
breadcrumbBuffer.push({
|
|
51
|
+
...crumb,
|
|
52
|
+
timestamp: _nullishCoalesce(crumb.timestamp, () => ( Date.now()))
|
|
53
|
+
});
|
|
54
|
+
if (breadcrumbBuffer.length > maxBreadcrumbs) {
|
|
55
|
+
breadcrumbBuffer = breadcrumbBuffer.slice(-maxBreadcrumbs);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function clearBreadcrumbs() {
|
|
59
|
+
breadcrumbBuffer = [];
|
|
60
|
+
}
|
|
61
|
+
function instrumentConsole() {
|
|
62
|
+
const originals = {
|
|
63
|
+
log: console.log,
|
|
64
|
+
warn: console.warn,
|
|
65
|
+
error: console.error,
|
|
66
|
+
info: console.info,
|
|
67
|
+
debug: console.debug
|
|
68
|
+
};
|
|
69
|
+
for (const level of Object.keys(originals)) {
|
|
70
|
+
const original = originals[level];
|
|
71
|
+
console[level] = function(...args) {
|
|
72
|
+
addBreadcrumb({
|
|
73
|
+
type: "console",
|
|
74
|
+
category: level,
|
|
75
|
+
message: args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")
|
|
76
|
+
});
|
|
77
|
+
return original.apply(console, args);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return () => {
|
|
81
|
+
for (const level of Object.keys(originals)) {
|
|
82
|
+
console[level] = originals[level];
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function instrumentClicks() {
|
|
87
|
+
const handler = (event) => {
|
|
88
|
+
const target = event.target;
|
|
89
|
+
if (!target) return;
|
|
90
|
+
const tag = _optionalChain([target, 'access', _ => _.tagName, 'optionalAccess', _2 => _2.toLowerCase, 'call', _3 => _3()]) || "";
|
|
91
|
+
const text = _optionalChain([target, 'access', _4 => _4.innerText, 'optionalAccess', _5 => _5.slice, 'call', _6 => _6(0, 50)]) || "";
|
|
92
|
+
const id = target.id ? `#${target.id}` : "";
|
|
93
|
+
const cls = target.className && typeof target.className === "string" ? `.${target.className.split(" ").slice(0, 2).join(".")}` : "";
|
|
94
|
+
addBreadcrumb({
|
|
95
|
+
type: "click",
|
|
96
|
+
category: "ui",
|
|
97
|
+
message: `${tag}${id}${cls}` + (text ? ` "${text}"` : "")
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
document.addEventListener("click", handler, true);
|
|
101
|
+
return () => document.removeEventListener("click", handler, true);
|
|
102
|
+
}
|
|
103
|
+
function instrumentNavigation() {
|
|
104
|
+
const origPushState = history.pushState;
|
|
105
|
+
const origReplaceState = history.replaceState;
|
|
106
|
+
const record = (from, to) => {
|
|
107
|
+
addBreadcrumb({
|
|
108
|
+
type: "navigation",
|
|
109
|
+
category: "navigation",
|
|
110
|
+
message: `${from} -> ${to}`,
|
|
111
|
+
data: { from, to }
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
history.pushState = function(...args) {
|
|
115
|
+
const from = location.href;
|
|
116
|
+
origPushState.apply(this, args);
|
|
117
|
+
record(from, location.href);
|
|
118
|
+
};
|
|
119
|
+
history.replaceState = function(...args) {
|
|
120
|
+
const from = location.href;
|
|
121
|
+
origReplaceState.apply(this, args);
|
|
122
|
+
record(from, location.href);
|
|
123
|
+
};
|
|
124
|
+
const popHandler = () => {
|
|
125
|
+
addBreadcrumb({
|
|
126
|
+
type: "navigation",
|
|
127
|
+
category: "navigation",
|
|
128
|
+
message: `popstate -> ${location.href}`
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
window.addEventListener("popstate", popHandler);
|
|
132
|
+
return () => {
|
|
133
|
+
history.pushState = origPushState;
|
|
134
|
+
history.replaceState = origReplaceState;
|
|
135
|
+
window.removeEventListener("popstate", popHandler);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function instrumentFetch() {
|
|
139
|
+
const origFetch = window.fetch;
|
|
140
|
+
window.fetch = async function(input, init2) {
|
|
141
|
+
const method = _optionalChain([init2, 'optionalAccess', _7 => _7.method, 'optionalAccess', _8 => _8.toUpperCase, 'call', _9 => _9()]) || "GET";
|
|
142
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
143
|
+
const start = Date.now();
|
|
144
|
+
try {
|
|
145
|
+
const response = await origFetch.apply(this, [input, init2]);
|
|
146
|
+
addBreadcrumb({
|
|
147
|
+
type: "fetch",
|
|
148
|
+
category: "http",
|
|
149
|
+
message: `${method} ${url} [${response.status}]`,
|
|
150
|
+
data: { method, url, status: response.status, duration: Date.now() - start }
|
|
151
|
+
});
|
|
152
|
+
return response;
|
|
153
|
+
} catch (err) {
|
|
154
|
+
addBreadcrumb({
|
|
155
|
+
type: "fetch",
|
|
156
|
+
category: "http",
|
|
157
|
+
message: `${method} ${url} [failed]`,
|
|
158
|
+
data: { method, url, duration: Date.now() - start }
|
|
159
|
+
});
|
|
160
|
+
throw err;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
return () => {
|
|
164
|
+
window.fetch = origFetch;
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function setupBreadcrumbs(options, max) {
|
|
168
|
+
maxBreadcrumbs = _nullishCoalesce(max, () => ( DEFAULT_MAX));
|
|
169
|
+
breadcrumbBuffer = [];
|
|
170
|
+
const teardowns = [];
|
|
171
|
+
const opts = typeof options === "boolean" ? { console: true, clicks: true, navigation: true, fetch: true } : options;
|
|
172
|
+
if (opts.console !== false) teardowns.push(instrumentConsole());
|
|
173
|
+
if (opts.clicks !== false) teardowns.push(instrumentClicks());
|
|
174
|
+
if (opts.navigation !== false) teardowns.push(instrumentNavigation());
|
|
175
|
+
if (opts.fetch !== false) teardowns.push(instrumentFetch());
|
|
176
|
+
return () => {
|
|
177
|
+
for (const fn of teardowns) fn();
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/transport.ts
|
|
182
|
+
var Transport = class {
|
|
183
|
+
constructor(endpoint, dsn) {
|
|
184
|
+
this.queue = [];
|
|
185
|
+
this.flushing = false;
|
|
186
|
+
this.endpoint = endpoint;
|
|
187
|
+
this.dsn = dsn;
|
|
188
|
+
if (typeof document !== "undefined") {
|
|
189
|
+
document.addEventListener("visibilitychange", () => {
|
|
190
|
+
if (document.visibilityState === "hidden") this.flush();
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
if (typeof window !== "undefined") {
|
|
194
|
+
window.addEventListener("pagehide", () => this.flush());
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
send(event) {
|
|
198
|
+
this.queue.push(event);
|
|
199
|
+
this.drain();
|
|
200
|
+
}
|
|
201
|
+
async drain() {
|
|
202
|
+
if (this.flushing) return;
|
|
203
|
+
this.flushing = true;
|
|
204
|
+
while (this.queue.length > 0) {
|
|
205
|
+
const event = this.queue.shift();
|
|
206
|
+
try {
|
|
207
|
+
await fetch(this.endpoint, {
|
|
208
|
+
method: "POST",
|
|
209
|
+
headers: {
|
|
210
|
+
"Content-Type": "application/json",
|
|
211
|
+
"X-Booboo-DSN": this.dsn
|
|
212
|
+
},
|
|
213
|
+
body: JSON.stringify(event),
|
|
214
|
+
keepalive: true
|
|
215
|
+
});
|
|
216
|
+
} catch (e) {
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
this.flushing = false;
|
|
220
|
+
}
|
|
221
|
+
flush() {
|
|
222
|
+
while (this.queue.length > 0) {
|
|
223
|
+
const event = this.queue.shift();
|
|
224
|
+
try {
|
|
225
|
+
fetch(this.endpoint, {
|
|
226
|
+
method: "POST",
|
|
227
|
+
headers: {
|
|
228
|
+
"Content-Type": "application/json",
|
|
229
|
+
"X-Booboo-DSN": this.dsn
|
|
230
|
+
},
|
|
231
|
+
body: JSON.stringify(event),
|
|
232
|
+
keepalive: true
|
|
233
|
+
});
|
|
234
|
+
} catch (e2) {
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/client.ts
|
|
241
|
+
var DEFAULT_ENDPOINT = "https://api.booboo.dev/ingest/";
|
|
242
|
+
var BoobooClient = class {
|
|
243
|
+
constructor(options) {
|
|
244
|
+
this.options = options;
|
|
245
|
+
const endpoint = options.endpoint || DEFAULT_ENDPOINT;
|
|
246
|
+
this.transport = new Transport(endpoint, options.dsn);
|
|
247
|
+
this.prevOnError = window.onerror;
|
|
248
|
+
window.onerror = (message, source, lineno, colno, error) => {
|
|
249
|
+
if (error) {
|
|
250
|
+
this.captureException(error);
|
|
251
|
+
} else {
|
|
252
|
+
this.captureMessage(String(message));
|
|
253
|
+
}
|
|
254
|
+
if (typeof this.prevOnError === "function") {
|
|
255
|
+
this.prevOnError(message, source, lineno, colno, error);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
this.prevOnUnhandledRejection = window.onunhandledrejection;
|
|
259
|
+
window.onunhandledrejection = (event) => {
|
|
260
|
+
const reason = event.reason;
|
|
261
|
+
if (reason instanceof Error) {
|
|
262
|
+
this.captureException(reason);
|
|
263
|
+
} else {
|
|
264
|
+
this.captureMessage(String(reason));
|
|
265
|
+
}
|
|
266
|
+
if (typeof this.prevOnUnhandledRejection === "function") {
|
|
267
|
+
this.prevOnUnhandledRejection(event);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
if (options.breadcrumbs !== false) {
|
|
271
|
+
this.teardownBreadcrumbs = setupBreadcrumbs(
|
|
272
|
+
_nullishCoalesce(options.breadcrumbs, () => ( true)),
|
|
273
|
+
options.maxBreadcrumbs
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
captureException(error, extra) {
|
|
278
|
+
const frames = parseStack(error);
|
|
279
|
+
const event = this.buildEvent(
|
|
280
|
+
error.message,
|
|
281
|
+
error.constructor.name || "Error",
|
|
282
|
+
frames,
|
|
283
|
+
extra
|
|
284
|
+
);
|
|
285
|
+
this.sendEvent(event);
|
|
286
|
+
}
|
|
287
|
+
captureMessage(message, level = "error") {
|
|
288
|
+
const event = this.buildEvent(message, "Error", [], void 0, level);
|
|
289
|
+
this.sendEvent(event);
|
|
290
|
+
}
|
|
291
|
+
addBreadcrumb(crumb) {
|
|
292
|
+
addBreadcrumb(crumb);
|
|
293
|
+
}
|
|
294
|
+
destroy() {
|
|
295
|
+
window.onerror = _nullishCoalesce(this.prevOnError, () => ( null));
|
|
296
|
+
window.onunhandledrejection = _nullishCoalesce(this.prevOnUnhandledRejection, () => ( null));
|
|
297
|
+
_optionalChain([this, 'access', _10 => _10.teardownBreadcrumbs, 'optionalCall', _11 => _11()]);
|
|
298
|
+
clearBreadcrumbs();
|
|
299
|
+
}
|
|
300
|
+
buildEvent(message, exceptionType, stacktrace, extra, level = "error") {
|
|
301
|
+
return {
|
|
302
|
+
message,
|
|
303
|
+
level,
|
|
304
|
+
exception_type: exceptionType,
|
|
305
|
+
stacktrace,
|
|
306
|
+
context: {
|
|
307
|
+
...this.options.context,
|
|
308
|
+
...extra,
|
|
309
|
+
breadcrumbs: getBreadcrumbs(),
|
|
310
|
+
browser: {
|
|
311
|
+
url: window.location.href,
|
|
312
|
+
userAgent: navigator.userAgent,
|
|
313
|
+
screen: `${screen.width}x${screen.height}`,
|
|
314
|
+
viewport: `${window.innerWidth}x${window.innerHeight}`
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
request: {
|
|
318
|
+
url: window.location.href,
|
|
319
|
+
headers: {
|
|
320
|
+
"User-Agent": navigator.userAgent
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
tags: { ...this.options.tags, runtime: "browser" }
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
sendEvent(event) {
|
|
327
|
+
if (this.options.beforeSend) {
|
|
328
|
+
const modified = this.options.beforeSend(event);
|
|
329
|
+
if (modified === null) return;
|
|
330
|
+
event = modified;
|
|
331
|
+
}
|
|
332
|
+
this.transport.send(event);
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
// src/index.ts
|
|
337
|
+
var client = null;
|
|
338
|
+
function init(options) {
|
|
339
|
+
if (client) {
|
|
340
|
+
client.destroy();
|
|
341
|
+
}
|
|
342
|
+
client = new BoobooClient(options);
|
|
343
|
+
return client;
|
|
344
|
+
}
|
|
345
|
+
function captureException(error, extra) {
|
|
346
|
+
_optionalChain([client, 'optionalAccess', _12 => _12.captureException, 'call', _13 => _13(error, extra)]);
|
|
347
|
+
}
|
|
348
|
+
function captureMessage(message, level) {
|
|
349
|
+
_optionalChain([client, 'optionalAccess', _14 => _14.captureMessage, 'call', _15 => _15(message, level)]);
|
|
350
|
+
}
|
|
351
|
+
function addBreadcrumb2(crumb) {
|
|
352
|
+
_optionalChain([client, 'optionalAccess', _16 => _16.addBreadcrumb, 'call', _17 => _17(crumb)]);
|
|
353
|
+
}
|
|
354
|
+
function getClient() {
|
|
355
|
+
return client;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
exports.parseStack = parseStack; exports.init = init; exports.captureException = captureException; exports.captureMessage = captureMessage; exports.addBreadcrumb = addBreadcrumb2; exports.getClient = getClient;
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
var _chunkO4OOPXTScjs = require('./chunk-O4OOPXTS.cjs');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
exports.addBreadcrumb = _chunkO4OOPXTScjs.addBreadcrumb; exports.captureException = _chunkO4OOPXTScjs.captureException; exports.captureMessage = _chunkO4OOPXTScjs.captureMessage; exports.getClient = _chunkO4OOPXTScjs.getClient; exports.init = _chunkO4OOPXTScjs.init; exports.parseStack = _chunkO4OOPXTScjs.parseStack;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
interface StackFrame {
|
|
2
|
+
filename: string;
|
|
3
|
+
function: string;
|
|
4
|
+
lineno: number;
|
|
5
|
+
colno?: number;
|
|
6
|
+
}
|
|
7
|
+
interface Breadcrumb {
|
|
8
|
+
type: "console" | "click" | "navigation" | "fetch" | "custom";
|
|
9
|
+
category?: string;
|
|
10
|
+
message: string;
|
|
11
|
+
data?: Record<string, unknown>;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
}
|
|
14
|
+
interface BreadcrumbOptions {
|
|
15
|
+
console?: boolean;
|
|
16
|
+
clicks?: boolean;
|
|
17
|
+
navigation?: boolean;
|
|
18
|
+
fetch?: boolean;
|
|
19
|
+
}
|
|
20
|
+
interface BoobooOptions {
|
|
21
|
+
dsn: string;
|
|
22
|
+
endpoint?: string;
|
|
23
|
+
breadcrumbs?: boolean | BreadcrumbOptions;
|
|
24
|
+
maxBreadcrumbs?: number;
|
|
25
|
+
beforeSend?: (event: BoobooEvent) => BoobooEvent | null;
|
|
26
|
+
tags?: Record<string, string>;
|
|
27
|
+
context?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
interface BoobooEvent {
|
|
30
|
+
message: string;
|
|
31
|
+
level: "error" | "warning" | "info";
|
|
32
|
+
exception_type: string;
|
|
33
|
+
stacktrace: StackFrame[];
|
|
34
|
+
context: Record<string, unknown>;
|
|
35
|
+
request: {
|
|
36
|
+
url: string;
|
|
37
|
+
headers: Record<string, string>;
|
|
38
|
+
};
|
|
39
|
+
tags: Record<string, string>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
declare function addBreadcrumb$1(crumb: Omit<Breadcrumb, "timestamp"> & {
|
|
43
|
+
timestamp?: number;
|
|
44
|
+
}): void;
|
|
45
|
+
|
|
46
|
+
declare class BoobooClient {
|
|
47
|
+
private options;
|
|
48
|
+
private transport;
|
|
49
|
+
private teardownBreadcrumbs?;
|
|
50
|
+
private prevOnError?;
|
|
51
|
+
private prevOnUnhandledRejection?;
|
|
52
|
+
constructor(options: BoobooOptions);
|
|
53
|
+
captureException(error: Error, extra?: Record<string, unknown>): void;
|
|
54
|
+
captureMessage(message: string, level?: "error" | "warning" | "info"): void;
|
|
55
|
+
addBreadcrumb(crumb: Parameters<typeof addBreadcrumb$1>[0]): void;
|
|
56
|
+
destroy(): void;
|
|
57
|
+
private buildEvent;
|
|
58
|
+
private sendEvent;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
declare function parseStack(error: Error): StackFrame[];
|
|
62
|
+
|
|
63
|
+
declare function init(options: BoobooOptions): BoobooClient;
|
|
64
|
+
declare function captureException(error: Error, extra?: Record<string, unknown>): void;
|
|
65
|
+
declare function captureMessage(message: string, level?: "error" | "warning" | "info"): void;
|
|
66
|
+
declare function addBreadcrumb(crumb: Omit<Breadcrumb, "timestamp"> & {
|
|
67
|
+
timestamp?: number;
|
|
68
|
+
}): void;
|
|
69
|
+
declare function getClient(): BoobooClient | null;
|
|
70
|
+
|
|
71
|
+
export { type BoobooEvent, type BoobooOptions, type Breadcrumb, type BreadcrumbOptions, type StackFrame, addBreadcrumb, captureException, captureMessage, getClient, init, parseStack };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
interface StackFrame {
|
|
2
|
+
filename: string;
|
|
3
|
+
function: string;
|
|
4
|
+
lineno: number;
|
|
5
|
+
colno?: number;
|
|
6
|
+
}
|
|
7
|
+
interface Breadcrumb {
|
|
8
|
+
type: "console" | "click" | "navigation" | "fetch" | "custom";
|
|
9
|
+
category?: string;
|
|
10
|
+
message: string;
|
|
11
|
+
data?: Record<string, unknown>;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
}
|
|
14
|
+
interface BreadcrumbOptions {
|
|
15
|
+
console?: boolean;
|
|
16
|
+
clicks?: boolean;
|
|
17
|
+
navigation?: boolean;
|
|
18
|
+
fetch?: boolean;
|
|
19
|
+
}
|
|
20
|
+
interface BoobooOptions {
|
|
21
|
+
dsn: string;
|
|
22
|
+
endpoint?: string;
|
|
23
|
+
breadcrumbs?: boolean | BreadcrumbOptions;
|
|
24
|
+
maxBreadcrumbs?: number;
|
|
25
|
+
beforeSend?: (event: BoobooEvent) => BoobooEvent | null;
|
|
26
|
+
tags?: Record<string, string>;
|
|
27
|
+
context?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
interface BoobooEvent {
|
|
30
|
+
message: string;
|
|
31
|
+
level: "error" | "warning" | "info";
|
|
32
|
+
exception_type: string;
|
|
33
|
+
stacktrace: StackFrame[];
|
|
34
|
+
context: Record<string, unknown>;
|
|
35
|
+
request: {
|
|
36
|
+
url: string;
|
|
37
|
+
headers: Record<string, string>;
|
|
38
|
+
};
|
|
39
|
+
tags: Record<string, string>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
declare function addBreadcrumb$1(crumb: Omit<Breadcrumb, "timestamp"> & {
|
|
43
|
+
timestamp?: number;
|
|
44
|
+
}): void;
|
|
45
|
+
|
|
46
|
+
declare class BoobooClient {
|
|
47
|
+
private options;
|
|
48
|
+
private transport;
|
|
49
|
+
private teardownBreadcrumbs?;
|
|
50
|
+
private prevOnError?;
|
|
51
|
+
private prevOnUnhandledRejection?;
|
|
52
|
+
constructor(options: BoobooOptions);
|
|
53
|
+
captureException(error: Error, extra?: Record<string, unknown>): void;
|
|
54
|
+
captureMessage(message: string, level?: "error" | "warning" | "info"): void;
|
|
55
|
+
addBreadcrumb(crumb: Parameters<typeof addBreadcrumb$1>[0]): void;
|
|
56
|
+
destroy(): void;
|
|
57
|
+
private buildEvent;
|
|
58
|
+
private sendEvent;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
declare function parseStack(error: Error): StackFrame[];
|
|
62
|
+
|
|
63
|
+
declare function init(options: BoobooOptions): BoobooClient;
|
|
64
|
+
declare function captureException(error: Error, extra?: Record<string, unknown>): void;
|
|
65
|
+
declare function captureMessage(message: string, level?: "error" | "warning" | "info"): void;
|
|
66
|
+
declare function addBreadcrumb(crumb: Omit<Breadcrumb, "timestamp"> & {
|
|
67
|
+
timestamp?: number;
|
|
68
|
+
}): void;
|
|
69
|
+
declare function getClient(): BoobooClient | null;
|
|
70
|
+
|
|
71
|
+
export { type BoobooEvent, type BoobooOptions, type Breadcrumb, type BreadcrumbOptions, type StackFrame, addBreadcrumb, captureException, captureMessage, getClient, init, parseStack };
|
package/dist/index.js
ADDED
package/dist/react.cjs
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkO4OOPXTScjs = require('./chunk-O4OOPXTS.cjs');
|
|
5
|
+
|
|
6
|
+
// src/react.ts
|
|
7
|
+
var _react = require('react');
|
|
8
|
+
var ErrorBoundary = class extends _react.Component {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(...arguments);
|
|
11
|
+
this.state = { error: null };
|
|
12
|
+
this.reset = () => {
|
|
13
|
+
this.setState({ error: null });
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
static getDerivedStateFromError(error) {
|
|
17
|
+
return { error };
|
|
18
|
+
}
|
|
19
|
+
componentDidCatch(error, errorInfo) {
|
|
20
|
+
const client = _chunkO4OOPXTScjs.getClient.call(void 0, );
|
|
21
|
+
if (client) {
|
|
22
|
+
const extra = {};
|
|
23
|
+
if (errorInfo.componentStack) {
|
|
24
|
+
extra.componentStack = errorInfo.componentStack;
|
|
25
|
+
}
|
|
26
|
+
_chunkO4OOPXTScjs.captureException.call(void 0, error, extra);
|
|
27
|
+
}
|
|
28
|
+
_optionalChain([this, 'access', _ => _.props, 'access', _2 => _2.onError, 'optionalCall', _3 => _3(error, errorInfo)]);
|
|
29
|
+
}
|
|
30
|
+
render() {
|
|
31
|
+
if (this.state.error) {
|
|
32
|
+
const { fallback } = this.props;
|
|
33
|
+
if (typeof fallback === "function") {
|
|
34
|
+
return fallback(this.state.error, this.reset);
|
|
35
|
+
}
|
|
36
|
+
return _nullishCoalesce(fallback, () => ( null));
|
|
37
|
+
}
|
|
38
|
+
return this.props.children;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
exports.ErrorBoundary = ErrorBoundary;
|
package/dist/react.d.cts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Component, ReactNode, ErrorInfo } from 'react';
|
|
2
|
+
|
|
3
|
+
interface ErrorBoundaryProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode);
|
|
6
|
+
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
7
|
+
}
|
|
8
|
+
interface ErrorBoundaryState {
|
|
9
|
+
error: Error | null;
|
|
10
|
+
}
|
|
11
|
+
declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
12
|
+
state: ErrorBoundaryState;
|
|
13
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState;
|
|
14
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
|
|
15
|
+
reset: () => void;
|
|
16
|
+
render(): ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { ErrorBoundary };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Component, ReactNode, ErrorInfo } from 'react';
|
|
2
|
+
|
|
3
|
+
interface ErrorBoundaryProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode);
|
|
6
|
+
onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
7
|
+
}
|
|
8
|
+
interface ErrorBoundaryState {
|
|
9
|
+
error: Error | null;
|
|
10
|
+
}
|
|
11
|
+
declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
12
|
+
state: ErrorBoundaryState;
|
|
13
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState;
|
|
14
|
+
componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
|
|
15
|
+
reset: () => void;
|
|
16
|
+
render(): ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { ErrorBoundary };
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
captureException,
|
|
3
|
+
getClient
|
|
4
|
+
} from "./chunk-5PWHK5SB.js";
|
|
5
|
+
|
|
6
|
+
// src/react.ts
|
|
7
|
+
import { Component } from "react";
|
|
8
|
+
var ErrorBoundary = class extends Component {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(...arguments);
|
|
11
|
+
this.state = { error: null };
|
|
12
|
+
this.reset = () => {
|
|
13
|
+
this.setState({ error: null });
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
static getDerivedStateFromError(error) {
|
|
17
|
+
return { error };
|
|
18
|
+
}
|
|
19
|
+
componentDidCatch(error, errorInfo) {
|
|
20
|
+
const client = getClient();
|
|
21
|
+
if (client) {
|
|
22
|
+
const extra = {};
|
|
23
|
+
if (errorInfo.componentStack) {
|
|
24
|
+
extra.componentStack = errorInfo.componentStack;
|
|
25
|
+
}
|
|
26
|
+
captureException(error, extra);
|
|
27
|
+
}
|
|
28
|
+
this.props.onError?.(error, errorInfo);
|
|
29
|
+
}
|
|
30
|
+
render() {
|
|
31
|
+
if (this.state.error) {
|
|
32
|
+
const { fallback } = this.props;
|
|
33
|
+
if (typeof fallback === "function") {
|
|
34
|
+
return fallback(this.state.error, this.reset);
|
|
35
|
+
}
|
|
36
|
+
return fallback ?? null;
|
|
37
|
+
}
|
|
38
|
+
return this.props.children;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
export {
|
|
42
|
+
ErrorBoundary
|
|
43
|
+
};
|
package/dist/vue.cjs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
var _chunkO4OOPXTScjs = require('./chunk-O4OOPXTS.cjs');
|
|
4
|
+
|
|
5
|
+
// src/vue.ts
|
|
6
|
+
function BoobooVue(_options) {
|
|
7
|
+
return {
|
|
8
|
+
install(app) {
|
|
9
|
+
const prevHandler = app.config.errorHandler;
|
|
10
|
+
app.config.errorHandler = (err, instance, info) => {
|
|
11
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
12
|
+
const extra = {
|
|
13
|
+
vueInfo: info
|
|
14
|
+
};
|
|
15
|
+
if (instance) {
|
|
16
|
+
extra.componentName = _optionalChain([instance, 'access', _ => _.$options, 'optionalAccess', _2 => _2.name]) || _optionalChain([instance, 'access', _3 => _3.$options, 'optionalAccess', _4 => _4.__name]) || "<Anonymous>";
|
|
17
|
+
if (instance.$props && typeof instance.$props === "object") {
|
|
18
|
+
extra.propKeys = Object.keys(instance.$props);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
_chunkO4OOPXTScjs.captureException.call(void 0, error, extra);
|
|
22
|
+
if (typeof prevHandler === "function") {
|
|
23
|
+
prevHandler(err, instance, info);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
exports.BoobooVue = BoobooVue;
|
package/dist/vue.d.cts
ADDED
package/dist/vue.d.ts
ADDED
package/dist/vue.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
captureException
|
|
3
|
+
} from "./chunk-5PWHK5SB.js";
|
|
4
|
+
|
|
5
|
+
// src/vue.ts
|
|
6
|
+
function BoobooVue(_options) {
|
|
7
|
+
return {
|
|
8
|
+
install(app) {
|
|
9
|
+
const prevHandler = app.config.errorHandler;
|
|
10
|
+
app.config.errorHandler = (err, instance, info) => {
|
|
11
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
12
|
+
const extra = {
|
|
13
|
+
vueInfo: info
|
|
14
|
+
};
|
|
15
|
+
if (instance) {
|
|
16
|
+
extra.componentName = instance.$options?.name || instance.$options?.__name || "<Anonymous>";
|
|
17
|
+
if (instance.$props && typeof instance.$props === "object") {
|
|
18
|
+
extra.propKeys = Object.keys(instance.$props);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
captureException(error, extra);
|
|
22
|
+
if (typeof prevHandler === "function") {
|
|
23
|
+
prevHandler(err, instance, info);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
BoobooVue
|
|
31
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@booboo.dev/js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official JavaScript SDK for booboo.dev error tracking",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./react": {
|
|
16
|
+
"types": "./dist/react.d.ts",
|
|
17
|
+
"import": "./dist/react.js",
|
|
18
|
+
"require": "./dist/react.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./vue": {
|
|
21
|
+
"types": "./dist/vue.d.ts",
|
|
22
|
+
"import": "./dist/vue.js",
|
|
23
|
+
"require": "./dist/vue.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": ["dist"],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsup",
|
|
29
|
+
"dev": "tsup --watch"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/react": "^19.0.0",
|
|
33
|
+
"tsup": "^8.0.0",
|
|
34
|
+
"typescript": "^5.4.0",
|
|
35
|
+
"vue": "^3.5.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"react": ">=17.0.0",
|
|
39
|
+
"vue": ">=3.0.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependenciesMeta": {
|
|
42
|
+
"react": { "optional": true },
|
|
43
|
+
"vue": { "optional": true }
|
|
44
|
+
},
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/booboo-dev/booboo.dev"
|
|
49
|
+
},
|
|
50
|
+
"keywords": ["error-tracking", "booboo", "monitoring", "javascript", "react", "vue"]
|
|
51
|
+
}
|