glitchgrab 1.20.1 → 1.22.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.js CHANGED
@@ -137,7 +137,10 @@ function interceptFetch() {
137
137
  const method = (_a = init == null ? void 0 : init.method) != null ? _a : "GET";
138
138
  const start = Date.now();
139
139
  try {
140
- const response = await origFetch.apply(window, [input, init]);
140
+ const response = await origFetch(
141
+ input,
142
+ init
143
+ );
141
144
  addBreadcrumb("api", `${method} ${url.slice(0, 100)} \u2192 ${response.status}`, {
142
145
  method,
143
146
  status: String(response.status),
@@ -269,7 +272,7 @@ function captureContext(visitedPages) {
269
272
  };
270
273
  }
271
274
  }
272
- var DEFAULT_BASE_URL = "https://www.glitchgrab.dev";
275
+ var DEFAULT_BASE_URL = "https://glitchgrab.dev";
273
276
  var MAX_RETRIES = 3;
274
277
  var RETRY_BASE_MS = 500;
275
278
  async function sendReport(payload, baseUrl) {
@@ -616,6 +619,7 @@ function ReportDialog({
616
619
  showSeverity = true
617
620
  }) {
618
621
  const [isEnhancing, setIsEnhancing] = (0, import_react.useState)(false);
622
+ const [screenshotDragOver, setScreenshotDragOver] = (0, import_react.useState)(false);
619
623
  const [mounted, setMounted] = (0, import_react.useState)(false);
620
624
  (0, import_react.useEffect)(() => {
621
625
  setMounted(true);
@@ -1034,6 +1038,144 @@ function ReportDialog({
1034
1038
  }
1035
1039
  )
1036
1040
  ] }),
1041
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: "10px" }, children: [
1042
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "12px", color: t.textMuted, marginBottom: "6px", display: "block", fontWeight: 500 }, children: "Screenshot" }),
1043
+ screenshot ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1044
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative" }, children: [
1045
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1046
+ "img",
1047
+ {
1048
+ src: screenshot,
1049
+ alt: "Page screenshot",
1050
+ onClick: () => setPreviewOpen(true),
1051
+ style: {
1052
+ width: "100%",
1053
+ borderRadius: "6px",
1054
+ border: `1px solid ${t.border}`,
1055
+ maxHeight: "64px",
1056
+ objectFit: "cover",
1057
+ objectPosition: "top",
1058
+ cursor: "zoom-in",
1059
+ display: "block"
1060
+ }
1061
+ }
1062
+ ),
1063
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
1064
+ position: "absolute",
1065
+ bottom: "5px",
1066
+ left: "6px",
1067
+ background: "rgba(0,0,0,0.55)",
1068
+ color: "#fff",
1069
+ fontSize: "10px",
1070
+ padding: "1px 5px",
1071
+ borderRadius: "3px",
1072
+ pointerEvents: "none"
1073
+ }, children: "click to preview" })
1074
+ ] }),
1075
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "6px", marginTop: "6px" }, children: [
1076
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1077
+ "button",
1078
+ {
1079
+ type: "button",
1080
+ onClick: () => setScreenshot(null),
1081
+ style: {
1082
+ flex: 1,
1083
+ padding: "6px 0",
1084
+ borderRadius: "6px",
1085
+ border: `1px solid ${t.inputBorder}`,
1086
+ background: "transparent",
1087
+ color: "#ef4444",
1088
+ fontSize: "12px",
1089
+ fontWeight: 500,
1090
+ cursor: "pointer",
1091
+ fontFamily: "inherit",
1092
+ display: "flex",
1093
+ alignItems: "center",
1094
+ justifyContent: "center",
1095
+ gap: "4px"
1096
+ },
1097
+ children: [
1098
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "11", height: "11", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M1 1L9 9M9 1L1 9", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }),
1099
+ "Remove"
1100
+ ]
1101
+ }
1102
+ ),
1103
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1104
+ "button",
1105
+ {
1106
+ type: "button",
1107
+ onClick: () => {
1108
+ var _a;
1109
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
1110
+ },
1111
+ style: {
1112
+ flex: 1,
1113
+ padding: "6px 0",
1114
+ borderRadius: "6px",
1115
+ border: `1px solid ${t.inputBorder}`,
1116
+ background: "transparent",
1117
+ color: t.textMuted,
1118
+ fontSize: "12px",
1119
+ fontWeight: 500,
1120
+ cursor: "pointer",
1121
+ fontFamily: "inherit",
1122
+ display: "flex",
1123
+ alignItems: "center",
1124
+ justifyContent: "center",
1125
+ gap: "4px"
1126
+ },
1127
+ children: [
1128
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
1129
+ "Replace"
1130
+ ]
1131
+ }
1132
+ )
1133
+ ] })
1134
+ ] }) : (
1135
+ /* Drop zone */
1136
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1137
+ "div",
1138
+ {
1139
+ onClick: () => {
1140
+ var _a;
1141
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
1142
+ },
1143
+ onDrop: (e) => {
1144
+ e.preventDefault();
1145
+ setScreenshotDragOver(false);
1146
+ const file = Array.from(e.dataTransfer.files).find((f) => f.type.startsWith("image/"));
1147
+ if (!file) return;
1148
+ const reader = new FileReader();
1149
+ reader.onload = () => setScreenshot(reader.result);
1150
+ reader.readAsDataURL(file);
1151
+ },
1152
+ onDragOver: (e) => {
1153
+ e.preventDefault();
1154
+ setScreenshotDragOver(true);
1155
+ },
1156
+ onDragLeave: () => setScreenshotDragOver(false),
1157
+ style: {
1158
+ border: `1.5px dashed ${screenshotDragOver ? t.accent : t.inputBorder}`,
1159
+ borderRadius: "8px",
1160
+ padding: "18px 12px",
1161
+ textAlign: "center",
1162
+ cursor: "pointer",
1163
+ background: screenshotDragOver ? isDark ? "rgba(34,211,238,0.06)" : "rgba(8,145,178,0.04)" : "transparent",
1164
+ transition: "border-color 0.15s ease, background 0.15s ease"
1165
+ },
1166
+ children: [
1167
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", style: { margin: "0 auto 6px", display: "block", opacity: 0.45 }, children: [
1168
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", stroke: t.textMuted, strokeWidth: "1.5" }),
1169
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5", stroke: t.textMuted, strokeWidth: "1.5" }),
1170
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 15l-5-5L5 21", stroke: t.textMuted, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
1171
+ ] }),
1172
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: 0, fontSize: "12px", fontWeight: 600, color: t.text }, children: screenshotDragOver ? "Drop to attach" : "Add a screenshot" }),
1173
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: "3px 0 0", fontSize: "11px", color: t.textMuted }, children: "Drag & drop \xB7 Paste \u2318V / Ctrl+V \xB7 Click to browse" })
1174
+ ]
1175
+ }
1176
+ )
1177
+ )
1178
+ ] }),
1037
1179
  showSeverity && reportType === "BUG" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: "10px" }, children: [
1038
1180
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "12px", color: t.textMuted, marginBottom: "6px", display: "block" }, children: "Severity" }),
1039
1181
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: "6px" }, children: ["low", "medium", "high"].map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1135,91 +1277,23 @@ function ReportDialog({
1135
1277
  overflow: "hidden",
1136
1278
  lineHeight: "1.4"
1137
1279
  }, children: description.length > 200 ? description.slice(0, 200) + "..." : description }),
