bugcatch-sdk 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/README.md +233 -0
- package/dist/index.d.mts +159 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.js +496 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +490 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +86 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
var __objRest = (source, exclude) => {
|
|
18
|
+
var target = {};
|
|
19
|
+
for (var prop in source)
|
|
20
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
21
|
+
target[prop] = source[prop];
|
|
22
|
+
if (source != null && __getOwnPropSymbols)
|
|
23
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
24
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
25
|
+
target[prop] = source[prop];
|
|
26
|
+
}
|
|
27
|
+
return target;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// src/parse-stack.ts
|
|
31
|
+
var CHROME_RE = /^\s*at (?:(.*?) \()?(.+?):(\d+):(\d+)\)?$/;
|
|
32
|
+
var FIREFOX_RE = /^(?:(.+?)@)?(.+?):(\d+):(\d+)$/;
|
|
33
|
+
var INTERNAL_PATTERNS = [/node_modules\//, /bugcatch[-_]?sdk/, /^\(native\)$/, /^native code/];
|
|
34
|
+
function isInApp(filename) {
|
|
35
|
+
if (!filename) return false;
|
|
36
|
+
return !INTERNAL_PATTERNS.some((p) => p.test(filename));
|
|
37
|
+
}
|
|
38
|
+
function parseChromeLine(line) {
|
|
39
|
+
const m = CHROME_RE.exec(line);
|
|
40
|
+
if (!m) return null;
|
|
41
|
+
const [, fn, filename, lineno, colno] = m;
|
|
42
|
+
return {
|
|
43
|
+
function: fn != null ? fn : "<anonymous>",
|
|
44
|
+
filename: filename != null ? filename : void 0,
|
|
45
|
+
lineno: lineno ? parseInt(lineno, 10) : void 0,
|
|
46
|
+
colno: colno ? parseInt(colno, 10) : void 0,
|
|
47
|
+
in_app: isInApp(filename != null ? filename : void 0)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function parseFirefoxLine(line) {
|
|
51
|
+
const m = FIREFOX_RE.exec(line);
|
|
52
|
+
if (!m) return null;
|
|
53
|
+
const [, fn, filename, lineno, colno] = m;
|
|
54
|
+
return {
|
|
55
|
+
function: fn != null ? fn : "<anonymous>",
|
|
56
|
+
filename: filename != null ? filename : void 0,
|
|
57
|
+
lineno: lineno ? parseInt(lineno, 10) : void 0,
|
|
58
|
+
colno: colno ? parseInt(colno, 10) : void 0,
|
|
59
|
+
in_app: isInApp(filename != null ? filename : void 0)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function parseStack(error) {
|
|
63
|
+
var _a, _b;
|
|
64
|
+
const stack = error.stack;
|
|
65
|
+
if (!stack) return [];
|
|
66
|
+
const lines = stack.split("\n");
|
|
67
|
+
const frames = [];
|
|
68
|
+
for (const line of lines) {
|
|
69
|
+
const trimmed = line.trim();
|
|
70
|
+
if (!trimmed || trimmed.startsWith("Error") || trimmed.startsWith((_a = error.message) != null ? _a : "")) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const frame = (_b = parseChromeLine(trimmed)) != null ? _b : parseFirefoxLine(trimmed);
|
|
74
|
+
if (frame) {
|
|
75
|
+
frames.push(frame);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return frames;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/breadcrumbs.ts
|
|
82
|
+
var BreadcrumbBuffer = class {
|
|
83
|
+
constructor(max = 100) {
|
|
84
|
+
this.buffer = [];
|
|
85
|
+
this.max = max;
|
|
86
|
+
}
|
|
87
|
+
add(crumb) {
|
|
88
|
+
if (this.buffer.length >= this.max) {
|
|
89
|
+
this.buffer.shift();
|
|
90
|
+
}
|
|
91
|
+
this.buffer.push(crumb);
|
|
92
|
+
}
|
|
93
|
+
getAll() {
|
|
94
|
+
return [...this.buffer];
|
|
95
|
+
}
|
|
96
|
+
clear() {
|
|
97
|
+
this.buffer.length = 0;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
function installNavigationBreadcrumbs(add) {
|
|
101
|
+
if (typeof window === "undefined") return () => void 0;
|
|
102
|
+
const originalPush = history.pushState.bind(history);
|
|
103
|
+
const originalReplace = history.replaceState.bind(history);
|
|
104
|
+
history.pushState = function(...args) {
|
|
105
|
+
var _a, _b;
|
|
106
|
+
add({
|
|
107
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
108
|
+
type: "navigation",
|
|
109
|
+
category: "navigation",
|
|
110
|
+
message: `Navigated to ${String((_a = args[2]) != null ? _a : "")}`,
|
|
111
|
+
data: { to: String((_b = args[2]) != null ? _b : "") }
|
|
112
|
+
});
|
|
113
|
+
return originalPush(...args);
|
|
114
|
+
};
|
|
115
|
+
history.replaceState = function(...args) {
|
|
116
|
+
var _a, _b;
|
|
117
|
+
add({
|
|
118
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
119
|
+
type: "navigation",
|
|
120
|
+
category: "navigation",
|
|
121
|
+
message: `Replaced state: ${String((_a = args[2]) != null ? _a : "")}`,
|
|
122
|
+
data: { to: String((_b = args[2]) != null ? _b : "") }
|
|
123
|
+
});
|
|
124
|
+
return originalReplace(...args);
|
|
125
|
+
};
|
|
126
|
+
const onPopState = () => {
|
|
127
|
+
add({
|
|
128
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
129
|
+
type: "navigation",
|
|
130
|
+
category: "navigation",
|
|
131
|
+
message: `Navigated back/forward to ${window.location.href}`,
|
|
132
|
+
data: { to: window.location.href }
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
window.addEventListener("popstate", onPopState);
|
|
136
|
+
return () => {
|
|
137
|
+
history.pushState = originalPush;
|
|
138
|
+
history.replaceState = originalReplace;
|
|
139
|
+
window.removeEventListener("popstate", onPopState);
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function installClickBreadcrumbs(add) {
|
|
143
|
+
if (typeof document === "undefined") return () => void 0;
|
|
144
|
+
const handler = (e) => {
|
|
145
|
+
var _a, _b, _c;
|
|
146
|
+
const target = e.target;
|
|
147
|
+
if (!target) return;
|
|
148
|
+
const tag = (_b = (_a = target.tagName) == null ? void 0 : _a.toLowerCase()) != null ? _b : "unknown";
|
|
149
|
+
const text = ((_c = target.textContent) != null ? _c : "").trim().slice(0, 50);
|
|
150
|
+
const id = target.id ? `#${target.id}` : "";
|
|
151
|
+
const cls = target.className && typeof target.className === "string" ? `.${target.className.split(" ").join(".")}` : "";
|
|
152
|
+
add({
|
|
153
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
154
|
+
type: "user",
|
|
155
|
+
category: "ui.click",
|
|
156
|
+
message: `Click on <${tag}${id}${cls}>`,
|
|
157
|
+
data: { tag, text: text || void 0 }
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
document.addEventListener("click", handler, { capture: true, passive: true });
|
|
161
|
+
return () => {
|
|
162
|
+
document.removeEventListener("click", handler, { capture: true });
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function installConsoleBreadcrumbs(add) {
|
|
166
|
+
if (typeof console === "undefined") return () => void 0;
|
|
167
|
+
const originalWarn = console.warn.bind(console);
|
|
168
|
+
const originalError = console.error.bind(console);
|
|
169
|
+
const formatArgs = (args) => args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ").slice(0, 200);
|
|
170
|
+
console.warn = (...args) => {
|
|
171
|
+
add({
|
|
172
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
173
|
+
type: "console",
|
|
174
|
+
category: "console",
|
|
175
|
+
message: formatArgs(args),
|
|
176
|
+
data: { level: "warning" }
|
|
177
|
+
});
|
|
178
|
+
originalWarn(...args);
|
|
179
|
+
};
|
|
180
|
+
console.error = (...args) => {
|
|
181
|
+
add({
|
|
182
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
183
|
+
type: "console",
|
|
184
|
+
category: "console",
|
|
185
|
+
message: formatArgs(args),
|
|
186
|
+
data: { level: "error" }
|
|
187
|
+
});
|
|
188
|
+
originalError(...args);
|
|
189
|
+
};
|
|
190
|
+
return () => {
|
|
191
|
+
console.warn = originalWarn;
|
|
192
|
+
console.error = originalError;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/client.ts
|
|
197
|
+
function uuid() {
|
|
198
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
199
|
+
return crypto.randomUUID();
|
|
200
|
+
}
|
|
201
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
202
|
+
const r = Math.random() * 16 | 0;
|
|
203
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
204
|
+
return v.toString(16);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function parseDsn(dsn) {
|
|
208
|
+
let url;
|
|
209
|
+
try {
|
|
210
|
+
url = new URL(dsn);
|
|
211
|
+
} catch (e) {
|
|
212
|
+
throw new Error(`[BugCatch] Invalid DSN: "${dsn}"`);
|
|
213
|
+
}
|
|
214
|
+
const sdkKey = url.searchParams.get("key");
|
|
215
|
+
if (!sdkKey) {
|
|
216
|
+
throw new Error(`[BugCatch] DSN is missing the "key" query parameter: "${dsn}"`);
|
|
217
|
+
}
|
|
218
|
+
const segments = url.pathname.split("/").filter(Boolean);
|
|
219
|
+
const projectId = segments[segments.length - 1];
|
|
220
|
+
if (!projectId) {
|
|
221
|
+
throw new Error(`[BugCatch] Could not extract projectId from DSN path: "${dsn}"`);
|
|
222
|
+
}
|
|
223
|
+
const ingestUrl = `${url.origin}${url.pathname}?key=${sdkKey}`;
|
|
224
|
+
return { ingestUrl, projectId, sdkKey };
|
|
225
|
+
}
|
|
226
|
+
function matchesPattern(value, patterns) {
|
|
227
|
+
return patterns.some(
|
|
228
|
+
(p) => typeof p === "string" ? value.includes(p) : p.test(value)
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
var BugCatchClient = class {
|
|
232
|
+
constructor(options) {
|
|
233
|
+
this.user = {};
|
|
234
|
+
this.tags = {};
|
|
235
|
+
this.cleanups = [];
|
|
236
|
+
this.opts = __spreadValues({
|
|
237
|
+
debug: false,
|
|
238
|
+
maxBreadcrumbs: 100,
|
|
239
|
+
autoCaptureErrors: true,
|
|
240
|
+
autoCaptureBreadcrumbs: true
|
|
241
|
+
}, options);
|
|
242
|
+
this.dsn = parseDsn(options.dsn);
|
|
243
|
+
this.crumbs = new BreadcrumbBuffer(this.opts.maxBreadcrumbs);
|
|
244
|
+
if (this.opts.autoCaptureErrors) {
|
|
245
|
+
this.installErrorHandlers();
|
|
246
|
+
}
|
|
247
|
+
if (this.opts.autoCaptureBreadcrumbs) {
|
|
248
|
+
this.cleanups.push(installNavigationBreadcrumbs((c) => this.addBreadcrumb(c)));
|
|
249
|
+
this.cleanups.push(installClickBreadcrumbs((c) => this.addBreadcrumb(c)));
|
|
250
|
+
this.cleanups.push(installConsoleBreadcrumbs((c) => this.addBreadcrumb(c)));
|
|
251
|
+
}
|
|
252
|
+
this.log("Initialized. Project:", this.dsn.projectId);
|
|
253
|
+
}
|
|
254
|
+
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
255
|
+
captureException(error, extra) {
|
|
256
|
+
const event = this.buildExceptionPayload(error, extra);
|
|
257
|
+
void this.send(event);
|
|
258
|
+
return event.event_id;
|
|
259
|
+
}
|
|
260
|
+
captureMessage(message, level = "info", extra) {
|
|
261
|
+
const event = this.buildMessagePayload(message, level, extra);
|
|
262
|
+
void this.send(event);
|
|
263
|
+
return event.event_id;
|
|
264
|
+
}
|
|
265
|
+
setUser(user) {
|
|
266
|
+
this.user = __spreadValues({}, user);
|
|
267
|
+
}
|
|
268
|
+
clearUser() {
|
|
269
|
+
this.user = {};
|
|
270
|
+
}
|
|
271
|
+
setTag(key, value) {
|
|
272
|
+
this.tags[key] = value;
|
|
273
|
+
}
|
|
274
|
+
addBreadcrumb(crumb) {
|
|
275
|
+
this.crumbs.add(crumb);
|
|
276
|
+
}
|
|
277
|
+
/** Tear down all global listeners. Call when unmounting in SPAs. */
|
|
278
|
+
destroy() {
|
|
279
|
+
for (const cleanup of this.cleanups) {
|
|
280
|
+
cleanup();
|
|
281
|
+
}
|
|
282
|
+
this.cleanups.length = 0;
|
|
283
|
+
}
|
|
284
|
+
// ─── Internal: build payloads ────────────────────────────────────────────
|
|
285
|
+
buildExceptionPayload(error, extra) {
|
|
286
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
287
|
+
const frames = parseStack(err);
|
|
288
|
+
const exceptionValue = {
|
|
289
|
+
type: err.name || "Error",
|
|
290
|
+
value: err.message,
|
|
291
|
+
stacktrace: frames.length > 0 ? { frames } : void 0
|
|
292
|
+
};
|
|
293
|
+
return this.buildBase({
|
|
294
|
+
level: "error",
|
|
295
|
+
exception: { values: [exceptionValue] },
|
|
296
|
+
extra
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
buildMessagePayload(message, level, extra) {
|
|
300
|
+
return this.buildBase({ level, message, extra });
|
|
301
|
+
}
|
|
302
|
+
buildBase(overrides) {
|
|
303
|
+
const _a = overrides, { extra } = _a, rest = __objRest(_a, ["extra"]);
|
|
304
|
+
const payload = __spreadValues({
|
|
305
|
+
event_id: uuid(),
|
|
306
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
307
|
+
platform: "javascript"
|
|
308
|
+
}, rest);
|
|
309
|
+
if (this.opts.release) payload.release = this.opts.release;
|
|
310
|
+
if (this.opts.environment) payload.environment = this.opts.environment;
|
|
311
|
+
if (Object.keys(this.user).length > 0) {
|
|
312
|
+
payload.user = __spreadValues({}, this.user);
|
|
313
|
+
}
|
|
314
|
+
if (Object.keys(this.tags).length > 0) {
|
|
315
|
+
payload.tags = __spreadValues({}, this.tags);
|
|
316
|
+
}
|
|
317
|
+
if (extra && Object.keys(extra).length > 0) {
|
|
318
|
+
payload.extra = extra;
|
|
319
|
+
}
|
|
320
|
+
const breadcrumbs = this.crumbs.getAll();
|
|
321
|
+
if (breadcrumbs.length > 0) {
|
|
322
|
+
payload.breadcrumbs = breadcrumbs;
|
|
323
|
+
}
|
|
324
|
+
if (typeof window !== "undefined") {
|
|
325
|
+
payload.request = {
|
|
326
|
+
url: window.location.href,
|
|
327
|
+
headers: {
|
|
328
|
+
"user-agent": navigator.userAgent
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
return payload;
|
|
333
|
+
}
|
|
334
|
+
// ─── Internal: error handlers ────────────────────────────────────────────
|
|
335
|
+
installErrorHandlers() {
|
|
336
|
+
if (typeof window === "undefined") {
|
|
337
|
+
const onUncaught = (err) => {
|
|
338
|
+
this.captureException(err, { handler: "uncaughtException" });
|
|
339
|
+
};
|
|
340
|
+
const onUnhandled = (reason) => {
|
|
341
|
+
this.captureException(reason, { handler: "unhandledRejection" });
|
|
342
|
+
};
|
|
343
|
+
process.on("uncaughtException", onUncaught);
|
|
344
|
+
process.on("unhandledRejection", onUnhandled);
|
|
345
|
+
this.cleanups.push(() => {
|
|
346
|
+
process.off("uncaughtException", onUncaught);
|
|
347
|
+
process.off("unhandledRejection", onUnhandled);
|
|
348
|
+
});
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const onError = (event) => {
|
|
352
|
+
var _a;
|
|
353
|
+
if (!event.error) return;
|
|
354
|
+
if (this.shouldIgnore(event.error, (_a = event.filename) != null ? _a : "")) return;
|
|
355
|
+
this.captureException(event.error, { handler: "window.onerror" });
|
|
356
|
+
};
|
|
357
|
+
const onUnhandledRejection = (event) => {
|
|
358
|
+
const reason = event.reason;
|
|
359
|
+
if (this.shouldIgnore(reason, "")) return;
|
|
360
|
+
this.captureException(reason, { handler: "unhandledrejection" });
|
|
361
|
+
};
|
|
362
|
+
window.addEventListener("error", onError);
|
|
363
|
+
window.addEventListener("unhandledrejection", onUnhandledRejection);
|
|
364
|
+
this.cleanups.push(() => {
|
|
365
|
+
window.removeEventListener("error", onError);
|
|
366
|
+
window.removeEventListener("unhandledrejection", onUnhandledRejection);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
shouldIgnore(error, scriptUrl) {
|
|
370
|
+
const { ignoreUrls, ignoreErrors } = this.opts;
|
|
371
|
+
if ((ignoreUrls == null ? void 0 : ignoreUrls.length) && scriptUrl) {
|
|
372
|
+
if (matchesPattern(scriptUrl, ignoreUrls)) return true;
|
|
373
|
+
}
|
|
374
|
+
if (ignoreErrors == null ? void 0 : ignoreErrors.length) {
|
|
375
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
376
|
+
if (matchesPattern(message, ignoreErrors)) return true;
|
|
377
|
+
}
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
// ─── Internal: transport ─────────────────────────────────────────────────
|
|
381
|
+
async send(event) {
|
|
382
|
+
let finalEvent = event;
|
|
383
|
+
if (this.opts.beforeSend) {
|
|
384
|
+
finalEvent = this.opts.beforeSend(event);
|
|
385
|
+
if (finalEvent === false) {
|
|
386
|
+
this.log("Event dropped by beforeSend hook");
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
this.log("Sending event:", finalEvent.event_id, finalEvent.level);
|
|
391
|
+
try {
|
|
392
|
+
const res = await fetch(this.dsn.ingestUrl, {
|
|
393
|
+
method: "POST",
|
|
394
|
+
headers: { "Content-Type": "application/json" },
|
|
395
|
+
body: JSON.stringify(finalEvent),
|
|
396
|
+
keepalive: true
|
|
397
|
+
// allow the request to outlive the page
|
|
398
|
+
});
|
|
399
|
+
if (!res.ok) {
|
|
400
|
+
this.log(`Ingest responded with ${res.status}:`, await res.text());
|
|
401
|
+
}
|
|
402
|
+
} catch (err) {
|
|
403
|
+
this.log("Failed to send event:", err);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
log(...args) {
|
|
407
|
+
if (this.opts.debug) {
|
|
408
|
+
console.debug("[BugCatch]", ...args);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// src/index.ts
|
|
414
|
+
var _client = null;
|
|
415
|
+
function getClient() {
|
|
416
|
+
if (!_client) {
|
|
417
|
+
throw new Error("[BugCatch] SDK not initialized. Call BugCatch.init(options) first.");
|
|
418
|
+
}
|
|
419
|
+
return _client;
|
|
420
|
+
}
|
|
421
|
+
var BugCatch = {
|
|
422
|
+
/**
|
|
423
|
+
* Initialize the SDK. Call this once, as early as possible in your app.
|
|
424
|
+
*
|
|
425
|
+
* @example
|
|
426
|
+
* BugCatch.init({
|
|
427
|
+
* dsn: 'http://localhost:3000/ingest/project-id?key=sdk-key',
|
|
428
|
+
* release: '1.0.0',
|
|
429
|
+
* environment: 'production',
|
|
430
|
+
* });
|
|
431
|
+
*/
|
|
432
|
+
init(options) {
|
|
433
|
+
if (_client) {
|
|
434
|
+
console.warn("[BugCatch] init() called more than once. Ignoring.");
|
|
435
|
+
return _client;
|
|
436
|
+
}
|
|
437
|
+
_client = new BugCatchClient(options);
|
|
438
|
+
return _client;
|
|
439
|
+
},
|
|
440
|
+
/**
|
|
441
|
+
* Capture an Error object or any value as an error event.
|
|
442
|
+
* Returns the generated event_id.
|
|
443
|
+
*/
|
|
444
|
+
captureException(error, extra) {
|
|
445
|
+
return getClient().captureException(error, extra);
|
|
446
|
+
},
|
|
447
|
+
/**
|
|
448
|
+
* Capture a plain text message as an event.
|
|
449
|
+
* Returns the generated event_id.
|
|
450
|
+
*/
|
|
451
|
+
captureMessage(message, level, extra) {
|
|
452
|
+
return getClient().captureMessage(message, level, extra);
|
|
453
|
+
},
|
|
454
|
+
/**
|
|
455
|
+
* Set the current user context. Attached to all subsequent events.
|
|
456
|
+
*/
|
|
457
|
+
setUser(user) {
|
|
458
|
+
getClient().setUser(user);
|
|
459
|
+
},
|
|
460
|
+
/**
|
|
461
|
+
* Clear the current user context (e.g. on logout).
|
|
462
|
+
*/
|
|
463
|
+
clearUser() {
|
|
464
|
+
getClient().clearUser();
|
|
465
|
+
},
|
|
466
|
+
/**
|
|
467
|
+
* Set a tag that will be attached to all subsequent events.
|
|
468
|
+
*/
|
|
469
|
+
setTag(key, value) {
|
|
470
|
+
getClient().setTag(key, value);
|
|
471
|
+
},
|
|
472
|
+
/**
|
|
473
|
+
* Manually add a breadcrumb.
|
|
474
|
+
*/
|
|
475
|
+
addBreadcrumb(crumb) {
|
|
476
|
+
getClient().addBreadcrumb(crumb);
|
|
477
|
+
},
|
|
478
|
+
/**
|
|
479
|
+
* Tear down all listeners. Useful in SPA cleanup or hot-reload scenarios.
|
|
480
|
+
*/
|
|
481
|
+
destroy() {
|
|
482
|
+
_client == null ? void 0 : _client.destroy();
|
|
483
|
+
_client = null;
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
var index_default = BugCatch;
|
|
487
|
+
|
|
488
|
+
export { BugCatch, BugCatchClient, index_default as default };
|
|
489
|
+
//# sourceMappingURL=index.mjs.map
|
|
490
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/parse-stack.ts","../src/breadcrumbs.ts","../src/client.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { StackFrame } from './types.js';\n\n// Chrome/V8: \" at functionName (filename:line:col)\"\n// \" at filename:line:col\"\nconst CHROME_RE = /^\\s*at (?:(.*?) \\()?(.+?):(\\d+):(\\d+)\\)?$/;\n\n// Firefox/Safari: \"functionName@filename:line:col\"\n// \"@filename:line:col\"\nconst FIREFOX_RE = /^(?:(.+?)@)?(.+?):(\\d+):(\\d+)$/;\n\n// Origins that are not \"in-app\" frames\nconst INTERNAL_PATTERNS = [/node_modules\\//, /bugcatch[-_]?sdk/, /^\\(native\\)$/, /^native code/];\n\nfunction isInApp(filename: string | undefined): boolean {\n if (!filename) return false;\n return !INTERNAL_PATTERNS.some((p) => p.test(filename));\n}\n\nfunction parseChromeLine(line: string): StackFrame | null {\n const m = CHROME_RE.exec(line);\n if (!m) return null;\n const [, fn, filename, lineno, colno] = m;\n return {\n function: fn ?? '<anonymous>',\n filename: filename ?? undefined,\n lineno: lineno ? parseInt(lineno, 10) : undefined,\n colno: colno ? parseInt(colno, 10) : undefined,\n in_app: isInApp(filename ?? undefined),\n };\n}\n\nfunction parseFirefoxLine(line: string): StackFrame | null {\n const m = FIREFOX_RE.exec(line);\n if (!m) return null;\n const [, fn, filename, lineno, colno] = m;\n return {\n function: fn ?? '<anonymous>',\n filename: filename ?? undefined,\n lineno: lineno ? parseInt(lineno, 10) : undefined,\n colno: colno ? parseInt(colno, 10) : undefined,\n in_app: isInApp(filename ?? undefined),\n };\n}\n\nexport function parseStack(error: Error): StackFrame[] {\n const stack = error.stack;\n if (!stack) return [];\n\n const lines = stack.split('\\n');\n const frames: StackFrame[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('Error') || trimmed.startsWith(error.message ?? '')) {\n continue;\n }\n const frame = parseChromeLine(trimmed) ?? parseFirefoxLine(trimmed);\n if (frame) {\n frames.push(frame);\n }\n }\n\n // The API fingerprinting uses the LAST in-app frame, which maps to innermost\n // call. Return in innermost-first order (as captured).\n return frames;\n}\n","import type { BreadcrumbEntry } from './types.js';\n\nexport class BreadcrumbBuffer {\n private readonly buffer: BreadcrumbEntry[] = [];\n private readonly max: number;\n\n constructor(max = 100) {\n this.max = max;\n }\n\n add(crumb: BreadcrumbEntry): void {\n if (this.buffer.length >= this.max) {\n this.buffer.shift();\n }\n this.buffer.push(crumb);\n }\n\n getAll(): BreadcrumbEntry[] {\n return [...this.buffer];\n }\n\n clear(): void {\n this.buffer.length = 0;\n }\n}\n\n// ─── Auto-capture helpers ─────────────────────────────────────────────────────\n\ntype AddFn = (crumb: BreadcrumbEntry) => void;\n\n/**\n * Patch History API (pushState / replaceState / popstate) to capture\n * navigation breadcrumbs.\n */\nexport function installNavigationBreadcrumbs(add: AddFn): () => void {\n if (typeof window === 'undefined') return () => undefined;\n\n const originalPush = history.pushState.bind(history);\n const originalReplace = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n add({\n timestamp: new Date().toISOString(),\n type: 'navigation',\n category: 'navigation',\n message: `Navigated to ${String(args[2] ?? '')}`,\n data: { to: String(args[2] ?? '') },\n });\n return originalPush(...args);\n };\n\n history.replaceState = function (...args) {\n add({\n timestamp: new Date().toISOString(),\n type: 'navigation',\n category: 'navigation',\n message: `Replaced state: ${String(args[2] ?? '')}`,\n data: { to: String(args[2] ?? '') },\n });\n return originalReplace(...args);\n };\n\n const onPopState = () => {\n add({\n timestamp: new Date().toISOString(),\n type: 'navigation',\n category: 'navigation',\n message: `Navigated back/forward to ${window.location.href}`,\n data: { to: window.location.href },\n });\n };\n\n window.addEventListener('popstate', onPopState);\n\n return () => {\n history.pushState = originalPush;\n history.replaceState = originalReplace;\n window.removeEventListener('popstate', onPopState);\n };\n}\n\n/**\n * Capture click events as breadcrumbs (element tag + text).\n */\nexport function installClickBreadcrumbs(add: AddFn): () => void {\n if (typeof document === 'undefined') return () => undefined;\n\n const handler = (e: MouseEvent) => {\n const target = e.target as HTMLElement | null;\n if (!target) return;\n const tag = target.tagName?.toLowerCase() ?? 'unknown';\n const text = (target.textContent ?? '').trim().slice(0, 50);\n const id = target.id ? `#${target.id}` : '';\n const cls = target.className && typeof target.className === 'string'\n ? `.${target.className.split(' ').join('.')}`\n : '';\n add({\n timestamp: new Date().toISOString(),\n type: 'user',\n category: 'ui.click',\n message: `Click on <${tag}${id}${cls}>`,\n data: { tag, text: text || undefined },\n });\n };\n\n document.addEventListener('click', handler, { capture: true, passive: true });\n\n return () => {\n document.removeEventListener('click', handler, { capture: true });\n };\n}\n\n/**\n * Capture console.warn and console.error calls as breadcrumbs.\n */\nexport function installConsoleBreadcrumbs(add: AddFn): () => void {\n if (typeof console === 'undefined') return () => undefined;\n\n const originalWarn = console.warn.bind(console);\n const originalError = console.error.bind(console);\n\n const formatArgs = (args: unknown[]): string =>\n args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' ').slice(0, 200);\n\n console.warn = (...args: unknown[]) => {\n add({\n timestamp: new Date().toISOString(),\n type: 'console',\n category: 'console',\n message: formatArgs(args),\n data: { level: 'warning' },\n });\n originalWarn(...args);\n };\n\n console.error = (...args: unknown[]) => {\n add({\n timestamp: new Date().toISOString(),\n type: 'console',\n category: 'console',\n message: formatArgs(args),\n data: { level: 'error' },\n });\n originalError(...args);\n };\n\n return () => {\n console.warn = originalWarn;\n console.error = originalError;\n };\n}\n","import type {\n BugCatchOptions,\n UserContext,\n BreadcrumbEntry,\n EventPayload,\n ParsedDsn,\n ExceptionValue,\n} from './types.js';\nimport { parseStack } from './parse-stack.js';\nimport {\n BreadcrumbBuffer,\n installNavigationBreadcrumbs,\n installClickBreadcrumbs,\n installConsoleBreadcrumbs,\n} from './breadcrumbs.js';\n\n// ─── UUID ─────────────────────────────────────────────────────────────────────\n\nfunction uuid(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n// ─── DSN parser ───────────────────────────────────────────────────────────────\n\nfunction parseDsn(dsn: string): ParsedDsn {\n let url: URL;\n try {\n url = new URL(dsn);\n } catch {\n throw new Error(`[BugCatch] Invalid DSN: \"${dsn}\"`);\n }\n\n const sdkKey = url.searchParams.get('key');\n if (!sdkKey) {\n throw new Error(`[BugCatch] DSN is missing the \"key\" query parameter: \"${dsn}\"`);\n }\n\n // Extract projectId from the last path segment (/ingest/{projectId})\n const segments = url.pathname.split('/').filter(Boolean);\n const projectId = segments[segments.length - 1];\n if (!projectId) {\n throw new Error(`[BugCatch] Could not extract projectId from DSN path: \"${dsn}\"`);\n }\n\n // Reconstruct the URL without extra query params\n const ingestUrl = `${url.origin}${url.pathname}?key=${sdkKey}`;\n\n return { ingestUrl, projectId, sdkKey };\n}\n\n// ─── Pattern matching ─────────────────────────────────────────────────────────\n\nfunction matchesPattern(value: string, patterns: Array<string | RegExp>): boolean {\n return patterns.some((p) =>\n typeof p === 'string' ? value.includes(p) : p.test(value),\n );\n}\n\n// ─── Client ───────────────────────────────────────────────────────────────────\n\nexport class BugCatchClient {\n private readonly opts: Required<\n Pick<BugCatchOptions, 'debug' | 'maxBreadcrumbs' | 'autoCaptureErrors' | 'autoCaptureBreadcrumbs'>\n > & BugCatchOptions;\n\n private readonly dsn: ParsedDsn;\n private readonly crumbs: BreadcrumbBuffer;\n private user: UserContext = {};\n private tags: Record<string, string> = {};\n private readonly cleanups: Array<() => void> = [];\n\n constructor(options: BugCatchOptions) {\n this.opts = {\n debug: false,\n maxBreadcrumbs: 100,\n autoCaptureErrors: true,\n autoCaptureBreadcrumbs: true,\n ...options,\n };\n\n this.dsn = parseDsn(options.dsn);\n this.crumbs = new BreadcrumbBuffer(this.opts.maxBreadcrumbs);\n\n if (this.opts.autoCaptureErrors) {\n this.installErrorHandlers();\n }\n\n if (this.opts.autoCaptureBreadcrumbs) {\n this.cleanups.push(installNavigationBreadcrumbs((c) => this.addBreadcrumb(c)));\n this.cleanups.push(installClickBreadcrumbs((c) => this.addBreadcrumb(c)));\n this.cleanups.push(installConsoleBreadcrumbs((c) => this.addBreadcrumb(c)));\n }\n\n this.log('Initialized. Project:', this.dsn.projectId);\n }\n\n // ─── Public API ─────────────────────────────────────────────────────────────\n\n captureException(error: unknown, extra?: Record<string, unknown>): string {\n const event = this.buildExceptionPayload(error, extra);\n void this.send(event);\n return event.event_id;\n }\n\n captureMessage(message: string, level: string = 'info', extra?: Record<string, unknown>): string {\n const event = this.buildMessagePayload(message, level, extra);\n void this.send(event);\n return event.event_id;\n }\n\n setUser(user: UserContext): void {\n this.user = { ...user };\n }\n\n clearUser(): void {\n this.user = {};\n }\n\n setTag(key: string, value: string): void {\n this.tags[key] = value;\n }\n\n addBreadcrumb(crumb: BreadcrumbEntry): void {\n this.crumbs.add(crumb);\n }\n\n /** Tear down all global listeners. Call when unmounting in SPAs. */\n destroy(): void {\n for (const cleanup of this.cleanups) {\n cleanup();\n }\n this.cleanups.length = 0;\n }\n\n // ─── Internal: build payloads ────────────────────────────────────────────\n\n private buildExceptionPayload(\n error: unknown,\n extra?: Record<string, unknown>,\n ): EventPayload {\n const err = error instanceof Error ? error : new Error(String(error));\n const frames = parseStack(err);\n\n const exceptionValue: ExceptionValue = {\n type: err.name || 'Error',\n value: err.message,\n stacktrace: frames.length > 0 ? { frames } : undefined,\n };\n\n return this.buildBase({\n level: 'error',\n exception: { values: [exceptionValue] },\n extra,\n });\n }\n\n private buildMessagePayload(\n message: string,\n level: string,\n extra?: Record<string, unknown>,\n ): EventPayload {\n return this.buildBase({ level, message, extra });\n }\n\n private buildBase(\n overrides: Partial<EventPayload> & { extra?: Record<string, unknown> },\n ): EventPayload {\n const { extra, ...rest } = overrides;\n const payload: EventPayload = {\n event_id: uuid(),\n timestamp: new Date().toISOString(),\n platform: 'javascript',\n ...rest,\n };\n\n if (this.opts.release) payload.release = this.opts.release;\n if (this.opts.environment) payload.environment = this.opts.environment;\n\n if (Object.keys(this.user).length > 0) {\n payload.user = { ...this.user };\n }\n\n if (Object.keys(this.tags).length > 0) {\n payload.tags = { ...this.tags };\n }\n\n if (extra && Object.keys(extra).length > 0) {\n payload.extra = extra;\n }\n\n const breadcrumbs = this.crumbs.getAll();\n if (breadcrumbs.length > 0) {\n payload.breadcrumbs = breadcrumbs;\n }\n\n // Capture browser request context\n if (typeof window !== 'undefined') {\n payload.request = {\n url: window.location.href,\n headers: {\n 'user-agent': navigator.userAgent,\n },\n };\n }\n\n return payload;\n }\n\n // ─── Internal: error handlers ────────────────────────────────────────────\n\n private installErrorHandlers(): void {\n if (typeof window === 'undefined') {\n // Node.js environment\n const onUncaught = (err: Error) => {\n this.captureException(err, { handler: 'uncaughtException' });\n };\n const onUnhandled = (reason: unknown) => {\n this.captureException(reason, { handler: 'unhandledRejection' });\n };\n process.on('uncaughtException', onUncaught);\n process.on('unhandledRejection', onUnhandled);\n this.cleanups.push(() => {\n process.off('uncaughtException', onUncaught);\n process.off('unhandledRejection', onUnhandled);\n });\n return;\n }\n\n // Browser environment\n const onError = (event: ErrorEvent) => {\n if (!event.error) return;\n if (this.shouldIgnore(event.error, event.filename ?? '')) return;\n this.captureException(event.error, { handler: 'window.onerror' });\n };\n\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason as unknown;\n if (this.shouldIgnore(reason, '')) return;\n this.captureException(reason, { handler: 'unhandledrejection' });\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n\n this.cleanups.push(() => {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onUnhandledRejection);\n });\n }\n\n private shouldIgnore(error: unknown, scriptUrl: string): boolean {\n const { ignoreUrls, ignoreErrors } = this.opts;\n\n if (ignoreUrls?.length && scriptUrl) {\n if (matchesPattern(scriptUrl, ignoreUrls)) return true;\n }\n\n if (ignoreErrors?.length) {\n const message = error instanceof Error ? error.message : String(error);\n if (matchesPattern(message, ignoreErrors)) return true;\n }\n\n return false;\n }\n\n // ─── Internal: transport ─────────────────────────────────────────────────\n\n private async send(event: EventPayload): Promise<void> {\n let finalEvent: EventPayload | false = event;\n\n if (this.opts.beforeSend) {\n finalEvent = this.opts.beforeSend(event);\n if (finalEvent === false) {\n this.log('Event dropped by beforeSend hook');\n return;\n }\n }\n\n this.log('Sending event:', finalEvent.event_id, finalEvent.level);\n\n try {\n const res = await fetch(this.dsn.ingestUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(finalEvent),\n keepalive: true, // allow the request to outlive the page\n });\n\n if (!res.ok) {\n this.log(`Ingest responded with ${res.status}:`, await res.text());\n }\n } catch (err) {\n this.log('Failed to send event:', err);\n }\n }\n\n private log(...args: unknown[]): void {\n if (this.opts.debug) {\n console.debug('[BugCatch]', ...args);\n }\n }\n}\n","import { BugCatchClient } from './client.js';\nimport type { BugCatchOptions, UserContext, BreadcrumbEntry } from './types.js';\n\nexport type { BugCatchOptions, UserContext, BreadcrumbEntry };\nexport type { EventPayload, StackFrame, ParsedDsn } from './types.js';\nexport { BugCatchClient };\n\n// ─── Singleton instance ───────────────────────────────────────────────────────\n\nlet _client: BugCatchClient | null = null;\n\nfunction getClient(): BugCatchClient {\n if (!_client) {\n throw new Error('[BugCatch] SDK not initialized. Call BugCatch.init(options) first.');\n }\n return _client;\n}\n\n// ─── Public singleton API ─────────────────────────────────────────────────────\n\nconst BugCatch = {\n /**\n * Initialize the SDK. Call this once, as early as possible in your app.\n *\n * @example\n * BugCatch.init({\n * dsn: 'http://localhost:3000/ingest/project-id?key=sdk-key',\n * release: '1.0.0',\n * environment: 'production',\n * });\n */\n init(options: BugCatchOptions): BugCatchClient {\n if (_client) {\n console.warn('[BugCatch] init() called more than once. Ignoring.');\n return _client;\n }\n _client = new BugCatchClient(options);\n return _client;\n },\n\n /**\n * Capture an Error object or any value as an error event.\n * Returns the generated event_id.\n */\n captureException(error: unknown, extra?: Record<string, unknown>): string {\n return getClient().captureException(error, extra);\n },\n\n /**\n * Capture a plain text message as an event.\n * Returns the generated event_id.\n */\n captureMessage(message: string, level?: string, extra?: Record<string, unknown>): string {\n return getClient().captureMessage(message, level, extra);\n },\n\n /**\n * Set the current user context. Attached to all subsequent events.\n */\n setUser(user: UserContext): void {\n getClient().setUser(user);\n },\n\n /**\n * Clear the current user context (e.g. on logout).\n */\n clearUser(): void {\n getClient().clearUser();\n },\n\n /**\n * Set a tag that will be attached to all subsequent events.\n */\n setTag(key: string, value: string): void {\n getClient().setTag(key, value);\n },\n\n /**\n * Manually add a breadcrumb.\n */\n addBreadcrumb(crumb: BreadcrumbEntry): void {\n getClient().addBreadcrumb(crumb);\n },\n\n /**\n * Tear down all listeners. Useful in SPA cleanup or hot-reload scenarios.\n */\n destroy(): void {\n _client?.destroy();\n _client = null;\n },\n};\n\n// Named export for CJS consumers: const { BugCatch } = require('bugcatch-sdk')\nexport { BugCatch };\n\n// Default export for ESM consumers: import BugCatch from 'bugcatch-sdk'\nexport default BugCatch;\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bugcatch-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official JavaScript/TypeScript SDK for BugCatch error tracking",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"dev": "tsup --watch",
|
|
21
|
+
"typecheck": "tsc --noEmit"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"bugcatch",
|
|
25
|
+
"error-tracking",
|
|
26
|
+
"sdk",
|
|
27
|
+
"monitoring"
|
|
28
|
+
],
|
|
29
|
+
"author": "",
|
|
30
|
+
"license": "ISC",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.3.0",
|
|
33
|
+
"tsup": "^8.5.1",
|
|
34
|
+
"typescript": "^5.9.3"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"acorn": "^8.16.0",
|
|
38
|
+
"any-promise": "^1.3.0",
|
|
39
|
+
"bundle-require": "^5.1.0",
|
|
40
|
+
"cac": "^6.7.14",
|
|
41
|
+
"chokidar": "^4.0.3",
|
|
42
|
+
"commander": "^4.1.1",
|
|
43
|
+
"confbox": "^0.1.8",
|
|
44
|
+
"consola": "^3.4.2",
|
|
45
|
+
"debug": "^4.4.3",
|
|
46
|
+
"esbuild": "^0.27.3",
|
|
47
|
+
"fdir": "^6.5.0",
|
|
48
|
+
"fix-dts-default-cjs-exports": "^1.0.1",
|
|
49
|
+
"joycon": "^3.1.1",
|
|
50
|
+
"lilconfig": "^3.1.3",
|
|
51
|
+
"lines-and-columns": "^1.2.4",
|
|
52
|
+
"load-tsconfig": "^0.2.5",
|
|
53
|
+
"magic-string": "^0.30.21",
|
|
54
|
+
"mlly": "^1.8.0",
|
|
55
|
+
"ms": "^2.1.3",
|
|
56
|
+
"mz": "^2.7.0",
|
|
57
|
+
"object-assign": "^4.1.1",
|
|
58
|
+
"pathe": "^2.0.3",
|
|
59
|
+
"picocolors": "^1.1.1",
|
|
60
|
+
"picomatch": "^4.0.3",
|
|
61
|
+
"pirates": "^4.0.7",
|
|
62
|
+
"pkg-types": "^1.3.1",
|
|
63
|
+
"postcss-load-config": "^6.0.1",
|
|
64
|
+
"readdirp": "^4.1.2",
|
|
65
|
+
"resolve-from": "^5.0.0",
|
|
66
|
+
"rollup": "^4.59.0",
|
|
67
|
+
"source-map": "^0.7.6",
|
|
68
|
+
"sucrase": "^3.35.1",
|
|
69
|
+
"thenify": "^3.3.1",
|
|
70
|
+
"thenify-all": "^1.6.0",
|
|
71
|
+
"tinyexec": "^0.3.2",
|
|
72
|
+
"tinyglobby": "^0.2.15",
|
|
73
|
+
"tree-kill": "^1.2.2",
|
|
74
|
+
"ts-interface-checker": "^0.1.13",
|
|
75
|
+
"ufo": "^1.6.3",
|
|
76
|
+
"undici-types": "^7.18.2"
|
|
77
|
+
},
|
|
78
|
+
"repository": {
|
|
79
|
+
"type": "git",
|
|
80
|
+
"url": "git+https://github.com/lazarevic-00/bugcatch-sdk.git"
|
|
81
|
+
},
|
|
82
|
+
"bugs": {
|
|
83
|
+
"url": "https://github.com/lazarevic-00/bugcatch-sdk/issues"
|
|
84
|
+
},
|
|
85
|
+
"homepage": "https://github.com/lazarevic-00/bugcatch-sdk#readme"
|
|
86
|
+
}
|