glitchgrab 1.15.0 → 1.16.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 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
- 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, fetchGlitchgrabReports, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab, useGlitchgrabActions, useGlitchgrabReports };
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
- 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, fetchGlitchgrabReports, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab, useGlitchgrabActions, useGlitchgrabReports };
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",
@@ -1257,25 +1336,31 @@ function GlitchgrabProviderInner({
1257
1336
  if (typeof window === "undefined") return;
1258
1337
  if (process.env.NODE_ENV === "development") return;
1259
1338
  const handleError = (event) => {
1260
- var _a, _b, _c, _d, _e;
1339
+ var _a, _b, _c, _d, _e, _f;
1261
1340
  try {
1262
1341
  const context = captureContext(visitedPagesRef.current);
1342
+ const sig = computeSignature({
1343
+ errorMessage: event.message,
1344
+ pageUrl: context.url,
1345
+ errorStack: (_a = event.error) == null ? void 0 : _a.stack
1346
+ });
1347
+ if (shouldSkipDuplicate(sig)) return;
1263
1348
  const payload = {
1264
1349
  token,
1265
1350
  source: "SDK_AUTO",
1266
1351
  type: "BUG",
1267
1352
  errorMessage: event.message,
1268
- errorStack: (_a = event.error) == null ? void 0 : _a.stack,
1353
+ errorStack: (_b = event.error) == null ? void 0 : _b.stack,
1269
1354
  pageUrl: context.url,
1270
1355
  userAgent: context.userAgent,
1271
1356
  breadcrumbs: context.breadcrumbs,
1272
- deviceInfo: (_b = context.deviceInfo) != null ? _b : void 0,
1357
+ deviceInfo: (_c = context.deviceInfo) != null ? _c : void 0,
1273
1358
  metadata: {
1274
1359
  timestamp: context.timestamp,
1275
1360
  visitedPages: JSON.stringify(context.visitedPages),
1276
- filename: (_c = event.filename) != null ? _c : "",
1277
- lineno: String((_d = event.lineno) != null ? _d : ""),
1278
- colno: String((_e = event.colno) != null ? _e : ""),
1361
+ filename: (_d = event.filename) != null ? _d : "",
1362
+ lineno: String((_e = event.lineno) != null ? _e : ""),
1363
+ colno: String((_f = event.colno) != null ? _f : ""),
1279
1364
  ...(session == null ? void 0 : session.userId) ? { sessionUserId: session.userId } : {},
1280
1365
  ...(session == null ? void 0 : session.name) ? { sessionUserName: String(session.name) } : {},
1281
1366
  ...(session == null ? void 0 : session.email) ? { sessionUserEmail: String(session.email) } : {}
@@ -1293,12 +1378,20 @@ function GlitchgrabProviderInner({
1293
1378
  try {
1294
1379
  const context = captureContext(visitedPagesRef.current);
1295
1380
  const reason = event.reason;
1381
+ const errMsg = reason instanceof Error ? reason.message : String(reason);
1382
+ const errStack = reason instanceof Error ? reason.stack : void 0;
1383
+ const sig = computeSignature({
1384
+ errorMessage: errMsg,
1385
+ pageUrl: context.url,
1386
+ errorStack: errStack
1387
+ });
1388
+ if (shouldSkipDuplicate(sig)) return;
1296
1389
  const payload = {
1297
1390
  token,
1298
1391
  source: "SDK_AUTO",
1299
1392
  type: "BUG",
1300
- errorMessage: reason instanceof Error ? reason.message : String(reason),
1301
- errorStack: reason instanceof Error ? reason.stack : void 0,
1393
+ errorMessage: errMsg,
1394
+ errorStack: errStack,
1302
1395
  pageUrl: context.url,
1303
1396
  userAgent: context.userAgent,
1304
1397
  breadcrumbs: context.breadcrumbs,
@@ -1623,11 +1716,14 @@ function useGlitchgrabActions({
1623
1716
  captureContext,
1624
1717
  captureDeviceInfo,
1625
1718
  clearBreadcrumbs,
1719
+ clearDedupCache,
1720
+ computeSignature,
1626
1721
  fetchGlitchgrabReports,
1627
1722
  getBreadcrumbs,
1628
1723
  initBreadcrumbs,
1629
1724
  sanitizeUrl,
1630
1725
  sendReport,
1726
+ shouldSkipDuplicate,
1631
1727
  useGlitchgrab,
1632
1728
  useGlitchgrabActions,
1633
1729
  useGlitchgrabReports