1138
- screenshot && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: "10px", position: "relative" }, children: [
1139
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1140
- "img",
1141
- {
1142
- src: screenshot,
1143
- alt: "Page screenshot",
1144
- onClick: () => setPreviewOpen(true),
1145
- style: {
1146
- width: "100%",
1147
- borderRadius: "6px",
1148
- border: `1px solid ${t.border}`,
1149
- maxHeight: "80px",
1150
- objectFit: "cover",
1151
- objectPosition: "top",
1152
- cursor: "pointer"
1153
- }
1154
- }
1155
- ),
1156
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1157
- "button",
1158
- {
1159
- type: "button",
1160
- onClick: () => setScreenshot(null),
1161
- style: {
1162
- position: "absolute",
1163
- top: "4px",
1164
- right: "4px",
1165
- background: "rgba(0,0,0,0.6)",
1166
- border: "none",
1167
- borderRadius: "50%",
1168
- width: "20px",
1169
- height: "20px",
1170
- cursor: "pointer",
1171
- display: "flex",
1172
- alignItems: "center",
1173
- justifyContent: "center"
1174
- },
1175
- "aria-label": "Remove screenshot",
1176
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M1 1L9 9M9 1L1 9", stroke: "#fff", strokeWidth: "1.5", strokeLinecap: "round" }) })
1177
- }
1178
- )
1179
- ] }),
1180
- !screenshot && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "6px", marginBottom: "10px" }, children: [
1181
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1182
- "button",
1183
- {
1184
- type: "button",
1185
- onClick: () => {
1186
- var _a;
1187
- return (_a = fileInputRef.current) == null ? void 0 : _a.click();
1188
- },
1189
- style: {
1190
- flex: 1,
1191
- padding: "8px",
1192
- borderRadius: "6px",
1193
- border: `1px dashed ${t.inputBorder}`,
1194
- textAlign: "center",
1195
- fontSize: "11px",
1196
- color: t.textMuted,
1197
- background: "none",
1198
- cursor: "pointer"
1199
- },
1200
- children: "Upload or paste (\u2318V)"
1201
- }
1202
- ),
1203
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1204
- "button",
1205
- {
1206
- type: "button",
1207
- onClick: retakeScreenshot,
1208
- style: {
1209
- flex: 1,
1210
- padding: "8px",
1211
- borderRadius: "6px",
1212
- border: `1px dashed ${t.inputBorder}`,
1213
- textAlign: "center",
1214
- fontSize: "11px",
1215
- color: t.textMuted,
1216
- background: "none",
1217
- cursor: "pointer"
1218
- },
1219
- children: "Retake screenshot"
1280
+ screenshot && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginBottom: "10px", position: "relative" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1281
+ "img",
1282
+ {
1283
+ src: screenshot,
1284
+ alt: "Page screenshot",
1285
+ onClick: () => setPreviewOpen(true),
1286
+ style: {
1287
+ width: "100%",
1288
+ borderRadius: "6px",
1289
+ border: `1px solid ${t.border}`,
1290
+ maxHeight: "80px",
1291
+ objectFit: "cover",
1292
+ objectPosition: "top",
1293
+ cursor: "pointer"
1220
1294
  }
1221
- )
1222
- ] }),
1295
+ }
1296
+ ) }),
1223
1297
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1224
1298
  "button",
