glitchgrab 1.15.0 → 1.17.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/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +143 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +140 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -288,4 +288,12 @@ declare function captureContext(visitedPages: string[]): CapturedContext;
|
|
|
288
288
|
*/
|
|
289
289
|
declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<ReportResult | null>;
|
|
290
290
|
|
|
291
|
-
|
|
291
|
+
declare function computeSignature(params: {
|
|
292
|
+
errorMessage: string | undefined;
|
|
293
|
+
pageUrl: string | undefined;
|
|
294
|
+
errorStack?: string | undefined;
|
|
295
|
+
}): string;
|
|
296
|
+
declare function shouldSkipDuplicate(signature: string, windowMs?: number, now?: number): boolean;
|
|
297
|
+
declare function clearDedupCache(): void;
|
|
298
|
+
|
|
299
|
+
export { type Breadcrumb, type BreadcrumbType, type CapturedContext, type DeviceInfo, type GlitchgrabConfig, GlitchgrabErrorBoundary, GlitchgrabProvider, type GlitchgrabProviderProps, type GlitchgrabReport, type GlitchgrabSession, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportSeverity, type ReportType, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, clearBreadcrumbs, clearDedupCache, computeSignature, fetchGlitchgrabReports, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, shouldSkipDuplicate, useGlitchgrab, useGlitchgrabActions, useGlitchgrabReports };
|
package/dist/index.d.ts
CHANGED
|
@@ -288,4 +288,12 @@ declare function captureContext(visitedPages: string[]): CapturedContext;
|
|
|
288
288
|
*/
|
|
289
289
|
declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<ReportResult | null>;
|
|
290
290
|
|
|
291
|
-
|
|
291
|
+
declare function computeSignature(params: {
|
|
292
|
+
errorMessage: string | undefined;
|
|
293
|
+
pageUrl: string | undefined;
|
|
294
|
+
errorStack?: string | undefined;
|
|
295
|
+
}): string;
|
|
296
|
+
declare function shouldSkipDuplicate(signature: string, windowMs?: number, now?: number): boolean;
|
|
297
|
+
declare function clearDedupCache(): void;
|
|
298
|
+
|
|
299
|
+
export { type Breadcrumb, type BreadcrumbType, type CapturedContext, type DeviceInfo, type GlitchgrabConfig, GlitchgrabErrorBoundary, GlitchgrabProvider, type GlitchgrabProviderProps, type GlitchgrabReport, type GlitchgrabSession, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportSeverity, type ReportType, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, clearBreadcrumbs, clearDedupCache, computeSignature, fetchGlitchgrabReports, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, shouldSkipDuplicate, useGlitchgrab, useGlitchgrabActions, useGlitchgrabReports };
|
package/dist/index.js
CHANGED
|
@@ -38,11 +38,14 @@ __export(index_exports, {
|
|
|
38
38
|
captureContext: () => captureContext,
|
|
39
39
|
captureDeviceInfo: () => captureDeviceInfo,
|
|
40
40
|
clearBreadcrumbs: () => clearBreadcrumbs,
|
|
41
|
+
clearDedupCache: () => clearDedupCache,
|
|
42
|
+
computeSignature: () => computeSignature,
|
|
41
43
|
fetchGlitchgrabReports: () => fetchGlitchgrabReports,
|
|
42
44
|
getBreadcrumbs: () => getBreadcrumbs,
|
|
43
45
|
initBreadcrumbs: () => initBreadcrumbs,
|
|
44
46
|
sanitizeUrl: () => sanitizeUrl,
|
|
45
47
|
sendReport: () => sendReport,
|
|
48
|
+
shouldSkipDuplicate: () => shouldSkipDuplicate,
|
|
46
49
|
useGlitchgrab: () => useGlitchgrab,
|
|
47
50
|
useGlitchgrabActions: () => useGlitchgrabActions,
|
|
48
51
|
useGlitchgrabReports: () => useGlitchgrabReports
|
|
@@ -313,6 +316,73 @@ async function sendReport(payload, baseUrl) {
|
|
|
313
316
|
}
|
|
314
317
|
}
|
|
315
318
|
|
|
319
|
+
// src/dedup.ts
|
|
320
|
+
var DEFAULT_WINDOW_MS = 5 * 60 * 1e3;
|
|
321
|
+
var MAX_ENTRIES = 100;
|
|
322
|
+
var seen = /* @__PURE__ */ new Map();
|
|
323
|
+
function hashString(input) {
|
|
324
|
+
let h1 = 3735928559 ^ 0;
|
|
325
|
+
let h2 = 1103547991 ^ 0;
|
|
326
|
+
for (let i = 0; i < input.length; i++) {
|
|
327
|
+
const ch = input.charCodeAt(i);
|
|
328
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
329
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
330
|
+
}
|
|
331
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
|
|
332
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
333
|
+
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
|
|
334
|
+
}
|
|
335
|
+
function topStackFrame(stack) {
|
|
336
|
+
if (!stack) return "";
|
|
337
|
+
const lines = stack.split("\n");
|
|
338
|
+
for (const line of lines) {
|
|
339
|
+
const t = line.trim();
|
|
340
|
+
if (t.startsWith("at ") || t.includes("@")) {
|
|
341
|
+
return t;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return "";
|
|
345
|
+
}
|
|
346
|
+
function stripUrlQuery(url) {
|
|
347
|
+
if (!url) return "";
|
|
348
|
+
try {
|
|
349
|
+
const u = new URL(url);
|
|
350
|
+
return `${u.origin}${u.pathname}`;
|
|
351
|
+
} catch (e) {
|
|
352
|
+
const q = url.indexOf("?");
|
|
353
|
+
return q === -1 ? url : url.slice(0, q);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function computeSignature(params) {
|
|
357
|
+
var _a, _b;
|
|
358
|
+
const msg = (_b = (_a = params.errorMessage) == null ? void 0 : _a.trim()) != null ? _b : "";
|
|
359
|
+
const page = stripUrlQuery(params.pageUrl);
|
|
360
|
+
const frame = topStackFrame(params.errorStack);
|
|
361
|
+
return hashString(`${msg}|${page}|${frame}`);
|
|
362
|
+
}
|
|
363
|
+
function shouldSkipDuplicate(signature, windowMs = DEFAULT_WINDOW_MS, now = Date.now()) {
|
|
364
|
+
const last = seen.get(signature);
|
|
365
|
+
if (last !== void 0 && now - last < windowMs) {
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
seen.set(signature, now);
|
|
369
|
+
if (seen.size > MAX_ENTRIES) {
|
|
370
|
+
const cutoff = now - windowMs;
|
|
371
|
+
for (const [sig, ts] of seen) {
|
|
372
|
+
if (ts < cutoff) seen.delete(sig);
|
|
373
|
+
}
|
|
374
|
+
if (seen.size > MAX_ENTRIES) {
|
|
375
|
+
const excess = seen.size - MAX_ENTRIES;
|
|
376
|
+
const keys = Array.from(seen.keys()).slice(0, excess);
|
|
377
|
+
for (const k of keys) seen.delete(k);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
function clearDedupCache() {
|
|
383
|
+
seen.clear();
|
|
384
|
+
}
|
|
385
|
+
|
|
316
386
|
// src/error-boundary.tsx
|
|
317
387
|
var GlitchgrabErrorBoundary = class extends React.Component {
|
|
318
388
|
constructor(props) {
|
|
@@ -326,6 +396,15 @@ var GlitchgrabErrorBoundary = class extends React.Component {
|
|
|
326
396
|
var _a, _b;
|
|
327
397
|
try {
|
|
328
398
|
const context = captureContext(this.props.visitedPages);
|
|
399
|
+
const sig = computeSignature({
|
|
400
|
+
errorMessage: error.message,
|
|
401
|
+
pageUrl: context.url,
|
|
402
|
+
errorStack: error.stack
|
|
403
|
+
});
|
|
404
|
+
if (shouldSkipDuplicate(sig)) {
|
|
405
|
+
if (this.props.onError) this.props.onError(error);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
329
408
|
const payload = {
|
|
330
409
|
token: this.props.token,
|
|
331
410
|
source: "SDK_AUTO",
|
|
@@ -593,6 +672,30 @@ function ReportDialog({
|
|
|
593
672
|
document.addEventListener("keydown", handleEsc);
|
|
594
673
|
return () => document.removeEventListener("keydown", handleEsc);
|
|
595
674
|
}, [isOpen, previewOpen]);
|
|
675
|
+
(0, import_react.useEffect)(() => {
|
|
676
|
+
if (!isOpen) return;
|
|
677
|
+
const handlePaste = (e) => {
|
|
678
|
+
var _a;
|
|
679
|
+
try {
|
|
680
|
+
const items = (_a = e.clipboardData) == null ? void 0 : _a.items;
|
|
681
|
+
if (!items) return;
|
|
682
|
+
for (let i = 0; i < items.length; i++) {
|
|
683
|
+
if (items[i].type.startsWith("image/")) {
|
|
684
|
+
const file = items[i].getAsFile();
|
|
685
|
+
if (!file) continue;
|
|
686
|
+
const reader = new FileReader();
|
|
687
|
+
reader.onload = () => setScreenshot(reader.result);
|
|
688
|
+
reader.readAsDataURL(file);
|
|
689
|
+
e.preventDefault();
|
|
690
|
+
break;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
} catch (e2) {
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
window.addEventListener("paste", handlePaste);
|
|
697
|
+
return () => window.removeEventListener("paste", handlePaste);
|
|
698
|
+
}, [isOpen]);
|
|
596
699
|
const handleClose = () => {
|
|
597
700
|
setIsOpen(false);
|
|
598
701
|
setStep(1);
|
|
@@ -1002,7 +1105,7 @@ function ReportDialog({
|
|
|
1002
1105
|
background: "none",
|
|
1003
1106
|
cursor: "pointer"
|
|
1004
1107
|
},
|
|
1005
|
-
children: "Upload
|
|
1108
|
+
children: "Upload or paste (\u2318V)"
|
|
1006
1109
|
}
|
|
1007
1110
|
),
|
|
1008
1111
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1257,25 +1360,31 @@ function GlitchgrabProviderInner({
|
|
|
1257
1360
|
if (typeof window === "undefined") return;
|
|
1258
1361
|
if (process.env.NODE_ENV === "development") return;
|
|
1259
1362
|
const handleError = (event) => {
|
|
1260
|
-
var _a, _b, _c, _d, _e;
|
|
1363
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1261
1364
|
try {
|
|
1262
1365
|
const context = captureContext(visitedPagesRef.current);
|
|
1366
|
+
const sig = computeSignature({
|
|
1367
|
+
errorMessage: event.message,
|
|
1368
|
+
pageUrl: context.url,
|
|
1369
|
+
errorStack: (_a = event.error) == null ? void 0 : _a.stack
|
|
1370
|
+
});
|
|
1371
|
+
if (shouldSkipDuplicate(sig)) return;
|
|
1263
1372
|
const payload = {
|
|
1264
1373
|
token,
|
|
1265
1374
|
source: "SDK_AUTO",
|
|
1266
1375
|
type: "BUG",
|
|
1267
1376
|
errorMessage: event.message,
|
|
1268
|
-
errorStack: (
|
|
1377
|
+
errorStack: (_b = event.error) == null ? void 0 : _b.stack,
|
|
1269
1378
|
pageUrl: context.url,
|
|
1270
1379
|
userAgent: context.userAgent,
|
|
1271
1380
|
breadcrumbs: context.breadcrumbs,
|
|
1272
|
-
deviceInfo: (
|
|
1381
|
+
deviceInfo: (_c = context.deviceInfo) != null ? _c : void 0,
|
|
1273
1382
|
metadata: {
|
|
1274
1383
|
timestamp: context.timestamp,
|
|
1275
1384
|
visitedPages: JSON.stringify(context.visitedPages),
|
|
1276
|
-
filename: (
|
|
1277
|
-
lineno: String((
|
|
1278
|
-
colno: String((
|
|
1385
|
+
filename: (_d = event.filename) != null ? _d : "",
|
|
1386
|
+
lineno: String((_e = event.lineno) != null ? _e : ""),
|
|
1387
|
+
colno: String((_f = event.colno) != null ? _f : ""),
|
|
1279
1388
|
...(session == null ? void 0 : session.userId) ? { sessionUserId: session.userId } : {},
|
|
1280
1389
|
...(session == null ? void 0 : session.name) ? { sessionUserName: String(session.name) } : {},
|
|
1281
1390
|
...(session == null ? void 0 : session.email) ? { sessionUserEmail: String(session.email) } : {}
|
|
@@ -1293,12 +1402,20 @@ function GlitchgrabProviderInner({
|
|
|
1293
1402
|
try {
|
|
1294
1403
|
const context = captureContext(visitedPagesRef.current);
|
|
1295
1404
|
const reason = event.reason;
|
|
1405
|
+
const errMsg = reason instanceof Error ? reason.message : String(reason);
|
|
1406
|
+
const errStack = reason instanceof Error ? reason.stack : void 0;
|
|
1407
|
+
const sig = computeSignature({
|
|
1408
|
+
errorMessage: errMsg,
|
|
1409
|
+
pageUrl: context.url,
|
|
1410
|
+
errorStack: errStack
|
|
1411
|
+
});
|
|
1412
|
+
if (shouldSkipDuplicate(sig)) return;
|
|
1296
1413
|
const payload = {
|
|
1297
1414
|
token,
|
|
1298
1415
|
source: "SDK_AUTO",
|
|
1299
1416
|
type: "BUG",
|
|
1300
|
-
errorMessage:
|
|
1301
|
-
errorStack:
|
|
1417
|
+
errorMessage: errMsg,
|
|
1418
|
+
errorStack: errStack,
|
|
1302
1419
|
pageUrl: context.url,
|
|
1303
1420
|
userAgent: context.userAgent,
|
|
1304
1421
|
breadcrumbs: context.breadcrumbs,
|
|
@@ -1376,6 +1493,20 @@ function GlitchgrabProviderInner({
|
|
|
1376
1493
|
window.dispatchEvent(new CustomEvent("glitchgrab:open-report", { detail: options }));
|
|
1377
1494
|
}
|
|
1378
1495
|
}, []);
|
|
1496
|
+
(0, import_react2.useEffect)(() => {
|
|
1497
|
+
try {
|
|
1498
|
+
if (typeof window === "undefined") return;
|
|
1499
|
+
const handleKeyDown = (e) => {
|
|
1500
|
+
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "g") {
|
|
1501
|
+
e.preventDefault();
|
|
1502
|
+
openReportDialog();
|
|
1503
|
+
}
|
|
1504
|
+
};
|
|
1505
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
1506
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1507
|
+
} catch (e) {
|
|
1508
|
+
}
|
|
1509
|
+
}, [openReportDialog]);
|
|
1379
1510
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1380
1511
|
GlitchgrabContext.Provider,
|
|
1381
1512
|
{
|
|
@@ -1623,11 +1754,14 @@ function useGlitchgrabActions({
|
|
|
1623
1754
|
captureContext,
|
|
1624
1755
|
captureDeviceInfo,
|
|
1625
1756
|
clearBreadcrumbs,
|
|
1757
|
+
clearDedupCache,
|
|
1758
|
+
computeSignature,
|
|
1626
1759
|
fetchGlitchgrabReports,
|
|
1627
1760
|
getBreadcrumbs,
|
|
1628
1761
|
initBreadcrumbs,
|
|
1629
1762
|
sanitizeUrl,
|
|
1630
1763
|
sendReport,
|
|
1764
|
+
shouldSkipDuplicate,
|
|
1631
1765
|
useGlitchgrab,
|
|
1632
1766
|
useGlitchgrabActions,
|
|
1633
1767
|
useGlitchgrabReports
|