1225
1299
  {
@@ -1382,7 +1456,7 @@ function getTypeIcon(type, color, size = 24) {
1382
1456
 
1383
1457
  // src/provider.tsx
1384
1458
  var import_jsx_runtime2 = require("react/jsx-runtime");
1385
- var DEFAULT_BASE_URL2 = "https://www.glitchgrab.dev";
1459
+ var DEFAULT_BASE_URL2 = "https://glitchgrab.dev";
1386
1460
  var GlitchgrabContext = (0, import_react2.createContext)(null);
1387
1461
  function useGlitchgrab() {
1388
1462
  const ctx = (0, import_react2.useContext)(GlitchgrabContext);
@@ -1451,18 +1525,25 @@ function GlitchgrabProviderInner({
1451
1525
  try {
1452
1526
  if (typeof window === "undefined") return;
1453
1527
  if (process.env.NODE_ENV === "development") return;
1528
+ const EXTENSION_ORIGIN_RE = /\b(?:chrome|safari|moz)-extension:\/\//;
1454
1529
  const handleError = (event) => {
1455
- var _a, _b, _c, _d, _e, _f;
1530
+ var _a, _b, _c, _d, _e, _f, _g;
1456
1531
  try {
1457
1532
  const isOpaqueCrossOrigin = event.message === "Script error." || event.message === "Script error" || !event.error && !event.filename;
1458
1533
  if (isOpaqueCrossOrigin) {
1459
1534
  return;
1460
1535
  }
1536
+ if (event.message === "ResizeObserver loop completed with undelivered notifications." || event.message === "ResizeObserver loop limit exceeded") {
1537
+ return;
1538
+ }
1539
+ if (event.filename && EXTENSION_ORIGIN_RE.test(event.filename) || ((_a = event.error) == null ? void 0 : _a.stack) && EXTENSION_ORIGIN_RE.test(event.error.stack)) {
1540
+ return;
1541
+ }
1461
1542
  const context = captureContext(visitedPagesRef.current);
1462
1543
  const sig = computeSignature({
1463
1544
  errorMessage: event.message,
1464
1545
  pageUrl: context.url,
1465
- errorStack: (_a = event.error) == null ? void 0 : _a.stack
1546
+ errorStack: (_b = event.error) == null ? void 0 : _b.stack
1466
1547
  });
1467
1548
  if (shouldSkipDuplicate(sig)) return;
1468
1549
  const payload = {
@@ -1470,17 +1551,17 @@ function GlitchgrabProviderInner({
1470
1551
  source: "SDK_AUTO",
1471
1552
  type: "BUG",
1472
1553
  errorMessage: event.message,
1473
- errorStack: (_b = event.error) == null ? void 0 : _b.stack,
1554
+ errorStack: (_c = event.error) == null ? void 0 : _c.stack,
1474
1555
  pageUrl: context.url,
1475
1556
  userAgent: context.userAgent,
1476
1557
  breadcrumbs: context.breadcrumbs,
1477
- deviceInfo: (_c = context.deviceInfo) != null ? _c : void 0,
1558
+ deviceInfo: (_d = context.deviceInfo) != null ? _d : void 0,
1478
1559
  metadata: {
1479
1560
  timestamp: context.timestamp,
1480
1561
  visitedPages: JSON.stringify(context.visitedPages),
1481
- filename: (_d = event.filename) != null ? _d : "",
1482
- lineno: String((_e = event.lineno) != null ? _e : ""),
1483
- colno: String((_f = event.colno) != null ? _f : ""),
1562
+ filename: (_e = event.filename) != null ? _e : "",
1563
+ lineno: String((_f = event.lineno) != null ? _f : ""),
1564
+ colno: String((_g = event.colno) != null ? _g : ""),
1484
1565
  ...(session == null ? void 0 : session.userId) ? { sessionUserId: session.userId } : {},
1485
1566
  ...(session == null ? void 0 : session.name) ? { sessionUserName: String(session.name) } : {},
1486
1567
  ...(session == null ? void 0 : session.email) ? { sessionUserEmail: String(session.email) } : {},
@@ -1504,6 +1585,7 @@ function GlitchgrabProviderInner({
1504
1585
  return;
1505
1586
  }
1506
1587
  const errStack = reason instanceof Error ? reason.stack : void 0;
1588
+ if (errStack && EXTENSION_ORIGIN_RE.test(errStack)) return;
1507
1589
  const sig = computeSignature({
1508
1590
  errorMessage: errMsg,
1509
1591
  pageUrl: context.url,
@@ -1755,7 +1837,7 @@ function ReportButton({
1755
1837
 
1756
1838
  // src/use-reports.ts
1757
1839
  var import_react4 = require("react");
1758
- var BASE_URL = "https://www.glitchgrab.dev";
1840
+ var BASE_URL = "https://glitchgrab.dev";
1759
1841
  function useGlitchgrabReports({
1760
1842
  token,
1761
1843
  userId,