glitchgrab 1.8.0 → 1.9.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 +22 -1
- package/dist/index.d.mts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +49 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -232,7 +232,28 @@ curl -H "Authorization: Bearer gg_your_token" \
|
|
|
232
232
|
|
|
233
233
|
## Managing Issues (Approve / Reject / Close)
|
|
234
234
|
|
|
235
|
-
|
|
235
|
+
### React hook
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
import { useGlitchgrabActions } from "glitchgrab";
|
|
239
|
+
|
|
240
|
+
function ReportActions({ reportId }: { reportId: string }) {
|
|
241
|
+
const { approve, reject, close, isPending, error } = useGlitchgrabActions({
|
|
242
|
+
token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,
|
|
243
|
+
onSuccess: () => refetch(), // refresh your reports list
|
|
244
|
+
onError: (err) => alert(err.message),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<div>
|
|
249
|
+
<button onClick={() => approve(reportId)} disabled={isPending}>Approve</button>
|
|
250
|
+
<button onClick={() => reject(reportId)} disabled={isPending}>Reject</button>
|
|
251
|
+
<button onClick={() => close(reportId)} disabled={isPending}>Close</button>
|
|
252
|
+
{error && <p>{error}</p>}
|
|
253
|
+
</div>
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
```
|
|
236
257
|
|
|
237
258
|
### Dashboard
|
|
238
259
|
|
package/dist/index.d.mts
CHANGED
|
@@ -213,6 +213,35 @@ declare function fetchGlitchgrabReports({ token, userId, limit, }: {
|
|
|
213
213
|
userId: string;
|
|
214
214
|
limit?: number;
|
|
215
215
|
}): Promise<GlitchgrabReport[]>;
|
|
216
|
+
/**
|
|
217
|
+
* Hook to manage report actions with loading/error states.
|
|
218
|
+
*
|
|
219
|
+
* ```tsx
|
|
220
|
+
* const { approve, reject, close, isPending, error } = useGlitchgrabActions({
|
|
221
|
+
* token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,
|
|
222
|
+
* onSuccess: () => refetch(),
|
|
223
|
+
* onError: (err) => toast.error(err.message),
|
|
224
|
+
* });
|
|
225
|
+
*
|
|
226
|
+
* <button onClick={() => approve(reportId)} disabled={isPending}>
|
|
227
|
+
* {isPending ? "..." : "Approve"}
|
|
228
|
+
* </button>
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
declare function useGlitchgrabActions({ token, onSuccess, onError, }: {
|
|
232
|
+
token: string;
|
|
233
|
+
onSuccess?: () => void;
|
|
234
|
+
onError?: (error: Error) => void;
|
|
235
|
+
}): {
|
|
236
|
+
approve: (reportId: string) => Promise<void>;
|
|
237
|
+
reject: (reportId: string) => Promise<void>;
|
|
238
|
+
close: (reportId: string) => Promise<void>;
|
|
239
|
+
reopen: (reportId: string) => Promise<void>;
|
|
240
|
+
label: (reportId: string, label: string) => Promise<void>;
|
|
241
|
+
unlabel: (reportId: string, label: string) => Promise<void>;
|
|
242
|
+
isPending: boolean;
|
|
243
|
+
error: string | null;
|
|
244
|
+
};
|
|
216
245
|
|
|
217
246
|
declare function initBreadcrumbs(max?: number): void;
|
|
218
247
|
declare function addBreadcrumb(type: BreadcrumbType, message: string, data?: Record<string, string>): void;
|
|
@@ -228,4 +257,4 @@ declare function captureContext(visitedPages: string[]): CapturedContext;
|
|
|
228
257
|
*/
|
|
229
258
|
declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<ReportResult | null>;
|
|
230
259
|
|
|
231
|
-
export { type Breadcrumb, type BreadcrumbType, type CapturedContext, type DeviceInfo, type GlitchgrabConfig, GlitchgrabErrorBoundary, GlitchgrabProvider, type GlitchgrabProviderProps, type GlitchgrabSession, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportType, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, clearBreadcrumbs, fetchGlitchgrabReports, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab, useGlitchgrabReports };
|
|
260
|
+
export { type Breadcrumb, type BreadcrumbType, type CapturedContext, type DeviceInfo, type GlitchgrabConfig, GlitchgrabErrorBoundary, GlitchgrabProvider, type GlitchgrabProviderProps, type GlitchgrabSession, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportType, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, clearBreadcrumbs, fetchGlitchgrabReports, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab, useGlitchgrabActions, useGlitchgrabReports };
|
package/dist/index.d.ts
CHANGED
|
@@ -213,6 +213,35 @@ declare function fetchGlitchgrabReports({ token, userId, limit, }: {
|
|
|
213
213
|
userId: string;
|
|
214
214
|
limit?: number;
|
|
215
215
|
}): Promise<GlitchgrabReport[]>;
|
|
216
|
+
/**
|
|
217
|
+
* Hook to manage report actions with loading/error states.
|
|
218
|
+
*
|
|
219
|
+
* ```tsx
|
|
220
|
+
* const { approve, reject, close, isPending, error } = useGlitchgrabActions({
|
|
221
|
+
* token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,
|
|
222
|
+
* onSuccess: () => refetch(),
|
|
223
|
+
* onError: (err) => toast.error(err.message),
|
|
224
|
+
* });
|
|
225
|
+
*
|
|
226
|
+
* <button onClick={() => approve(reportId)} disabled={isPending}>
|
|
227
|
+
* {isPending ? "..." : "Approve"}
|
|
228
|
+
* </button>
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
declare function useGlitchgrabActions({ token, onSuccess, onError, }: {
|
|
232
|
+
token: string;
|
|
233
|
+
onSuccess?: () => void;
|
|
234
|
+
onError?: (error: Error) => void;
|
|
235
|
+
}): {
|
|
236
|
+
approve: (reportId: string) => Promise<void>;
|
|
237
|
+
reject: (reportId: string) => Promise<void>;
|
|
238
|
+
close: (reportId: string) => Promise<void>;
|
|
239
|
+
reopen: (reportId: string) => Promise<void>;
|
|
240
|
+
label: (reportId: string, label: string) => Promise<void>;
|
|
241
|
+
unlabel: (reportId: string, label: string) => Promise<void>;
|
|
242
|
+
isPending: boolean;
|
|
243
|
+
error: string | null;
|
|
244
|
+
};
|
|
216
245
|
|
|
217
246
|
declare function initBreadcrumbs(max?: number): void;
|
|
218
247
|
declare function addBreadcrumb(type: BreadcrumbType, message: string, data?: Record<string, string>): void;
|
|
@@ -228,4 +257,4 @@ declare function captureContext(visitedPages: string[]): CapturedContext;
|
|
|
228
257
|
*/
|
|
229
258
|
declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<ReportResult | null>;
|
|
230
259
|
|
|
231
|
-
export { type Breadcrumb, type BreadcrumbType, type CapturedContext, type DeviceInfo, type GlitchgrabConfig, GlitchgrabErrorBoundary, GlitchgrabProvider, type GlitchgrabProviderProps, type GlitchgrabSession, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportType, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, clearBreadcrumbs, fetchGlitchgrabReports, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab, useGlitchgrabReports };
|
|
260
|
+
export { type Breadcrumb, type BreadcrumbType, type CapturedContext, type DeviceInfo, type GlitchgrabConfig, GlitchgrabErrorBoundary, GlitchgrabProvider, type GlitchgrabProviderProps, type GlitchgrabSession, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportType, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, clearBreadcrumbs, fetchGlitchgrabReports, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab, useGlitchgrabActions, useGlitchgrabReports };
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,7 @@ __export(index_exports, {
|
|
|
44
44
|
sanitizeUrl: () => sanitizeUrl,
|
|
45
45
|
sendReport: () => sendReport,
|
|
46
46
|
useGlitchgrab: () => useGlitchgrab,
|
|
47
|
+
useGlitchgrabActions: () => useGlitchgrabActions,
|
|
47
48
|
useGlitchgrabReports: () => useGlitchgrabReports
|
|
48
49
|
});
|
|
49
50
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -1226,6 +1227,54 @@ async function fetchGlitchgrabReports({
|
|
|
1226
1227
|
if (!data.success) throw new Error((_a = data.error) != null ? _a : "Failed to fetch reports");
|
|
1227
1228
|
return (_b = data.data) != null ? _b : [];
|
|
1228
1229
|
}
|
|
1230
|
+
async function reportAction(token, reportId, body) {
|
|
1231
|
+
var _a;
|
|
1232
|
+
const res = await fetch(`${BASE_URL}/api/v1/reports/${reportId}/actions`, {
|
|
1233
|
+
method: "POST",
|
|
1234
|
+
headers: {
|
|
1235
|
+
Authorization: `Bearer ${token}`,
|
|
1236
|
+
"Content-Type": "application/json"
|
|
1237
|
+
},
|
|
1238
|
+
body: JSON.stringify(body)
|
|
1239
|
+
});
|
|
1240
|
+
const data = await res.json().catch(() => ({}));
|
|
1241
|
+
if (!res.ok || !data.success) throw new Error((_a = data.error) != null ? _a : "Action failed");
|
|
1242
|
+
}
|
|
1243
|
+
function useGlitchgrabActions({
|
|
1244
|
+
token,
|
|
1245
|
+
onSuccess,
|
|
1246
|
+
onError
|
|
1247
|
+
}) {
|
|
1248
|
+
const [isPending, setIsPending] = (0, import_react3.useState)(false);
|
|
1249
|
+
const [error, setError] = (0, import_react3.useState)(null);
|
|
1250
|
+
const run = (0, import_react3.useCallback)(
|
|
1251
|
+
async (reportId, body) => {
|
|
1252
|
+
setIsPending(true);
|
|
1253
|
+
setError(null);
|
|
1254
|
+
try {
|
|
1255
|
+
await reportAction(token, reportId, body);
|
|
1256
|
+
onSuccess == null ? void 0 : onSuccess();
|
|
1257
|
+
} catch (e) {
|
|
1258
|
+
const err = e instanceof Error ? e : new Error("Action failed");
|
|
1259
|
+
setError(err.message);
|
|
1260
|
+
onError == null ? void 0 : onError(err);
|
|
1261
|
+
} finally {
|
|
1262
|
+
setIsPending(false);
|
|
1263
|
+
}
|
|
1264
|
+
},
|
|
1265
|
+
[token, onSuccess, onError]
|
|
1266
|
+
);
|
|
1267
|
+
return {
|
|
1268
|
+
approve: (reportId) => run(reportId, { action: "label", label: "approved" }),
|
|
1269
|
+
reject: (reportId) => run(reportId, { action: "label", label: "rejected" }),
|
|
1270
|
+
close: (reportId) => run(reportId, { action: "close" }),
|
|
1271
|
+
reopen: (reportId) => run(reportId, { action: "reopen" }),
|
|
1272
|
+
label: (reportId, label) => run(reportId, { action: "label", label }),
|
|
1273
|
+
unlabel: (reportId, label) => run(reportId, { action: "unlabel", label }),
|
|
1274
|
+
isPending,
|
|
1275
|
+
error
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1229
1278
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1230
1279
|
0 && (module.exports = {
|
|
1231
1280
|
GlitchgrabErrorBoundary,
|
|
@@ -1241,6 +1290,7 @@ async function fetchGlitchgrabReports({
|
|
|
1241
1290
|
sanitizeUrl,
|
|
1242
1291
|
sendReport,
|
|
1243
1292
|
useGlitchgrab,
|
|
1293
|
+
useGlitchgrabActions,
|
|
1244
1294
|
useGlitchgrabReports
|
|
1245
1295
|
});
|
|
1246
1296
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/error-boundary.tsx","../src/breadcrumbs.ts","../src/utils.ts","../src/report-button.tsx","../src/use-reports.ts"],"sourcesContent":["\"use client\";\n\n// ─── Core (required) ─────────────────────────────────────\nexport { GlitchgrabProvider, useGlitchgrab } from \"./provider\";\n\n// ─── Optional Components ─────────────────────────────────\nexport { ReportButton } from \"./report-button\";\nexport { GlitchgrabErrorBoundary } from \"./error-boundary\";\n\n// ─── Hooks ──────────────────────────────────────────────\nexport { useGlitchgrabReports, fetchGlitchgrabReports } from \"./use-reports\";\n\n// ─── Breadcrumbs ─────────────────────────────────────────\nexport {\n addBreadcrumb,\n getBreadcrumbs,\n clearBreadcrumbs,\n initBreadcrumbs,\n} from \"./breadcrumbs\";\n\n// ─── Utilities ───────────────────────────────────────────\nexport { sanitizeUrl, captureContext, captureDeviceInfo, sendReport } from \"./utils\";\n\n// ─── Types ───────────────────────────────────────────────\nexport type {\n GlitchgrabConfig,\n GlitchgrabProviderProps,\n ReportPayload,\n ReportResult,\n ReportType,\n CapturedContext,\n DeviceInfo,\n Breadcrumb,\n BreadcrumbType,\n UseGlitchgrabReturn,\n ReportButtonProps,\n GlitchgrabSession,\n} from \"./types\";\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useRef,\n useEffect,\n useCallback,\n useState,\n} from \"react\";\nimport type {\n GlitchgrabProviderProps,\n UseGlitchgrabReturn,\n ReportPayload,\n ReportResult,\n ReportType,\n} from \"./types\";\nimport { GlitchgrabErrorBoundary } from \"./error-boundary\";\nimport { sanitizeUrl, captureContext, sendReport, captureDeviceInfo } from \"./utils\";\nimport {\n initBreadcrumbs,\n addBreadcrumb as addBreadcrumbInternal,\n getBreadcrumbs,\n} from \"./breadcrumbs\";\n\nconst DEFAULT_BASE_URL = \"https://www.glitchgrab.dev\";\n\nconst GlitchgrabContext = createContext<UseGlitchgrabReturn | null>(null);\n\n/**\n * Hook to access Glitchgrab in your components.\n *\n * @example\n * ```tsx\n * const { reportBug, report, addBreadcrumb } = useGlitchgrab();\n *\n * // Report a bug\n * reportBug(\"Login button crashes on mobile\");\n *\n * // Report a feature request\n * report(\"FEATURE_REQUEST\", \"Add dark mode\");\n *\n * // Add a custom breadcrumb\n * addBreadcrumb(\"User clicked checkout\", { cartItems: \"3\" });\n * ```\n */\nexport function useGlitchgrab(): UseGlitchgrabReturn {\n const ctx = useContext(GlitchgrabContext);\n if (!ctx) {\n throw new Error(\"useGlitchgrab must be used within a GlitchgrabProvider\");\n }\n return ctx;\n}\n\nfunction GlitchgrabProviderInner({\n token,\n session,\n baseUrl,\n onError,\n onReportSent,\n breadcrumbs: enableBreadcrumbs = true,\n maxBreadcrumbs = 50,\n children,\n fallback,\n}: GlitchgrabProviderProps) {\n const visitedPagesRef = useRef<string[]>([]);\n\n // Initialize breadcrumbs\n useEffect(() => {\n if (enableBreadcrumbs) {\n initBreadcrumbs(maxBreadcrumbs);\n }\n }, [enableBreadcrumbs, maxBreadcrumbs]);\n\n // Track page visits\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n\n const trackPage = () => {\n try {\n const sanitized = sanitizeUrl(window.location.href);\n const pages = visitedPagesRef.current;\n if (pages[pages.length - 1] !== sanitized) {\n pages.push(sanitized);\n if (pages.length > 20) {\n pages.splice(0, pages.length - 20);\n }\n }\n } catch {\n // Silently fail\n }\n };\n\n trackPage();\n const handlePopState = () => trackPage();\n window.addEventListener(\"popstate\", handlePopState);\n\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPushState(...args);\n trackPage();\n };\n history.replaceState = function (...args) {\n origReplaceState(...args);\n trackPage();\n };\n\n return () => {\n window.removeEventListener(\"popstate\", handlePopState);\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n };\n } catch {\n // Never crash\n }\n }, []);\n\n // Unhandled errors and rejections — skip in development\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n if (process.env.NODE_ENV === \"development\") return;\n\n const handleError = (event: ErrorEvent) => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: event.message,\n errorStack: event.error?.stack,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n filename: event.filename ?? \"\",\n lineno: String(event.lineno ?? \"\"),\n colno: String(event.colno ?? \"\"),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && event.error) onError(event.error);\n } catch {\n // Silently fail\n }\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const reason = event.reason;\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: reason instanceof Error ? reason.message : String(reason),\n errorStack: reason instanceof Error ? reason.stack : undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n type: \"unhandledrejection\",\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && reason instanceof Error) onError(reason);\n } catch {\n // Silently fail\n }\n };\n\n window.addEventListener(\"error\", handleError);\n window.addEventListener(\"unhandledrejection\", handleRejection);\n\n return () => {\n window.removeEventListener(\"error\", handleError);\n window.removeEventListener(\"unhandledrejection\", handleRejection);\n };\n } catch {\n // Never crash\n }\n }, [token, baseUrl, onError, onReportSent]);\n\n const report = useCallback(\n async (\n type: ReportType,\n description: string,\n metadata?: Record<string, string>\n ): Promise<ReportResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_USER_REPORT\",\n type,\n description,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n ...metadata,\n },\n };\n const result = await sendReport(payload, baseUrl);\n if (result && onReportSent) onReportSent(result);\n return result;\n } catch {\n return null;\n }\n },\n [token, baseUrl, onReportSent]\n );\n\n const reportBug = useCallback(\n (description: string, metadata?: Record<string, string>) =>\n report(\"BUG\", description, metadata),\n [report]\n );\n\n const addBreadcrumb = useCallback(\n (message: string, data?: Record<string, string>) => {\n addBreadcrumbInternal(\"custom\", message, data);\n },\n []\n );\n\n return (\n <GlitchgrabContext.Provider\n value={{\n token,\n baseUrl: baseUrl ?? DEFAULT_BASE_URL,\n reportBug,\n report,\n addBreadcrumb,\n }}\n >\n <GlitchgrabErrorBoundary\n token={token}\n baseUrl={baseUrl}\n onError={onError}\n fallback={fallback}\n visitedPages={visitedPagesRef.current}\n >\n {children}\n </GlitchgrabErrorBoundary>\n </GlitchgrabContext.Provider>\n );\n}\n\nexport function GlitchgrabProvider(props: GlitchgrabProviderProps) {\n // No token = passthrough (SDK disabled)\n if (!props.token) return <>{props.children}</>;\n\n const resolvedProps = {\n ...props,\n baseUrl: props.baseUrl || DEFAULT_BASE_URL,\n };\n\n try {\n return <GlitchgrabProviderInner {...resolvedProps} />;\n } catch {\n return <>{props.children}</>;\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { ReportPayload } from \"./types\";\nimport { captureContext, sendReport } from \"./utils\";\n\ninterface ErrorBoundaryProps {\n token: string;\n baseUrl?: string;\n onError?: (error: Error) => void;\n fallback?: React.ReactNode;\n visitedPages: string[];\n children: React.ReactNode;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n}\n\nexport class GlitchgrabErrorBoundary extends React.Component<\n ErrorBoundaryProps,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): ErrorBoundaryState {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n try {\n const context = captureContext(this.props.visitedPages);\n\n const payload: ReportPayload = {\n token: this.props.token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: error.message,\n errorStack: error.stack,\n componentStack: errorInfo.componentStack ?? undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n },\n };\n\n sendReport(payload, this.props.baseUrl);\n\n if (this.props.onError) {\n this.props.onError(error);\n }\n } catch {\n // Never crash the host app\n }\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n // Re-render children — allows recovery from transient errors\n return this.props.children;\n }\n\n return this.props.children;\n }\n}\n","import type { Breadcrumb, BreadcrumbType } from \"./types\";\n\nconst MAX_DEFAULT = 50;\n\nlet breadcrumbs: Breadcrumb[] = [];\nlet maxBreadcrumbs = MAX_DEFAULT;\nlet initialized = false;\n\nexport function initBreadcrumbs(max?: number) {\n if (initialized) return;\n maxBreadcrumbs = max ?? MAX_DEFAULT;\n\n try {\n if (typeof window === \"undefined\") return;\n interceptConsole();\n interceptFetch();\n interceptNavigation();\n interceptClicks();\n initialized = true;\n } catch {\n // Never crash\n }\n}\n\nexport function addBreadcrumb(\n type: BreadcrumbType,\n message: string,\n data?: Record<string, string>\n) {\n try {\n breadcrumbs.push({\n type,\n message: message.slice(0, 200),\n timestamp: new Date().toISOString(),\n data,\n });\n if (breadcrumbs.length > maxBreadcrumbs) {\n breadcrumbs = breadcrumbs.slice(-maxBreadcrumbs);\n }\n } catch {\n // Never crash\n }\n}\n\nexport function getBreadcrumbs(): Breadcrumb[] {\n return [...breadcrumbs];\n}\n\nexport function clearBreadcrumbs() {\n breadcrumbs = [];\n}\n\n// ─── Console Interception ────────────────────────────────\n\nfunction interceptConsole() {\n const origLog = console.log;\n const origWarn = console.warn;\n const origError = console.error;\n\n console.log = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[log] ${argsToString(args)}`);\n origLog.apply(console, args);\n };\n\n console.warn = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[warn] ${argsToString(args)}`);\n origWarn.apply(console, args);\n };\n\n console.error = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[error] ${argsToString(args)}`);\n origError.apply(console, args);\n };\n}\n\nfunction argsToString(args: unknown[]): string {\n try {\n return args\n .map((a) => {\n if (typeof a === \"string\") return a;\n if (a instanceof Error) return a.message;\n try {\n return JSON.stringify(a);\n } catch {\n return String(a);\n }\n })\n .join(\" \")\n .slice(0, 200);\n } catch {\n return \"[unknown]\";\n }\n}\n\n// ─── Fetch Interception ──────────────────────────────────\n\nfunction interceptFetch() {\n const origFetch = window.fetch;\n\n window.fetch = async function (input, init) {\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input instanceof Request\n ? input.url\n : String(input);\n const method = init?.method ?? \"GET\";\n const start = Date.now();\n\n try {\n const response = await origFetch.apply(window, [input, init]);\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → ${response.status}`, {\n method,\n status: String(response.status),\n duration: `${Date.now() - start}ms`,\n });\n return response;\n } catch (err) {\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → FAILED`, {\n method,\n error: err instanceof Error ? err.message : \"unknown\",\n duration: `${Date.now() - start}ms`,\n });\n throw err;\n }\n };\n}\n\n// ─── Navigation Interception ─────────────────────────────\n\nfunction interceptNavigation() {\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPush(...args);\n addBreadcrumb(\"navigation\", `Navigate to ${window.location.pathname}`);\n };\n\n history.replaceState = function (...args) {\n origReplace(...args);\n addBreadcrumb(\"navigation\", `Replace to ${window.location.pathname}`);\n };\n\n window.addEventListener(\"popstate\", () => {\n addBreadcrumb(\"navigation\", `Back/Forward to ${window.location.pathname}`);\n });\n}\n\n// ─── Click Interception ──────────────────────────────────\n\nfunction interceptClicks() {\n document.addEventListener(\n \"click\",\n (e) => {\n try {\n const target = e.target as HTMLElement;\n const tag = target.tagName?.toLowerCase();\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(\" \")[0]}`\n : \"\";\n\n addBreadcrumb(\"click\", `Click ${tag}${id}${cls} \"${text}\"`);\n } catch {\n // Never crash\n }\n },\n { capture: true }\n );\n}\n","import type { ReportPayload, ReportResult, CapturedContext, DeviceInfo } from \"./types\";\nimport { getBreadcrumbs } from \"./breadcrumbs\";\n\nconst SENSITIVE_PARAMS = [\n \"token\", \"key\", \"secret\", \"password\", \"passwd\", \"auth\", \"authorization\",\n \"session\", \"sessionid\", \"session_id\", \"api_key\", \"apikey\", \"access_token\",\n \"refresh_token\", \"client_secret\", \"code\", \"state\", \"nonce\", \"credential\", \"private\",\n];\n\nexport function sanitizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n const params = new URLSearchParams(parsed.search);\n let modified = false;\n for (const key of Array.from(params.keys())) {\n if (SENSITIVE_PARAMS.some((s) => key.toLowerCase().includes(s))) {\n params.set(key, \"[REDACTED]\");\n modified = true;\n }\n }\n if (modified) parsed.search = params.toString();\n return parsed.toString();\n } catch {\n return url.split(\"?\")[0] ?? url;\n }\n}\n\nexport function captureDeviceInfo(): DeviceInfo | null {\n try {\n if (typeof window === \"undefined\") return null;\n return {\n screenWidth: screen.width,\n screenHeight: screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n platform: navigator.platform ?? \"unknown\",\n language: navigator.language ?? \"unknown\",\n online: navigator.onLine,\n colorScheme: window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\",\n devicePixelRatio: window.devicePixelRatio ?? 1,\n };\n } catch {\n return null;\n }\n}\n\nexport function captureContext(visitedPages: string[]): CapturedContext {\n try {\n return {\n url: sanitizeUrl(typeof window !== \"undefined\" ? window.location.href : \"\"),\n userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"\",\n timestamp: new Date().toISOString(),\n visitedPages: visitedPages.map(sanitizeUrl),\n breadcrumbs: getBreadcrumbs(),\n deviceInfo: captureDeviceInfo(),\n };\n } catch {\n return {\n url: \"\",\n userAgent: \"\",\n timestamp: new Date().toISOString(),\n visitedPages: [],\n breadcrumbs: [],\n deviceInfo: null,\n };\n }\n}\n\nconst DEFAULT_BASE_URL = \"https://www.glitchgrab.dev\";\nconst MAX_RETRIES = 3;\nconst RETRY_BASE_MS = 500;\n\n/**\n * Send a report and return the result.\n * Never throws — returns null on failure.\n */\nexport async function sendReport(\n payload: ReportPayload,\n baseUrl?: string\n): Promise<ReportResult | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/report`;\n const body = JSON.stringify(payload);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${payload.token}`,\n };\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n keepalive: true,\n });\n\n if (response.ok) {\n const data = (await response.json()) as { success: boolean; data?: ReportResult };\n return data.data ?? { success: data.success };\n }\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return null;\n }\n } catch {\n // Will retry\n }\n\n if (attempt < MAX_RETRIES - 1) {\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_BASE_MS * Math.pow(2, attempt))\n );\n }\n }\n\n // Fallback: sendBeacon (fire-and-forget, no result)\n if (typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n try {\n navigator.sendBeacon(url, new Blob([body], { type: \"application/json\" }));\n } catch {\n // Silently fail\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n","\"use client\";\n\nimport { useState, useRef, useEffect, type CSSProperties, type ReactNode } from \"react\";\n// @ts-expect-error react-dom types handled by host app\nimport { createPortal } from \"react-dom\";\nimport type { ReportButtonProps, UseGlitchgrabReturn } from \"./types\";\nimport { useGlitchgrab } from \"./provider\";\n\n/** Safe version of useGlitchgrab that returns null when outside provider */\nfunction useGlitchgrabSafe(): UseGlitchgrabReturn | null {\n try {\n return useGlitchgrab();\n } catch {\n return null;\n }\n}\n\n/** Detect if the host page uses a dark or light theme */\nfunction useIsDark(): boolean {\n if (typeof window === \"undefined\") return true;\n try {\n const bg = getComputedStyle(document.body).backgroundColor;\n const match = bg.match(/\\d+/g);\n if (match && match.length >= 3) {\n const [r, g, b] = match.map(Number);\n return (r * 299 + g * 587 + b * 114) / 1000 < 128;\n }\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n } catch {\n return true;\n }\n}\n\nfunction getTheme(dark: boolean) {\n return dark\n ? { bg: \"#1c1c1e\", bgSecondary: \"#27272a\", border: \"#2c2c2e\", text: \"#fafafa\", textMuted: \"#a1a1aa\", accent: \"#22d3ee\", accentText: \"#09090b\", inputBg: \"#27272a\", inputBorder: \"#3f3f46\" }\n : { bg: \"#ffffff\", bgSecondary: \"#f4f4f5\", border: \"#e4e4e7\", text: \"#18181b\", textMuted: \"#71717a\", accent: \"#0891b2\", accentText: \"#ffffff\", inputBg: \"#fafafa\", inputBorder: \"#d4d4d8\" };\n}\n\nexport function ReportButton({\n position = \"bottom-right\",\n label = \"Report Bug\",\n className,\n children,\n}: ReportButtonProps & {\n /** Render prop — receives { onClick, capturing } so you can use your own trigger button */\n children?: (props: { onClick: () => void; capturing: boolean }) => ReactNode;\n}) {\n const [capturing, setCapturing] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [description, setDescription] = useState(\"\");\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const [screenshot, setScreenshot] = useState<string | null>(null);\n const [previewOpen, setPreviewOpen] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const modalRef = useRef<HTMLDivElement>(null);\n const glitchgrab = useGlitchgrabSafe();\n\n // If no provider context, render nothing\n if (!glitchgrab) return null;\n\n const { reportBug } = glitchgrab;\n const isDark = useIsDark();\n const t = getTheme(isDark);\n\n const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => {\n setScreenshot(reader.result as string);\n };\n reader.readAsDataURL(file);\n e.target.value = \"\";\n };\n\n const retakeScreenshot = async () => {\n setPreviewOpen(false);\n setIsOpen(false);\n setScreenshot(null);\n // Small delay so the modal is gone before capture\n await new Promise((r) => setTimeout(r, 300));\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const canvas = await html2canvas(document.body, {\n scale: 0.5,\n logging: false,\n useCORS: true,\n allowTaint: true,\n });\n setScreenshot(canvas.toDataURL(\"image/jpeg\", 0.6));\n } catch {\n // silently fail\n }\n setIsOpen(true);\n };\n\n const handleOpen = async () => {\n setCapturing(true);\n setSubmitted(false);\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const canvas = await html2canvas(document.body, {\n scale: 0.5,\n logging: false,\n useCORS: true,\n allowTaint: true,\n });\n setScreenshot(canvas.toDataURL(\"image/jpeg\", 0.6));\n } catch {\n // screenshot failed — open without it\n }\n setCapturing(false);\n setIsOpen(true);\n };\n\n // Close modal on Escape key\n useEffect(() => {\n if (!isOpen) return;\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n if (previewOpen) setPreviewOpen(false);\n else setIsOpen(false);\n }\n };\n document.addEventListener(\"keydown\", handleEsc);\n return () => document.removeEventListener(\"keydown\", handleEsc);\n }, [isOpen, previewOpen]);\n\n const handleSubmit = async () => {\n try {\n if (!description.trim() || isSubmitting) return;\n\n setIsSubmitting(true);\n const result = await reportBug(description.trim(), screenshot ? { screenshot } : undefined);\n\n if (result) {\n setSubmitted(true);\n setDescription(\"\");\n setScreenshot(null);\n\n setTimeout(() => {\n setSubmitted(false);\n setIsOpen(false);\n }, 2000);\n }\n setIsSubmitting(false);\n } catch {\n setIsSubmitting(false);\n }\n };\n\n const isTop = position?.startsWith(\"top\") ?? false;\n const isLeft = position?.endsWith(\"left\") ?? false;\n\n const modalPositionStyles: CSSProperties = children\n ? {} // user controls positioning\n : {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"64px\" } : { bottom: \"64px\" }),\n };\n\n return (\n <>\n {/* Trigger: user's custom button OR default floating button */}\n {children ? (\n children({ onClick: handleOpen, capturing })\n ) : (\n <DefaultTrigger\n onClick={handleOpen}\n capturing={capturing}\n label={label}\n className={className}\n position={position}\n isLeft={isLeft}\n isTop={isTop}\n />\n )}\n\n {/* Report modal — rendered in portal to escape host stacking contexts */}\n {isOpen && typeof document !== \"undefined\" && createPortal(\n <div\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"rgba(0,0,0,0.5)\",\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n }}\n onClick={() => { if (!previewOpen) setIsOpen(false); }}\n >\n <div\n ref={modalRef}\n onClick={(e) => e.stopPropagation()}\n style={{\n position: children ? \"relative\" : \"fixed\",\n ...modalPositionStyles,\n zIndex: 2147483647,\n width: \"340px\",\n maxWidth: \"calc(100% - 32px)\",\n backgroundColor: t.bg,\n borderRadius: \"12px\",\n boxShadow:\n \"0 20px 60px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.1)\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n overflow: \"hidden\",\n color: t.text,\n isolation: \"isolate\",\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px 16px 12px\",\n borderBottom: `1px solid ${t.border}`,\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n fontSize: \"15px\",\n fontWeight: 600,\n color: t.text,\n }}\n >\n Report a Bug\n </span>\n <button\n type=\"button\"\n onClick={() => setIsOpen(false)}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Close\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" style={{ display: \"block\" }}>\n <path d=\"M4 4L12 12M12 4L4 12\" stroke={t.textMuted} strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Body */}\n <div style={{ padding: \"16px\" }}>\n {submitted ? (\n <div\n style={{\n textAlign: \"center\",\n padding: \"20px 0\",\n color: t.accent,\n fontSize: \"14px\",\n fontWeight: 500,\n }}\n >\n Bug report sent. Thank you!\n </div>\n ) : (\n <>\n {/* Screenshot preview */}\n {screenshot && (\n <div style={{ marginBottom: \"10px\", position: \"relative\" }}>\n <img\n src={screenshot}\n alt=\"Page screenshot\"\n onClick={() => setPreviewOpen(true)}\n style={{\n width: \"100%\",\n borderRadius: \"6px\",\n border: `1px solid ${t.border}`,\n maxHeight: \"120px\",\n objectFit: \"cover\",\n objectPosition: \"top\",\n cursor: \"pointer\",\n }}\n />\n <button\n type=\"button\"\n onClick={() => setScreenshot(null)}\n style={{\n position: \"absolute\",\n top: \"4px\",\n right: \"4px\",\n background: \"rgba(0,0,0,0.6)\",\n border: \"none\",\n borderRadius: \"50%\",\n width: \"20px\",\n height: \"20px\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Remove screenshot\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M1 1L9 9M9 1L1 9\" stroke=\"#fff\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n </button>\n <div\n style={{\n position: \"absolute\",\n bottom: \"4px\",\n left: \"6px\",\n right: \"6px\",\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n background: \"rgba(0,0,0,0.6)\",\n color: \"#fff\",\n fontSize: \"10px\",\n padding: \"2px 6px\",\n borderRadius: \"4px\",\n }}\n >\n Screenshot ({Math.round(screenshot.length * 0.75 / 1024)}KB) — click to preview\n </span>\n <div style={{ display: \"flex\", gap: \"4px\" }}>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n style={{\n background: t.accent,\n color: t.accentText,\n fontSize: \"10px\",\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontWeight: 600,\n }}\n >\n Upload\n </button>\n <button\n type=\"button\"\n onClick={retakeScreenshot}\n style={{\n background: t.accent,\n color: t.accentText,\n fontSize: \"10px\",\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontWeight: 600,\n }}\n >\n Retake\n </button>\n </div>\n </div>\n </div>\n )}\n {!screenshot && !submitted && (\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n style={{\n marginBottom: \"10px\",\n padding: \"10px\",\n borderRadius: \"6px\",\n border: `1px dashed ${t.inputBorder}`,\n textAlign: \"center\",\n fontSize: \"11px\",\n color: t.textMuted,\n width: \"100%\",\n background: \"none\",\n cursor: \"pointer\",\n }}\n >\n Click to upload a screenshot\n </button>\n )}\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe what went wrong...\"\n style={{\n width: \"100%\",\n minHeight: \"100px\",\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n fontSize: \"14px\",\n fontFamily: \"inherit\",\n resize: \"vertical\",\n outline: \"none\",\n boxSizing: \"border-box\",\n color: t.text,\n backgroundColor: t.inputBg,\n }}\n onFocus={(e) => {\n (e.target as HTMLTextAreaElement).style.borderColor = t.accent;\n }}\n onBlur={(e) => {\n (e.target as HTMLTextAreaElement).style.borderColor = t.inputBorder;\n }}\n autoFocus\n />\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!description.trim() || isSubmitting}\n style={{\n marginTop: \"12px\",\n width: \"100%\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor:\n !description.trim() || isSubmitting\n ? t.bgSecondary\n : t.accent,\n color:\n !description.trim() || isSubmitting\n ? t.textMuted\n : t.accentText,\n fontSize: \"14px\",\n fontWeight: 600,\n cursor:\n !description.trim() || isSubmitting\n ? \"not-allowed\"\n : \"pointer\",\n fontFamily: \"inherit\",\n transition: \"background-color 0.15s ease\",\n }}\n >\n {isSubmitting ? \"Sending...\" : \"Send Report\"}\n </button>\n </>\n )}\n </div>\n\n {/* Footer */}\n <div\n style={{\n padding: \"8px 16px 10px\",\n borderTop: `1px solid ${t.border}`,\n textAlign: \"center\",\n }}\n >\n <span style={{ fontSize: \"11px\", color: t.textMuted }}>\n Powered by Glitchgrab\n </span>\n </div>\n </div>\n </div>,\n document.body\n )}\n\n {/* Hidden file input for screenshot upload */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileUpload}\n style={{ display: \"none\" }}\n />\n\n {/* Full-screen screenshot preview */}\n {previewOpen && screenshot && typeof document !== \"undefined\" && createPortal(\n <div\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.85)\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n cursor: \"pointer\",\n }}\n onClick={(e) => { e.stopPropagation(); setPreviewOpen(false); }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n <img\n src={screenshot}\n alt=\"Screenshot preview\"\n onClick={(e) => e.stopPropagation()}\n style={{\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 80px)\",\n borderRadius: \"8px\",\n objectFit: \"contain\",\n cursor: \"default\",\n }}\n />\n <span\n style={{\n marginTop: \"12px\",\n color: t.textMuted,\n fontSize: \"12px\",\n }}\n >\n Click outside to close\n </span>\n </div>,\n document.body\n )}\n </>\n );\n}\n\n/** Default floating trigger button (used when no children provided) */\nfunction DefaultTrigger({\n onClick,\n capturing,\n label,\n className,\n position,\n isLeft,\n isTop,\n}: {\n onClick: () => void;\n capturing: boolean;\n label: string;\n className?: string;\n position?: string;\n isLeft: boolean;\n isTop: boolean;\n}) {\n const positionStyles: CSSProperties = {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"16px\" } : { bottom: \"16px\" }),\n };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={capturing}\n className={className}\n style={{\n position: \"fixed\",\n ...positionStyles,\n zIndex: 99999,\n padding: \"10px 18px\",\n borderRadius: \"24px\",\n border: \"none\",\n backgroundColor: \"#18181b\",\n color: \"#fafafa\",\n fontSize: \"14px\",\n fontWeight: 500,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n cursor: capturing ? \"wait\" : \"pointer\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.15s ease, box-shadow 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n opacity: capturing ? 0.7 : 1,\n }}\n onMouseEnter={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1)\";\n }}\n aria-label={label}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n >\n <path\n d=\"M8 1C4.134 1 1 4.134 1 8s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zm.75-3.5a.75.75 0 01-1.5 0V5a.75.75 0 011.5 0v5z\"\n fill=\"currentColor\"\n />\n </svg>\n {capturing ? \"Capturing...\" : label}\n </button>\n );\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\n\ninterface GlitchgrabReport {\n id: string;\n source: string;\n status: string;\n rawInput: string | null;\n reporterPrimaryKey: string;\n reporterName: string;\n reporterEmail: string | null;\n reporterPhone: string | null;\n pageUrl: string | null;\n createdAt: string;\n issue: {\n githubNumber: number;\n githubUrl: string;\n title: string;\n labels: string[];\n severity: string | null;\n githubState: string | null;\n } | null;\n}\n\nconst BASE_URL = \"https://www.glitchgrab.dev\";\n\n/**\n * Hook to fetch bug reports for a specific user.\n *\n * ```tsx\n * const { reports, isLoading, error, refetch } = useGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * });\n * ```\n */\nexport function useGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n /** Max results (default 100, max 100) */\n limit?: number;\n}): {\n reports: GlitchgrabReport[];\n isLoading: boolean;\n isFetching: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n} {\n const [reports, setReports] = useState<GlitchgrabReport[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fetchReports = useCallback(async () => {\n if (!token || !userId) {\n setIsLoading(false);\n return;\n }\n\n setIsFetching(true);\n setError(null);\n\n try {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n\n if (data.success) {\n setReports(data.data ?? []);\n } else {\n setError(data.error ?? \"Failed to fetch reports\");\n }\n } catch {\n setError(\"Network error\");\n } finally {\n setIsLoading(false);\n setIsFetching(false);\n }\n }, [token, userId, limit]);\n\n useEffect(() => {\n fetchReports();\n }, [fetchReports]);\n\n return { reports, isLoading, isFetching, error, refetch: fetchReports };\n}\n\n/**\n * Standalone fetcher — use with TanStack Query or any data fetching library.\n *\n * ```tsx\n * const { data } = useQuery({\n * queryKey: [\"glitchgrab-reports\", userId],\n * queryFn: () => fetchGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * }),\n * });\n * ```\n */\nexport async function fetchGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n limit?: number;\n}): Promise<GlitchgrabReport[]> {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n if (!data.success) throw new Error(data.error ?? \"Failed to fetch reports\");\n return data.data ?? [];\n}\n"],"mappings":"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","names":["e","DEFAULT_BASE_URL","maxBreadcrumbs","addBreadcrumb","import_react","import_jsx_runtime","_a","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/error-boundary.tsx","../src/breadcrumbs.ts","../src/utils.ts","../src/report-button.tsx","../src/use-reports.ts"],"sourcesContent":["\"use client\";\n\n// ─── Core (required) ─────────────────────────────────────\nexport { GlitchgrabProvider, useGlitchgrab } from \"./provider\";\n\n// ─── Optional Components ─────────────────────────────────\nexport { ReportButton } from \"./report-button\";\nexport { GlitchgrabErrorBoundary } from \"./error-boundary\";\n\n// ─── Hooks ──────────────────────────────────────────────\nexport { useGlitchgrabReports, fetchGlitchgrabReports, useGlitchgrabActions } from \"./use-reports\";\n\n// ─── Breadcrumbs ─────────────────────────────────────────\nexport {\n addBreadcrumb,\n getBreadcrumbs,\n clearBreadcrumbs,\n initBreadcrumbs,\n} from \"./breadcrumbs\";\n\n// ─── Utilities ───────────────────────────────────────────\nexport { sanitizeUrl, captureContext, captureDeviceInfo, sendReport } from \"./utils\";\n\n// ─── Types ───────────────────────────────────────────────\nexport type {\n GlitchgrabConfig,\n GlitchgrabProviderProps,\n ReportPayload,\n ReportResult,\n ReportType,\n CapturedContext,\n DeviceInfo,\n Breadcrumb,\n BreadcrumbType,\n UseGlitchgrabReturn,\n ReportButtonProps,\n GlitchgrabSession,\n} from \"./types\";\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useRef,\n useEffect,\n useCallback,\n useState,\n} from \"react\";\nimport type {\n GlitchgrabProviderProps,\n UseGlitchgrabReturn,\n ReportPayload,\n ReportResult,\n ReportType,\n} from \"./types\";\nimport { GlitchgrabErrorBoundary } from \"./error-boundary\";\nimport { sanitizeUrl, captureContext, sendReport, captureDeviceInfo } from \"./utils\";\nimport {\n initBreadcrumbs,\n addBreadcrumb as addBreadcrumbInternal,\n getBreadcrumbs,\n} from \"./breadcrumbs\";\n\nconst DEFAULT_BASE_URL = \"https://www.glitchgrab.dev\";\n\nconst GlitchgrabContext = createContext<UseGlitchgrabReturn | null>(null);\n\n/**\n * Hook to access Glitchgrab in your components.\n *\n * @example\n * ```tsx\n * const { reportBug, report, addBreadcrumb } = useGlitchgrab();\n *\n * // Report a bug\n * reportBug(\"Login button crashes on mobile\");\n *\n * // Report a feature request\n * report(\"FEATURE_REQUEST\", \"Add dark mode\");\n *\n * // Add a custom breadcrumb\n * addBreadcrumb(\"User clicked checkout\", { cartItems: \"3\" });\n * ```\n */\nexport function useGlitchgrab(): UseGlitchgrabReturn {\n const ctx = useContext(GlitchgrabContext);\n if (!ctx) {\n throw new Error(\"useGlitchgrab must be used within a GlitchgrabProvider\");\n }\n return ctx;\n}\n\nfunction GlitchgrabProviderInner({\n token,\n session,\n baseUrl,\n onError,\n onReportSent,\n breadcrumbs: enableBreadcrumbs = true,\n maxBreadcrumbs = 50,\n children,\n fallback,\n}: GlitchgrabProviderProps) {\n const visitedPagesRef = useRef<string[]>([]);\n\n // Initialize breadcrumbs\n useEffect(() => {\n if (enableBreadcrumbs) {\n initBreadcrumbs(maxBreadcrumbs);\n }\n }, [enableBreadcrumbs, maxBreadcrumbs]);\n\n // Track page visits\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n\n const trackPage = () => {\n try {\n const sanitized = sanitizeUrl(window.location.href);\n const pages = visitedPagesRef.current;\n if (pages[pages.length - 1] !== sanitized) {\n pages.push(sanitized);\n if (pages.length > 20) {\n pages.splice(0, pages.length - 20);\n }\n }\n } catch {\n // Silently fail\n }\n };\n\n trackPage();\n const handlePopState = () => trackPage();\n window.addEventListener(\"popstate\", handlePopState);\n\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPushState(...args);\n trackPage();\n };\n history.replaceState = function (...args) {\n origReplaceState(...args);\n trackPage();\n };\n\n return () => {\n window.removeEventListener(\"popstate\", handlePopState);\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n };\n } catch {\n // Never crash\n }\n }, []);\n\n // Unhandled errors and rejections — skip in development\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n if (process.env.NODE_ENV === \"development\") return;\n\n const handleError = (event: ErrorEvent) => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: event.message,\n errorStack: event.error?.stack,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n filename: event.filename ?? \"\",\n lineno: String(event.lineno ?? \"\"),\n colno: String(event.colno ?? \"\"),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && event.error) onError(event.error);\n } catch {\n // Silently fail\n }\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const reason = event.reason;\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: reason instanceof Error ? reason.message : String(reason),\n errorStack: reason instanceof Error ? reason.stack : undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n type: \"unhandledrejection\",\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && reason instanceof Error) onError(reason);\n } catch {\n // Silently fail\n }\n };\n\n window.addEventListener(\"error\", handleError);\n window.addEventListener(\"unhandledrejection\", handleRejection);\n\n return () => {\n window.removeEventListener(\"error\", handleError);\n window.removeEventListener(\"unhandledrejection\", handleRejection);\n };\n } catch {\n // Never crash\n }\n }, [token, baseUrl, onError, onReportSent]);\n\n const report = useCallback(\n async (\n type: ReportType,\n description: string,\n metadata?: Record<string, string>\n ): Promise<ReportResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_USER_REPORT\",\n type,\n description,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n ...metadata,\n },\n };\n const result = await sendReport(payload, baseUrl);\n if (result && onReportSent) onReportSent(result);\n return result;\n } catch {\n return null;\n }\n },\n [token, baseUrl, onReportSent]\n );\n\n const reportBug = useCallback(\n (description: string, metadata?: Record<string, string>) =>\n report(\"BUG\", description, metadata),\n [report]\n );\n\n const addBreadcrumb = useCallback(\n (message: string, data?: Record<string, string>) => {\n addBreadcrumbInternal(\"custom\", message, data);\n },\n []\n );\n\n return (\n <GlitchgrabContext.Provider\n value={{\n token,\n baseUrl: baseUrl ?? DEFAULT_BASE_URL,\n reportBug,\n report,\n addBreadcrumb,\n }}\n >\n <GlitchgrabErrorBoundary\n token={token}\n baseUrl={baseUrl}\n onError={onError}\n fallback={fallback}\n visitedPages={visitedPagesRef.current}\n >\n {children}\n </GlitchgrabErrorBoundary>\n </GlitchgrabContext.Provider>\n );\n}\n\nexport function GlitchgrabProvider(props: GlitchgrabProviderProps) {\n // No token = passthrough (SDK disabled)\n if (!props.token) return <>{props.children}</>;\n\n const resolvedProps = {\n ...props,\n baseUrl: props.baseUrl || DEFAULT_BASE_URL,\n };\n\n try {\n return <GlitchgrabProviderInner {...resolvedProps} />;\n } catch {\n return <>{props.children}</>;\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { ReportPayload } from \"./types\";\nimport { captureContext, sendReport } from \"./utils\";\n\ninterface ErrorBoundaryProps {\n token: string;\n baseUrl?: string;\n onError?: (error: Error) => void;\n fallback?: React.ReactNode;\n visitedPages: string[];\n children: React.ReactNode;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n}\n\nexport class GlitchgrabErrorBoundary extends React.Component<\n ErrorBoundaryProps,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): ErrorBoundaryState {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n try {\n const context = captureContext(this.props.visitedPages);\n\n const payload: ReportPayload = {\n token: this.props.token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: error.message,\n errorStack: error.stack,\n componentStack: errorInfo.componentStack ?? undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n },\n };\n\n sendReport(payload, this.props.baseUrl);\n\n if (this.props.onError) {\n this.props.onError(error);\n }\n } catch {\n // Never crash the host app\n }\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n // Re-render children — allows recovery from transient errors\n return this.props.children;\n }\n\n return this.props.children;\n }\n}\n","import type { Breadcrumb, BreadcrumbType } from \"./types\";\n\nconst MAX_DEFAULT = 50;\n\nlet breadcrumbs: Breadcrumb[] = [];\nlet maxBreadcrumbs = MAX_DEFAULT;\nlet initialized = false;\n\nexport function initBreadcrumbs(max?: number) {\n if (initialized) return;\n maxBreadcrumbs = max ?? MAX_DEFAULT;\n\n try {\n if (typeof window === \"undefined\") return;\n interceptConsole();\n interceptFetch();\n interceptNavigation();\n interceptClicks();\n initialized = true;\n } catch {\n // Never crash\n }\n}\n\nexport function addBreadcrumb(\n type: BreadcrumbType,\n message: string,\n data?: Record<string, string>\n) {\n try {\n breadcrumbs.push({\n type,\n message: message.slice(0, 200),\n timestamp: new Date().toISOString(),\n data,\n });\n if (breadcrumbs.length > maxBreadcrumbs) {\n breadcrumbs = breadcrumbs.slice(-maxBreadcrumbs);\n }\n } catch {\n // Never crash\n }\n}\n\nexport function getBreadcrumbs(): Breadcrumb[] {\n return [...breadcrumbs];\n}\n\nexport function clearBreadcrumbs() {\n breadcrumbs = [];\n}\n\n// ─── Console Interception ────────────────────────────────\n\nfunction interceptConsole() {\n const origLog = console.log;\n const origWarn = console.warn;\n const origError = console.error;\n\n console.log = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[log] ${argsToString(args)}`);\n origLog.apply(console, args);\n };\n\n console.warn = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[warn] ${argsToString(args)}`);\n origWarn.apply(console, args);\n };\n\n console.error = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[error] ${argsToString(args)}`);\n origError.apply(console, args);\n };\n}\n\nfunction argsToString(args: unknown[]): string {\n try {\n return args\n .map((a) => {\n if (typeof a === \"string\") return a;\n if (a instanceof Error) return a.message;\n try {\n return JSON.stringify(a);\n } catch {\n return String(a);\n }\n })\n .join(\" \")\n .slice(0, 200);\n } catch {\n return \"[unknown]\";\n }\n}\n\n// ─── Fetch Interception ──────────────────────────────────\n\nfunction interceptFetch() {\n const origFetch = window.fetch;\n\n window.fetch = async function (input, init) {\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input instanceof Request\n ? input.url\n : String(input);\n const method = init?.method ?? \"GET\";\n const start = Date.now();\n\n try {\n const response = await origFetch.apply(window, [input, init]);\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → ${response.status}`, {\n method,\n status: String(response.status),\n duration: `${Date.now() - start}ms`,\n });\n return response;\n } catch (err) {\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → FAILED`, {\n method,\n error: err instanceof Error ? err.message : \"unknown\",\n duration: `${Date.now() - start}ms`,\n });\n throw err;\n }\n };\n}\n\n// ─── Navigation Interception ─────────────────────────────\n\nfunction interceptNavigation() {\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPush(...args);\n addBreadcrumb(\"navigation\", `Navigate to ${window.location.pathname}`);\n };\n\n history.replaceState = function (...args) {\n origReplace(...args);\n addBreadcrumb(\"navigation\", `Replace to ${window.location.pathname}`);\n };\n\n window.addEventListener(\"popstate\", () => {\n addBreadcrumb(\"navigation\", `Back/Forward to ${window.location.pathname}`);\n });\n}\n\n// ─── Click Interception ──────────────────────────────────\n\nfunction interceptClicks() {\n document.addEventListener(\n \"click\",\n (e) => {\n try {\n const target = e.target as HTMLElement;\n const tag = target.tagName?.toLowerCase();\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(\" \")[0]}`\n : \"\";\n\n addBreadcrumb(\"click\", `Click ${tag}${id}${cls} \"${text}\"`);\n } catch {\n // Never crash\n }\n },\n { capture: true }\n );\n}\n","import type { ReportPayload, ReportResult, CapturedContext, DeviceInfo } from \"./types\";\nimport { getBreadcrumbs } from \"./breadcrumbs\";\n\nconst SENSITIVE_PARAMS = [\n \"token\", \"key\", \"secret\", \"password\", \"passwd\", \"auth\", \"authorization\",\n \"session\", \"sessionid\", \"session_id\", \"api_key\", \"apikey\", \"access_token\",\n \"refresh_token\", \"client_secret\", \"code\", \"state\", \"nonce\", \"credential\", \"private\",\n];\n\nexport function sanitizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n const params = new URLSearchParams(parsed.search);\n let modified = false;\n for (const key of Array.from(params.keys())) {\n if (SENSITIVE_PARAMS.some((s) => key.toLowerCase().includes(s))) {\n params.set(key, \"[REDACTED]\");\n modified = true;\n }\n }\n if (modified) parsed.search = params.toString();\n return parsed.toString();\n } catch {\n return url.split(\"?\")[0] ?? url;\n }\n}\n\nexport function captureDeviceInfo(): DeviceInfo | null {\n try {\n if (typeof window === \"undefined\") return null;\n return {\n screenWidth: screen.width,\n screenHeight: screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n platform: navigator.platform ?? \"unknown\",\n language: navigator.language ?? \"unknown\",\n online: navigator.onLine,\n colorScheme: window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\",\n devicePixelRatio: window.devicePixelRatio ?? 1,\n };\n } catch {\n return null;\n }\n}\n\nexport function captureContext(visitedPages: string[]): CapturedContext {\n try {\n return {\n url: sanitizeUrl(typeof window !== \"undefined\" ? window.location.href : \"\"),\n userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"\",\n timestamp: new Date().toISOString(),\n visitedPages: visitedPages.map(sanitizeUrl),\n breadcrumbs: getBreadcrumbs(),\n deviceInfo: captureDeviceInfo(),\n };\n } catch {\n return {\n url: \"\",\n userAgent: \"\",\n timestamp: new Date().toISOString(),\n visitedPages: [],\n breadcrumbs: [],\n deviceInfo: null,\n };\n }\n}\n\nconst DEFAULT_BASE_URL = \"https://www.glitchgrab.dev\";\nconst MAX_RETRIES = 3;\nconst RETRY_BASE_MS = 500;\n\n/**\n * Send a report and return the result.\n * Never throws — returns null on failure.\n */\nexport async function sendReport(\n payload: ReportPayload,\n baseUrl?: string\n): Promise<ReportResult | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/report`;\n const body = JSON.stringify(payload);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${payload.token}`,\n };\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n keepalive: true,\n });\n\n if (response.ok) {\n const data = (await response.json()) as { success: boolean; data?: ReportResult };\n return data.data ?? { success: data.success };\n }\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return null;\n }\n } catch {\n // Will retry\n }\n\n if (attempt < MAX_RETRIES - 1) {\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_BASE_MS * Math.pow(2, attempt))\n );\n }\n }\n\n // Fallback: sendBeacon (fire-and-forget, no result)\n if (typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n try {\n navigator.sendBeacon(url, new Blob([body], { type: \"application/json\" }));\n } catch {\n // Silently fail\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n","\"use client\";\n\nimport { useState, useRef, useEffect, type CSSProperties, type ReactNode } from \"react\";\n// @ts-expect-error react-dom types handled by host app\nimport { createPortal } from \"react-dom\";\nimport type { ReportButtonProps, UseGlitchgrabReturn } from \"./types\";\nimport { useGlitchgrab } from \"./provider\";\n\n/** Safe version of useGlitchgrab that returns null when outside provider */\nfunction useGlitchgrabSafe(): UseGlitchgrabReturn | null {\n try {\n return useGlitchgrab();\n } catch {\n return null;\n }\n}\n\n/** Detect if the host page uses a dark or light theme */\nfunction useIsDark(): boolean {\n if (typeof window === \"undefined\") return true;\n try {\n const bg = getComputedStyle(document.body).backgroundColor;\n const match = bg.match(/\\d+/g);\n if (match && match.length >= 3) {\n const [r, g, b] = match.map(Number);\n return (r * 299 + g * 587 + b * 114) / 1000 < 128;\n }\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n } catch {\n return true;\n }\n}\n\nfunction getTheme(dark: boolean) {\n return dark\n ? { bg: \"#1c1c1e\", bgSecondary: \"#27272a\", border: \"#2c2c2e\", text: \"#fafafa\", textMuted: \"#a1a1aa\", accent: \"#22d3ee\", accentText: \"#09090b\", inputBg: \"#27272a\", inputBorder: \"#3f3f46\" }\n : { bg: \"#ffffff\", bgSecondary: \"#f4f4f5\", border: \"#e4e4e7\", text: \"#18181b\", textMuted: \"#71717a\", accent: \"#0891b2\", accentText: \"#ffffff\", inputBg: \"#fafafa\", inputBorder: \"#d4d4d8\" };\n}\n\nexport function ReportButton({\n position = \"bottom-right\",\n label = \"Report Bug\",\n className,\n children,\n}: ReportButtonProps & {\n /** Render prop — receives { onClick, capturing } so you can use your own trigger button */\n children?: (props: { onClick: () => void; capturing: boolean }) => ReactNode;\n}) {\n const [capturing, setCapturing] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [description, setDescription] = useState(\"\");\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const [screenshot, setScreenshot] = useState<string | null>(null);\n const [previewOpen, setPreviewOpen] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const modalRef = useRef<HTMLDivElement>(null);\n const glitchgrab = useGlitchgrabSafe();\n\n // If no provider context, render nothing\n if (!glitchgrab) return null;\n\n const { reportBug } = glitchgrab;\n const isDark = useIsDark();\n const t = getTheme(isDark);\n\n const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => {\n setScreenshot(reader.result as string);\n };\n reader.readAsDataURL(file);\n e.target.value = \"\";\n };\n\n const retakeScreenshot = async () => {\n setPreviewOpen(false);\n setIsOpen(false);\n setScreenshot(null);\n // Small delay so the modal is gone before capture\n await new Promise((r) => setTimeout(r, 300));\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const canvas = await html2canvas(document.body, {\n scale: 0.5,\n logging: false,\n useCORS: true,\n allowTaint: true,\n });\n setScreenshot(canvas.toDataURL(\"image/jpeg\", 0.6));\n } catch {\n // silently fail\n }\n setIsOpen(true);\n };\n\n const handleOpen = async () => {\n setCapturing(true);\n setSubmitted(false);\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const canvas = await html2canvas(document.body, {\n scale: 0.5,\n logging: false,\n useCORS: true,\n allowTaint: true,\n });\n setScreenshot(canvas.toDataURL(\"image/jpeg\", 0.6));\n } catch {\n // screenshot failed — open without it\n }\n setCapturing(false);\n setIsOpen(true);\n };\n\n // Close modal on Escape key\n useEffect(() => {\n if (!isOpen) return;\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n if (previewOpen) setPreviewOpen(false);\n else setIsOpen(false);\n }\n };\n document.addEventListener(\"keydown\", handleEsc);\n return () => document.removeEventListener(\"keydown\", handleEsc);\n }, [isOpen, previewOpen]);\n\n const handleSubmit = async () => {\n try {\n if (!description.trim() || isSubmitting) return;\n\n setIsSubmitting(true);\n const result = await reportBug(description.trim(), screenshot ? { screenshot } : undefined);\n\n if (result) {\n setSubmitted(true);\n setDescription(\"\");\n setScreenshot(null);\n\n setTimeout(() => {\n setSubmitted(false);\n setIsOpen(false);\n }, 2000);\n }\n setIsSubmitting(false);\n } catch {\n setIsSubmitting(false);\n }\n };\n\n const isTop = position?.startsWith(\"top\") ?? false;\n const isLeft = position?.endsWith(\"left\") ?? false;\n\n const modalPositionStyles: CSSProperties = children\n ? {} // user controls positioning\n : {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"64px\" } : { bottom: \"64px\" }),\n };\n\n return (\n <>\n {/* Trigger: user's custom button OR default floating button */}\n {children ? (\n children({ onClick: handleOpen, capturing })\n ) : (\n <DefaultTrigger\n onClick={handleOpen}\n capturing={capturing}\n label={label}\n className={className}\n position={position}\n isLeft={isLeft}\n isTop={isTop}\n />\n )}\n\n {/* Report modal — rendered in portal to escape host stacking contexts */}\n {isOpen && typeof document !== \"undefined\" && createPortal(\n <div\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"rgba(0,0,0,0.5)\",\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n }}\n onClick={() => { if (!previewOpen) setIsOpen(false); }}\n >\n <div\n ref={modalRef}\n onClick={(e) => e.stopPropagation()}\n style={{\n position: children ? \"relative\" : \"fixed\",\n ...modalPositionStyles,\n zIndex: 2147483647,\n width: \"340px\",\n maxWidth: \"calc(100% - 32px)\",\n backgroundColor: t.bg,\n borderRadius: \"12px\",\n boxShadow:\n \"0 20px 60px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.1)\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n overflow: \"hidden\",\n color: t.text,\n isolation: \"isolate\",\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px 16px 12px\",\n borderBottom: `1px solid ${t.border}`,\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n fontSize: \"15px\",\n fontWeight: 600,\n color: t.text,\n }}\n >\n Report a Bug\n </span>\n <button\n type=\"button\"\n onClick={() => setIsOpen(false)}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Close\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" style={{ display: \"block\" }}>\n <path d=\"M4 4L12 12M12 4L4 12\" stroke={t.textMuted} strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Body */}\n <div style={{ padding: \"16px\" }}>\n {submitted ? (\n <div\n style={{\n textAlign: \"center\",\n padding: \"20px 0\",\n color: t.accent,\n fontSize: \"14px\",\n fontWeight: 500,\n }}\n >\n Bug report sent. Thank you!\n </div>\n ) : (\n <>\n {/* Screenshot preview */}\n {screenshot && (\n <div style={{ marginBottom: \"10px\", position: \"relative\" }}>\n <img\n src={screenshot}\n alt=\"Page screenshot\"\n onClick={() => setPreviewOpen(true)}\n style={{\n width: \"100%\",\n borderRadius: \"6px\",\n border: `1px solid ${t.border}`,\n maxHeight: \"120px\",\n objectFit: \"cover\",\n objectPosition: \"top\",\n cursor: \"pointer\",\n }}\n />\n <button\n type=\"button\"\n onClick={() => setScreenshot(null)}\n style={{\n position: \"absolute\",\n top: \"4px\",\n right: \"4px\",\n background: \"rgba(0,0,0,0.6)\",\n border: \"none\",\n borderRadius: \"50%\",\n width: \"20px\",\n height: \"20px\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Remove screenshot\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M1 1L9 9M9 1L1 9\" stroke=\"#fff\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n </button>\n <div\n style={{\n position: \"absolute\",\n bottom: \"4px\",\n left: \"6px\",\n right: \"6px\",\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n background: \"rgba(0,0,0,0.6)\",\n color: \"#fff\",\n fontSize: \"10px\",\n padding: \"2px 6px\",\n borderRadius: \"4px\",\n }}\n >\n Screenshot ({Math.round(screenshot.length * 0.75 / 1024)}KB) — click to preview\n </span>\n <div style={{ display: \"flex\", gap: \"4px\" }}>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n style={{\n background: t.accent,\n color: t.accentText,\n fontSize: \"10px\",\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontWeight: 600,\n }}\n >\n Upload\n </button>\n <button\n type=\"button\"\n onClick={retakeScreenshot}\n style={{\n background: t.accent,\n color: t.accentText,\n fontSize: \"10px\",\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontWeight: 600,\n }}\n >\n Retake\n </button>\n </div>\n </div>\n </div>\n )}\n {!screenshot && !submitted && (\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n style={{\n marginBottom: \"10px\",\n padding: \"10px\",\n borderRadius: \"6px\",\n border: `1px dashed ${t.inputBorder}`,\n textAlign: \"center\",\n fontSize: \"11px\",\n color: t.textMuted,\n width: \"100%\",\n background: \"none\",\n cursor: \"pointer\",\n }}\n >\n Click to upload a screenshot\n </button>\n )}\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe what went wrong...\"\n style={{\n width: \"100%\",\n minHeight: \"100px\",\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n fontSize: \"14px\",\n fontFamily: \"inherit\",\n resize: \"vertical\",\n outline: \"none\",\n boxSizing: \"border-box\",\n color: t.text,\n backgroundColor: t.inputBg,\n }}\n onFocus={(e) => {\n (e.target as HTMLTextAreaElement).style.borderColor = t.accent;\n }}\n onBlur={(e) => {\n (e.target as HTMLTextAreaElement).style.borderColor = t.inputBorder;\n }}\n autoFocus\n />\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!description.trim() || isSubmitting}\n style={{\n marginTop: \"12px\",\n width: \"100%\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor:\n !description.trim() || isSubmitting\n ? t.bgSecondary\n : t.accent,\n color:\n !description.trim() || isSubmitting\n ? t.textMuted\n : t.accentText,\n fontSize: \"14px\",\n fontWeight: 600,\n cursor:\n !description.trim() || isSubmitting\n ? \"not-allowed\"\n : \"pointer\",\n fontFamily: \"inherit\",\n transition: \"background-color 0.15s ease\",\n }}\n >\n {isSubmitting ? \"Sending...\" : \"Send Report\"}\n </button>\n </>\n )}\n </div>\n\n {/* Footer */}\n <div\n style={{\n padding: \"8px 16px 10px\",\n borderTop: `1px solid ${t.border}`,\n textAlign: \"center\",\n }}\n >\n <span style={{ fontSize: \"11px\", color: t.textMuted }}>\n Powered by Glitchgrab\n </span>\n </div>\n </div>\n </div>,\n document.body\n )}\n\n {/* Hidden file input for screenshot upload */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileUpload}\n style={{ display: \"none\" }}\n />\n\n {/* Full-screen screenshot preview */}\n {previewOpen && screenshot && typeof document !== \"undefined\" && createPortal(\n <div\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.85)\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n cursor: \"pointer\",\n }}\n onClick={(e) => { e.stopPropagation(); setPreviewOpen(false); }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n <img\n src={screenshot}\n alt=\"Screenshot preview\"\n onClick={(e) => e.stopPropagation()}\n style={{\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 80px)\",\n borderRadius: \"8px\",\n objectFit: \"contain\",\n cursor: \"default\",\n }}\n />\n <span\n style={{\n marginTop: \"12px\",\n color: t.textMuted,\n fontSize: \"12px\",\n }}\n >\n Click outside to close\n </span>\n </div>,\n document.body\n )}\n </>\n );\n}\n\n/** Default floating trigger button (used when no children provided) */\nfunction DefaultTrigger({\n onClick,\n capturing,\n label,\n className,\n position,\n isLeft,\n isTop,\n}: {\n onClick: () => void;\n capturing: boolean;\n label: string;\n className?: string;\n position?: string;\n isLeft: boolean;\n isTop: boolean;\n}) {\n const positionStyles: CSSProperties = {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"16px\" } : { bottom: \"16px\" }),\n };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={capturing}\n className={className}\n style={{\n position: \"fixed\",\n ...positionStyles,\n zIndex: 99999,\n padding: \"10px 18px\",\n borderRadius: \"24px\",\n border: \"none\",\n backgroundColor: \"#18181b\",\n color: \"#fafafa\",\n fontSize: \"14px\",\n fontWeight: 500,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n cursor: capturing ? \"wait\" : \"pointer\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.15s ease, box-shadow 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n opacity: capturing ? 0.7 : 1,\n }}\n onMouseEnter={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1)\";\n }}\n aria-label={label}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n >\n <path\n d=\"M8 1C4.134 1 1 4.134 1 8s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zm.75-3.5a.75.75 0 01-1.5 0V5a.75.75 0 011.5 0v5z\"\n fill=\"currentColor\"\n />\n </svg>\n {capturing ? \"Capturing...\" : label}\n </button>\n );\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\n\ninterface GlitchgrabReport {\n id: string;\n source: string;\n status: string;\n rawInput: string | null;\n reporterPrimaryKey: string;\n reporterName: string;\n reporterEmail: string | null;\n reporterPhone: string | null;\n pageUrl: string | null;\n createdAt: string;\n issue: {\n githubNumber: number;\n githubUrl: string;\n title: string;\n labels: string[];\n severity: string | null;\n githubState: string | null;\n } | null;\n}\n\nconst BASE_URL = \"https://www.glitchgrab.dev\";\n\n/**\n * Hook to fetch bug reports for a specific user.\n *\n * ```tsx\n * const { reports, isLoading, error, refetch } = useGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * });\n * ```\n */\nexport function useGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n /** Max results (default 100, max 100) */\n limit?: number;\n}): {\n reports: GlitchgrabReport[];\n isLoading: boolean;\n isFetching: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n} {\n const [reports, setReports] = useState<GlitchgrabReport[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fetchReports = useCallback(async () => {\n if (!token || !userId) {\n setIsLoading(false);\n return;\n }\n\n setIsFetching(true);\n setError(null);\n\n try {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n\n if (data.success) {\n setReports(data.data ?? []);\n } else {\n setError(data.error ?? \"Failed to fetch reports\");\n }\n } catch {\n setError(\"Network error\");\n } finally {\n setIsLoading(false);\n setIsFetching(false);\n }\n }, [token, userId, limit]);\n\n useEffect(() => {\n fetchReports();\n }, [fetchReports]);\n\n return { reports, isLoading, isFetching, error, refetch: fetchReports };\n}\n\n/**\n * Standalone fetcher — use with TanStack Query or any data fetching library.\n *\n * ```tsx\n * const { data } = useQuery({\n * queryKey: [\"glitchgrab-reports\", userId],\n * queryFn: () => fetchGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * }),\n * });\n * ```\n */\nexport async function fetchGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n limit?: number;\n}): Promise<GlitchgrabReport[]> {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n if (!data.success) throw new Error(data.error ?? \"Failed to fetch reports\");\n return data.data ?? [];\n}\n\n// ─── Report Actions ─────────────────────────────────────\n\nasync function reportAction(\n token: string,\n reportId: string,\n body: Record<string, string>\n): Promise<void> {\n const res = await fetch(`${BASE_URL}/api/v1/reports/${reportId}/actions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok || !data.success) throw new Error(data.error ?? \"Action failed\");\n}\n\n/**\n * Hook to manage report actions with loading/error states.\n *\n * ```tsx\n * const { approve, reject, close, isPending, error } = useGlitchgrabActions({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * onSuccess: () => refetch(),\n * onError: (err) => toast.error(err.message),\n * });\n *\n * <button onClick={() => approve(reportId)} disabled={isPending}>\n * {isPending ? \"...\" : \"Approve\"}\n * </button>\n * ```\n */\nexport function useGlitchgrabActions({\n token,\n onSuccess,\n onError,\n}: {\n token: string;\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n}) {\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const run = useCallback(\n async (reportId: string, body: Record<string, string>) => {\n setIsPending(true);\n setError(null);\n try {\n await reportAction(token, reportId, body);\n onSuccess?.();\n } catch (e) {\n const err = e instanceof Error ? e : new Error(\"Action failed\");\n setError(err.message);\n onError?.(err);\n } finally {\n setIsPending(false);\n }\n },\n [token, onSuccess, onError]\n );\n\n return {\n approve: (reportId: string) => run(reportId, { action: \"label\", label: \"approved\" }),\n reject: (reportId: string) => run(reportId, { action: \"label\", label: \"rejected\" }),\n close: (reportId: string) => run(reportId, { action: \"close\" }),\n reopen: (reportId: string) => run(reportId, { action: \"reopen\" }),\n label: (reportId: string, label: string) => run(reportId, { action: \"label\", label }),\n unlabel: (reportId: string, label: string) => run(reportId, { action: \"unlabel\", label }),\n isPending,\n error,\n };\n}\n"],"mappings":"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","names":["e","DEFAULT_BASE_URL","maxBreadcrumbs","addBreadcrumb","import_react","import_jsx_runtime","_a","import_react"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1184,6 +1184,54 @@ async function fetchGlitchgrabReports({
|
|
|
1184
1184
|
if (!data.success) throw new Error((_a = data.error) != null ? _a : "Failed to fetch reports");
|
|
1185
1185
|
return (_b = data.data) != null ? _b : [];
|
|
1186
1186
|
}
|
|
1187
|
+
async function reportAction(token, reportId, body) {
|
|
1188
|
+
var _a;
|
|
1189
|
+
const res = await fetch(`${BASE_URL}/api/v1/reports/${reportId}/actions`, {
|
|
1190
|
+
method: "POST",
|
|
1191
|
+
headers: {
|
|
1192
|
+
Authorization: `Bearer ${token}`,
|
|
1193
|
+
"Content-Type": "application/json"
|
|
1194
|
+
},
|
|
1195
|
+
body: JSON.stringify(body)
|
|
1196
|
+
});
|
|
1197
|
+
const data = await res.json().catch(() => ({}));
|
|
1198
|
+
if (!res.ok || !data.success) throw new Error((_a = data.error) != null ? _a : "Action failed");
|
|
1199
|
+
}
|
|
1200
|
+
function useGlitchgrabActions({
|
|
1201
|
+
token,
|
|
1202
|
+
onSuccess,
|
|
1203
|
+
onError
|
|
1204
|
+
}) {
|
|
1205
|
+
const [isPending, setIsPending] = useState3(false);
|
|
1206
|
+
const [error, setError] = useState3(null);
|
|
1207
|
+
const run = useCallback2(
|
|
1208
|
+
async (reportId, body) => {
|
|
1209
|
+
setIsPending(true);
|
|
1210
|
+
setError(null);
|
|
1211
|
+
try {
|
|
1212
|
+
await reportAction(token, reportId, body);
|
|
1213
|
+
onSuccess == null ? void 0 : onSuccess();
|
|
1214
|
+
} catch (e) {
|
|
1215
|
+
const err = e instanceof Error ? e : new Error("Action failed");
|
|
1216
|
+
setError(err.message);
|
|
1217
|
+
onError == null ? void 0 : onError(err);
|
|
1218
|
+
} finally {
|
|
1219
|
+
setIsPending(false);
|
|
1220
|
+
}
|
|
1221
|
+
},
|
|
1222
|
+
[token, onSuccess, onError]
|
|
1223
|
+
);
|
|
1224
|
+
return {
|
|
1225
|
+
approve: (reportId) => run(reportId, { action: "label", label: "approved" }),
|
|
1226
|
+
reject: (reportId) => run(reportId, { action: "label", label: "rejected" }),
|
|
1227
|
+
close: (reportId) => run(reportId, { action: "close" }),
|
|
1228
|
+
reopen: (reportId) => run(reportId, { action: "reopen" }),
|
|
1229
|
+
label: (reportId, label) => run(reportId, { action: "label", label }),
|
|
1230
|
+
unlabel: (reportId, label) => run(reportId, { action: "unlabel", label }),
|
|
1231
|
+
isPending,
|
|
1232
|
+
error
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1187
1235
|
export {
|
|
1188
1236
|
GlitchgrabErrorBoundary,
|
|
1189
1237
|
GlitchgrabProvider,
|
|
@@ -1198,6 +1246,7 @@ export {
|
|
|
1198
1246
|
sanitizeUrl,
|
|
1199
1247
|
sendReport,
|
|
1200
1248
|
useGlitchgrab,
|
|
1249
|
+
useGlitchgrabActions,
|
|
1201
1250
|
useGlitchgrabReports
|
|
1202
1251
|
};
|
|
1203
1252
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.tsx","../src/error-boundary.tsx","../src/breadcrumbs.ts","../src/utils.ts","../src/report-button.tsx","../src/use-reports.ts"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useRef,\n useEffect,\n useCallback,\n useState,\n} from \"react\";\nimport type {\n GlitchgrabProviderProps,\n UseGlitchgrabReturn,\n ReportPayload,\n ReportResult,\n ReportType,\n} from \"./types\";\nimport { GlitchgrabErrorBoundary } from \"./error-boundary\";\nimport { sanitizeUrl, captureContext, sendReport, captureDeviceInfo } from \"./utils\";\nimport {\n initBreadcrumbs,\n addBreadcrumb as addBreadcrumbInternal,\n getBreadcrumbs,\n} from \"./breadcrumbs\";\n\nconst DEFAULT_BASE_URL = \"https://www.glitchgrab.dev\";\n\nconst GlitchgrabContext = createContext<UseGlitchgrabReturn | null>(null);\n\n/**\n * Hook to access Glitchgrab in your components.\n *\n * @example\n * ```tsx\n * const { reportBug, report, addBreadcrumb } = useGlitchgrab();\n *\n * // Report a bug\n * reportBug(\"Login button crashes on mobile\");\n *\n * // Report a feature request\n * report(\"FEATURE_REQUEST\", \"Add dark mode\");\n *\n * // Add a custom breadcrumb\n * addBreadcrumb(\"User clicked checkout\", { cartItems: \"3\" });\n * ```\n */\nexport function useGlitchgrab(): UseGlitchgrabReturn {\n const ctx = useContext(GlitchgrabContext);\n if (!ctx) {\n throw new Error(\"useGlitchgrab must be used within a GlitchgrabProvider\");\n }\n return ctx;\n}\n\nfunction GlitchgrabProviderInner({\n token,\n session,\n baseUrl,\n onError,\n onReportSent,\n breadcrumbs: enableBreadcrumbs = true,\n maxBreadcrumbs = 50,\n children,\n fallback,\n}: GlitchgrabProviderProps) {\n const visitedPagesRef = useRef<string[]>([]);\n\n // Initialize breadcrumbs\n useEffect(() => {\n if (enableBreadcrumbs) {\n initBreadcrumbs(maxBreadcrumbs);\n }\n }, [enableBreadcrumbs, maxBreadcrumbs]);\n\n // Track page visits\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n\n const trackPage = () => {\n try {\n const sanitized = sanitizeUrl(window.location.href);\n const pages = visitedPagesRef.current;\n if (pages[pages.length - 1] !== sanitized) {\n pages.push(sanitized);\n if (pages.length > 20) {\n pages.splice(0, pages.length - 20);\n }\n }\n } catch {\n // Silently fail\n }\n };\n\n trackPage();\n const handlePopState = () => trackPage();\n window.addEventListener(\"popstate\", handlePopState);\n\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPushState(...args);\n trackPage();\n };\n history.replaceState = function (...args) {\n origReplaceState(...args);\n trackPage();\n };\n\n return () => {\n window.removeEventListener(\"popstate\", handlePopState);\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n };\n } catch {\n // Never crash\n }\n }, []);\n\n // Unhandled errors and rejections — skip in development\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n if (process.env.NODE_ENV === \"development\") return;\n\n const handleError = (event: ErrorEvent) => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: event.message,\n errorStack: event.error?.stack,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n filename: event.filename ?? \"\",\n lineno: String(event.lineno ?? \"\"),\n colno: String(event.colno ?? \"\"),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && event.error) onError(event.error);\n } catch {\n // Silently fail\n }\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const reason = event.reason;\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: reason instanceof Error ? reason.message : String(reason),\n errorStack: reason instanceof Error ? reason.stack : undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n type: \"unhandledrejection\",\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && reason instanceof Error) onError(reason);\n } catch {\n // Silently fail\n }\n };\n\n window.addEventListener(\"error\", handleError);\n window.addEventListener(\"unhandledrejection\", handleRejection);\n\n return () => {\n window.removeEventListener(\"error\", handleError);\n window.removeEventListener(\"unhandledrejection\", handleRejection);\n };\n } catch {\n // Never crash\n }\n }, [token, baseUrl, onError, onReportSent]);\n\n const report = useCallback(\n async (\n type: ReportType,\n description: string,\n metadata?: Record<string, string>\n ): Promise<ReportResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_USER_REPORT\",\n type,\n description,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n ...metadata,\n },\n };\n const result = await sendReport(payload, baseUrl);\n if (result && onReportSent) onReportSent(result);\n return result;\n } catch {\n return null;\n }\n },\n [token, baseUrl, onReportSent]\n );\n\n const reportBug = useCallback(\n (description: string, metadata?: Record<string, string>) =>\n report(\"BUG\", description, metadata),\n [report]\n );\n\n const addBreadcrumb = useCallback(\n (message: string, data?: Record<string, string>) => {\n addBreadcrumbInternal(\"custom\", message, data);\n },\n []\n );\n\n return (\n <GlitchgrabContext.Provider\n value={{\n token,\n baseUrl: baseUrl ?? DEFAULT_BASE_URL,\n reportBug,\n report,\n addBreadcrumb,\n }}\n >\n <GlitchgrabErrorBoundary\n token={token}\n baseUrl={baseUrl}\n onError={onError}\n fallback={fallback}\n visitedPages={visitedPagesRef.current}\n >\n {children}\n </GlitchgrabErrorBoundary>\n </GlitchgrabContext.Provider>\n );\n}\n\nexport function GlitchgrabProvider(props: GlitchgrabProviderProps) {\n // No token = passthrough (SDK disabled)\n if (!props.token) return <>{props.children}</>;\n\n const resolvedProps = {\n ...props,\n baseUrl: props.baseUrl || DEFAULT_BASE_URL,\n };\n\n try {\n return <GlitchgrabProviderInner {...resolvedProps} />;\n } catch {\n return <>{props.children}</>;\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { ReportPayload } from \"./types\";\nimport { captureContext, sendReport } from \"./utils\";\n\ninterface ErrorBoundaryProps {\n token: string;\n baseUrl?: string;\n onError?: (error: Error) => void;\n fallback?: React.ReactNode;\n visitedPages: string[];\n children: React.ReactNode;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n}\n\nexport class GlitchgrabErrorBoundary extends React.Component<\n ErrorBoundaryProps,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): ErrorBoundaryState {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n try {\n const context = captureContext(this.props.visitedPages);\n\n const payload: ReportPayload = {\n token: this.props.token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: error.message,\n errorStack: error.stack,\n componentStack: errorInfo.componentStack ?? undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n },\n };\n\n sendReport(payload, this.props.baseUrl);\n\n if (this.props.onError) {\n this.props.onError(error);\n }\n } catch {\n // Never crash the host app\n }\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n // Re-render children — allows recovery from transient errors\n return this.props.children;\n }\n\n return this.props.children;\n }\n}\n","import type { Breadcrumb, BreadcrumbType } from \"./types\";\n\nconst MAX_DEFAULT = 50;\n\nlet breadcrumbs: Breadcrumb[] = [];\nlet maxBreadcrumbs = MAX_DEFAULT;\nlet initialized = false;\n\nexport function initBreadcrumbs(max?: number) {\n if (initialized) return;\n maxBreadcrumbs = max ?? MAX_DEFAULT;\n\n try {\n if (typeof window === \"undefined\") return;\n interceptConsole();\n interceptFetch();\n interceptNavigation();\n interceptClicks();\n initialized = true;\n } catch {\n // Never crash\n }\n}\n\nexport function addBreadcrumb(\n type: BreadcrumbType,\n message: string,\n data?: Record<string, string>\n) {\n try {\n breadcrumbs.push({\n type,\n message: message.slice(0, 200),\n timestamp: new Date().toISOString(),\n data,\n });\n if (breadcrumbs.length > maxBreadcrumbs) {\n breadcrumbs = breadcrumbs.slice(-maxBreadcrumbs);\n }\n } catch {\n // Never crash\n }\n}\n\nexport function getBreadcrumbs(): Breadcrumb[] {\n return [...breadcrumbs];\n}\n\nexport function clearBreadcrumbs() {\n breadcrumbs = [];\n}\n\n// ─── Console Interception ────────────────────────────────\n\nfunction interceptConsole() {\n const origLog = console.log;\n const origWarn = console.warn;\n const origError = console.error;\n\n console.log = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[log] ${argsToString(args)}`);\n origLog.apply(console, args);\n };\n\n console.warn = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[warn] ${argsToString(args)}`);\n origWarn.apply(console, args);\n };\n\n console.error = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[error] ${argsToString(args)}`);\n origError.apply(console, args);\n };\n}\n\nfunction argsToString(args: unknown[]): string {\n try {\n return args\n .map((a) => {\n if (typeof a === \"string\") return a;\n if (a instanceof Error) return a.message;\n try {\n return JSON.stringify(a);\n } catch {\n return String(a);\n }\n })\n .join(\" \")\n .slice(0, 200);\n } catch {\n return \"[unknown]\";\n }\n}\n\n// ─── Fetch Interception ──────────────────────────────────\n\nfunction interceptFetch() {\n const origFetch = window.fetch;\n\n window.fetch = async function (input, init) {\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input instanceof Request\n ? input.url\n : String(input);\n const method = init?.method ?? \"GET\";\n const start = Date.now();\n\n try {\n const response = await origFetch.apply(window, [input, init]);\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → ${response.status}`, {\n method,\n status: String(response.status),\n duration: `${Date.now() - start}ms`,\n });\n return response;\n } catch (err) {\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → FAILED`, {\n method,\n error: err instanceof Error ? err.message : \"unknown\",\n duration: `${Date.now() - start}ms`,\n });\n throw err;\n }\n };\n}\n\n// ─── Navigation Interception ─────────────────────────────\n\nfunction interceptNavigation() {\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPush(...args);\n addBreadcrumb(\"navigation\", `Navigate to ${window.location.pathname}`);\n };\n\n history.replaceState = function (...args) {\n origReplace(...args);\n addBreadcrumb(\"navigation\", `Replace to ${window.location.pathname}`);\n };\n\n window.addEventListener(\"popstate\", () => {\n addBreadcrumb(\"navigation\", `Back/Forward to ${window.location.pathname}`);\n });\n}\n\n// ─── Click Interception ──────────────────────────────────\n\nfunction interceptClicks() {\n document.addEventListener(\n \"click\",\n (e) => {\n try {\n const target = e.target as HTMLElement;\n const tag = target.tagName?.toLowerCase();\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(\" \")[0]}`\n : \"\";\n\n addBreadcrumb(\"click\", `Click ${tag}${id}${cls} \"${text}\"`);\n } catch {\n // Never crash\n }\n },\n { capture: true }\n );\n}\n","import type { ReportPayload, ReportResult, CapturedContext, DeviceInfo } from \"./types\";\nimport { getBreadcrumbs } from \"./breadcrumbs\";\n\nconst SENSITIVE_PARAMS = [\n \"token\", \"key\", \"secret\", \"password\", \"passwd\", \"auth\", \"authorization\",\n \"session\", \"sessionid\", \"session_id\", \"api_key\", \"apikey\", \"access_token\",\n \"refresh_token\", \"client_secret\", \"code\", \"state\", \"nonce\", \"credential\", \"private\",\n];\n\nexport function sanitizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n const params = new URLSearchParams(parsed.search);\n let modified = false;\n for (const key of Array.from(params.keys())) {\n if (SENSITIVE_PARAMS.some((s) => key.toLowerCase().includes(s))) {\n params.set(key, \"[REDACTED]\");\n modified = true;\n }\n }\n if (modified) parsed.search = params.toString();\n return parsed.toString();\n } catch {\n return url.split(\"?\")[0] ?? url;\n }\n}\n\nexport function captureDeviceInfo(): DeviceInfo | null {\n try {\n if (typeof window === \"undefined\") return null;\n return {\n screenWidth: screen.width,\n screenHeight: screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n platform: navigator.platform ?? \"unknown\",\n language: navigator.language ?? \"unknown\",\n online: navigator.onLine,\n colorScheme: window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\",\n devicePixelRatio: window.devicePixelRatio ?? 1,\n };\n } catch {\n return null;\n }\n}\n\nexport function captureContext(visitedPages: string[]): CapturedContext {\n try {\n return {\n url: sanitizeUrl(typeof window !== \"undefined\" ? window.location.href : \"\"),\n userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"\",\n timestamp: new Date().toISOString(),\n visitedPages: visitedPages.map(sanitizeUrl),\n breadcrumbs: getBreadcrumbs(),\n deviceInfo: captureDeviceInfo(),\n };\n } catch {\n return {\n url: \"\",\n userAgent: \"\",\n timestamp: new Date().toISOString(),\n visitedPages: [],\n breadcrumbs: [],\n deviceInfo: null,\n };\n }\n}\n\nconst DEFAULT_BASE_URL = \"https://www.glitchgrab.dev\";\nconst MAX_RETRIES = 3;\nconst RETRY_BASE_MS = 500;\n\n/**\n * Send a report and return the result.\n * Never throws — returns null on failure.\n */\nexport async function sendReport(\n payload: ReportPayload,\n baseUrl?: string\n): Promise<ReportResult | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/report`;\n const body = JSON.stringify(payload);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${payload.token}`,\n };\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n keepalive: true,\n });\n\n if (response.ok) {\n const data = (await response.json()) as { success: boolean; data?: ReportResult };\n return data.data ?? { success: data.success };\n }\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return null;\n }\n } catch {\n // Will retry\n }\n\n if (attempt < MAX_RETRIES - 1) {\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_BASE_MS * Math.pow(2, attempt))\n );\n }\n }\n\n // Fallback: sendBeacon (fire-and-forget, no result)\n if (typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n try {\n navigator.sendBeacon(url, new Blob([body], { type: \"application/json\" }));\n } catch {\n // Silently fail\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n","\"use client\";\n\nimport { useState, useRef, useEffect, type CSSProperties, type ReactNode } from \"react\";\n// @ts-expect-error react-dom types handled by host app\nimport { createPortal } from \"react-dom\";\nimport type { ReportButtonProps, UseGlitchgrabReturn } from \"./types\";\nimport { useGlitchgrab } from \"./provider\";\n\n/** Safe version of useGlitchgrab that returns null when outside provider */\nfunction useGlitchgrabSafe(): UseGlitchgrabReturn | null {\n try {\n return useGlitchgrab();\n } catch {\n return null;\n }\n}\n\n/** Detect if the host page uses a dark or light theme */\nfunction useIsDark(): boolean {\n if (typeof window === \"undefined\") return true;\n try {\n const bg = getComputedStyle(document.body).backgroundColor;\n const match = bg.match(/\\d+/g);\n if (match && match.length >= 3) {\n const [r, g, b] = match.map(Number);\n return (r * 299 + g * 587 + b * 114) / 1000 < 128;\n }\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n } catch {\n return true;\n }\n}\n\nfunction getTheme(dark: boolean) {\n return dark\n ? { bg: \"#1c1c1e\", bgSecondary: \"#27272a\", border: \"#2c2c2e\", text: \"#fafafa\", textMuted: \"#a1a1aa\", accent: \"#22d3ee\", accentText: \"#09090b\", inputBg: \"#27272a\", inputBorder: \"#3f3f46\" }\n : { bg: \"#ffffff\", bgSecondary: \"#f4f4f5\", border: \"#e4e4e7\", text: \"#18181b\", textMuted: \"#71717a\", accent: \"#0891b2\", accentText: \"#ffffff\", inputBg: \"#fafafa\", inputBorder: \"#d4d4d8\" };\n}\n\nexport function ReportButton({\n position = \"bottom-right\",\n label = \"Report Bug\",\n className,\n children,\n}: ReportButtonProps & {\n /** Render prop — receives { onClick, capturing } so you can use your own trigger button */\n children?: (props: { onClick: () => void; capturing: boolean }) => ReactNode;\n}) {\n const [capturing, setCapturing] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [description, setDescription] = useState(\"\");\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const [screenshot, setScreenshot] = useState<string | null>(null);\n const [previewOpen, setPreviewOpen] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const modalRef = useRef<HTMLDivElement>(null);\n const glitchgrab = useGlitchgrabSafe();\n\n // If no provider context, render nothing\n if (!glitchgrab) return null;\n\n const { reportBug } = glitchgrab;\n const isDark = useIsDark();\n const t = getTheme(isDark);\n\n const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => {\n setScreenshot(reader.result as string);\n };\n reader.readAsDataURL(file);\n e.target.value = \"\";\n };\n\n const retakeScreenshot = async () => {\n setPreviewOpen(false);\n setIsOpen(false);\n setScreenshot(null);\n // Small delay so the modal is gone before capture\n await new Promise((r) => setTimeout(r, 300));\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const canvas = await html2canvas(document.body, {\n scale: 0.5,\n logging: false,\n useCORS: true,\n allowTaint: true,\n });\n setScreenshot(canvas.toDataURL(\"image/jpeg\", 0.6));\n } catch {\n // silently fail\n }\n setIsOpen(true);\n };\n\n const handleOpen = async () => {\n setCapturing(true);\n setSubmitted(false);\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const canvas = await html2canvas(document.body, {\n scale: 0.5,\n logging: false,\n useCORS: true,\n allowTaint: true,\n });\n setScreenshot(canvas.toDataURL(\"image/jpeg\", 0.6));\n } catch {\n // screenshot failed — open without it\n }\n setCapturing(false);\n setIsOpen(true);\n };\n\n // Close modal on Escape key\n useEffect(() => {\n if (!isOpen) return;\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n if (previewOpen) setPreviewOpen(false);\n else setIsOpen(false);\n }\n };\n document.addEventListener(\"keydown\", handleEsc);\n return () => document.removeEventListener(\"keydown\", handleEsc);\n }, [isOpen, previewOpen]);\n\n const handleSubmit = async () => {\n try {\n if (!description.trim() || isSubmitting) return;\n\n setIsSubmitting(true);\n const result = await reportBug(description.trim(), screenshot ? { screenshot } : undefined);\n\n if (result) {\n setSubmitted(true);\n setDescription(\"\");\n setScreenshot(null);\n\n setTimeout(() => {\n setSubmitted(false);\n setIsOpen(false);\n }, 2000);\n }\n setIsSubmitting(false);\n } catch {\n setIsSubmitting(false);\n }\n };\n\n const isTop = position?.startsWith(\"top\") ?? false;\n const isLeft = position?.endsWith(\"left\") ?? false;\n\n const modalPositionStyles: CSSProperties = children\n ? {} // user controls positioning\n : {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"64px\" } : { bottom: \"64px\" }),\n };\n\n return (\n <>\n {/* Trigger: user's custom button OR default floating button */}\n {children ? (\n children({ onClick: handleOpen, capturing })\n ) : (\n <DefaultTrigger\n onClick={handleOpen}\n capturing={capturing}\n label={label}\n className={className}\n position={position}\n isLeft={isLeft}\n isTop={isTop}\n />\n )}\n\n {/* Report modal — rendered in portal to escape host stacking contexts */}\n {isOpen && typeof document !== \"undefined\" && createPortal(\n <div\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"rgba(0,0,0,0.5)\",\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n }}\n onClick={() => { if (!previewOpen) setIsOpen(false); }}\n >\n <div\n ref={modalRef}\n onClick={(e) => e.stopPropagation()}\n style={{\n position: children ? \"relative\" : \"fixed\",\n ...modalPositionStyles,\n zIndex: 2147483647,\n width: \"340px\",\n maxWidth: \"calc(100% - 32px)\",\n backgroundColor: t.bg,\n borderRadius: \"12px\",\n boxShadow:\n \"0 20px 60px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.1)\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n overflow: \"hidden\",\n color: t.text,\n isolation: \"isolate\",\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px 16px 12px\",\n borderBottom: `1px solid ${t.border}`,\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n fontSize: \"15px\",\n fontWeight: 600,\n color: t.text,\n }}\n >\n Report a Bug\n </span>\n <button\n type=\"button\"\n onClick={() => setIsOpen(false)}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Close\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" style={{ display: \"block\" }}>\n <path d=\"M4 4L12 12M12 4L4 12\" stroke={t.textMuted} strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Body */}\n <div style={{ padding: \"16px\" }}>\n {submitted ? (\n <div\n style={{\n textAlign: \"center\",\n padding: \"20px 0\",\n color: t.accent,\n fontSize: \"14px\",\n fontWeight: 500,\n }}\n >\n Bug report sent. Thank you!\n </div>\n ) : (\n <>\n {/* Screenshot preview */}\n {screenshot && (\n <div style={{ marginBottom: \"10px\", position: \"relative\" }}>\n <img\n src={screenshot}\n alt=\"Page screenshot\"\n onClick={() => setPreviewOpen(true)}\n style={{\n width: \"100%\",\n borderRadius: \"6px\",\n border: `1px solid ${t.border}`,\n maxHeight: \"120px\",\n objectFit: \"cover\",\n objectPosition: \"top\",\n cursor: \"pointer\",\n }}\n />\n <button\n type=\"button\"\n onClick={() => setScreenshot(null)}\n style={{\n position: \"absolute\",\n top: \"4px\",\n right: \"4px\",\n background: \"rgba(0,0,0,0.6)\",\n border: \"none\",\n borderRadius: \"50%\",\n width: \"20px\",\n height: \"20px\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Remove screenshot\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M1 1L9 9M9 1L1 9\" stroke=\"#fff\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n </button>\n <div\n style={{\n position: \"absolute\",\n bottom: \"4px\",\n left: \"6px\",\n right: \"6px\",\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n background: \"rgba(0,0,0,0.6)\",\n color: \"#fff\",\n fontSize: \"10px\",\n padding: \"2px 6px\",\n borderRadius: \"4px\",\n }}\n >\n Screenshot ({Math.round(screenshot.length * 0.75 / 1024)}KB) — click to preview\n </span>\n <div style={{ display: \"flex\", gap: \"4px\" }}>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n style={{\n background: t.accent,\n color: t.accentText,\n fontSize: \"10px\",\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontWeight: 600,\n }}\n >\n Upload\n </button>\n <button\n type=\"button\"\n onClick={retakeScreenshot}\n style={{\n background: t.accent,\n color: t.accentText,\n fontSize: \"10px\",\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontWeight: 600,\n }}\n >\n Retake\n </button>\n </div>\n </div>\n </div>\n )}\n {!screenshot && !submitted && (\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n style={{\n marginBottom: \"10px\",\n padding: \"10px\",\n borderRadius: \"6px\",\n border: `1px dashed ${t.inputBorder}`,\n textAlign: \"center\",\n fontSize: \"11px\",\n color: t.textMuted,\n width: \"100%\",\n background: \"none\",\n cursor: \"pointer\",\n }}\n >\n Click to upload a screenshot\n </button>\n )}\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe what went wrong...\"\n style={{\n width: \"100%\",\n minHeight: \"100px\",\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n fontSize: \"14px\",\n fontFamily: \"inherit\",\n resize: \"vertical\",\n outline: \"none\",\n boxSizing: \"border-box\",\n color: t.text,\n backgroundColor: t.inputBg,\n }}\n onFocus={(e) => {\n (e.target as HTMLTextAreaElement).style.borderColor = t.accent;\n }}\n onBlur={(e) => {\n (e.target as HTMLTextAreaElement).style.borderColor = t.inputBorder;\n }}\n autoFocus\n />\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!description.trim() || isSubmitting}\n style={{\n marginTop: \"12px\",\n width: \"100%\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor:\n !description.trim() || isSubmitting\n ? t.bgSecondary\n : t.accent,\n color:\n !description.trim() || isSubmitting\n ? t.textMuted\n : t.accentText,\n fontSize: \"14px\",\n fontWeight: 600,\n cursor:\n !description.trim() || isSubmitting\n ? \"not-allowed\"\n : \"pointer\",\n fontFamily: \"inherit\",\n transition: \"background-color 0.15s ease\",\n }}\n >\n {isSubmitting ? \"Sending...\" : \"Send Report\"}\n </button>\n </>\n )}\n </div>\n\n {/* Footer */}\n <div\n style={{\n padding: \"8px 16px 10px\",\n borderTop: `1px solid ${t.border}`,\n textAlign: \"center\",\n }}\n >\n <span style={{ fontSize: \"11px\", color: t.textMuted }}>\n Powered by Glitchgrab\n </span>\n </div>\n </div>\n </div>,\n document.body\n )}\n\n {/* Hidden file input for screenshot upload */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileUpload}\n style={{ display: \"none\" }}\n />\n\n {/* Full-screen screenshot preview */}\n {previewOpen && screenshot && typeof document !== \"undefined\" && createPortal(\n <div\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.85)\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n cursor: \"pointer\",\n }}\n onClick={(e) => { e.stopPropagation(); setPreviewOpen(false); }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n <img\n src={screenshot}\n alt=\"Screenshot preview\"\n onClick={(e) => e.stopPropagation()}\n style={{\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 80px)\",\n borderRadius: \"8px\",\n objectFit: \"contain\",\n cursor: \"default\",\n }}\n />\n <span\n style={{\n marginTop: \"12px\",\n color: t.textMuted,\n fontSize: \"12px\",\n }}\n >\n Click outside to close\n </span>\n </div>,\n document.body\n )}\n </>\n );\n}\n\n/** Default floating trigger button (used when no children provided) */\nfunction DefaultTrigger({\n onClick,\n capturing,\n label,\n className,\n position,\n isLeft,\n isTop,\n}: {\n onClick: () => void;\n capturing: boolean;\n label: string;\n className?: string;\n position?: string;\n isLeft: boolean;\n isTop: boolean;\n}) {\n const positionStyles: CSSProperties = {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"16px\" } : { bottom: \"16px\" }),\n };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={capturing}\n className={className}\n style={{\n position: \"fixed\",\n ...positionStyles,\n zIndex: 99999,\n padding: \"10px 18px\",\n borderRadius: \"24px\",\n border: \"none\",\n backgroundColor: \"#18181b\",\n color: \"#fafafa\",\n fontSize: \"14px\",\n fontWeight: 500,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n cursor: capturing ? \"wait\" : \"pointer\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.15s ease, box-shadow 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n opacity: capturing ? 0.7 : 1,\n }}\n onMouseEnter={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1)\";\n }}\n aria-label={label}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n >\n <path\n d=\"M8 1C4.134 1 1 4.134 1 8s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zm.75-3.5a.75.75 0 01-1.5 0V5a.75.75 0 011.5 0v5z\"\n fill=\"currentColor\"\n />\n </svg>\n {capturing ? \"Capturing...\" : label}\n </button>\n );\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\n\ninterface GlitchgrabReport {\n id: string;\n source: string;\n status: string;\n rawInput: string | null;\n reporterPrimaryKey: string;\n reporterName: string;\n reporterEmail: string | null;\n reporterPhone: string | null;\n pageUrl: string | null;\n createdAt: string;\n issue: {\n githubNumber: number;\n githubUrl: string;\n title: string;\n labels: string[];\n severity: string | null;\n githubState: string | null;\n } | null;\n}\n\nconst BASE_URL = \"https://www.glitchgrab.dev\";\n\n/**\n * Hook to fetch bug reports for a specific user.\n *\n * ```tsx\n * const { reports, isLoading, error, refetch } = useGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * });\n * ```\n */\nexport function useGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n /** Max results (default 100, max 100) */\n limit?: number;\n}): {\n reports: GlitchgrabReport[];\n isLoading: boolean;\n isFetching: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n} {\n const [reports, setReports] = useState<GlitchgrabReport[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fetchReports = useCallback(async () => {\n if (!token || !userId) {\n setIsLoading(false);\n return;\n }\n\n setIsFetching(true);\n setError(null);\n\n try {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n\n if (data.success) {\n setReports(data.data ?? []);\n } else {\n setError(data.error ?? \"Failed to fetch reports\");\n }\n } catch {\n setError(\"Network error\");\n } finally {\n setIsLoading(false);\n setIsFetching(false);\n }\n }, [token, userId, limit]);\n\n useEffect(() => {\n fetchReports();\n }, [fetchReports]);\n\n return { reports, isLoading, isFetching, error, refetch: fetchReports };\n}\n\n/**\n * Standalone fetcher — use with TanStack Query or any data fetching library.\n *\n * ```tsx\n * const { data } = useQuery({\n * queryKey: [\"glitchgrab-reports\", userId],\n * queryFn: () => fetchGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * }),\n * });\n * ```\n */\nexport async function fetchGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n limit?: number;\n}): Promise<GlitchgrabReport[]> {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n if (!data.success) throw new Error(data.error ?? \"Failed to fetch reports\");\n return data.data ?? [];\n}\n"],"mappings":"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","names":["e","DEFAULT_BASE_URL","maxBreadcrumbs","addBreadcrumb","useState","useRef","useEffect","Fragment","jsx","useState","useRef","_a","useEffect","useState","useEffect","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider.tsx","../src/error-boundary.tsx","../src/breadcrumbs.ts","../src/utils.ts","../src/report-button.tsx","../src/use-reports.ts"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useRef,\n useEffect,\n useCallback,\n useState,\n} from \"react\";\nimport type {\n GlitchgrabProviderProps,\n UseGlitchgrabReturn,\n ReportPayload,\n ReportResult,\n ReportType,\n} from \"./types\";\nimport { GlitchgrabErrorBoundary } from \"./error-boundary\";\nimport { sanitizeUrl, captureContext, sendReport, captureDeviceInfo } from \"./utils\";\nimport {\n initBreadcrumbs,\n addBreadcrumb as addBreadcrumbInternal,\n getBreadcrumbs,\n} from \"./breadcrumbs\";\n\nconst DEFAULT_BASE_URL = \"https://www.glitchgrab.dev\";\n\nconst GlitchgrabContext = createContext<UseGlitchgrabReturn | null>(null);\n\n/**\n * Hook to access Glitchgrab in your components.\n *\n * @example\n * ```tsx\n * const { reportBug, report, addBreadcrumb } = useGlitchgrab();\n *\n * // Report a bug\n * reportBug(\"Login button crashes on mobile\");\n *\n * // Report a feature request\n * report(\"FEATURE_REQUEST\", \"Add dark mode\");\n *\n * // Add a custom breadcrumb\n * addBreadcrumb(\"User clicked checkout\", { cartItems: \"3\" });\n * ```\n */\nexport function useGlitchgrab(): UseGlitchgrabReturn {\n const ctx = useContext(GlitchgrabContext);\n if (!ctx) {\n throw new Error(\"useGlitchgrab must be used within a GlitchgrabProvider\");\n }\n return ctx;\n}\n\nfunction GlitchgrabProviderInner({\n token,\n session,\n baseUrl,\n onError,\n onReportSent,\n breadcrumbs: enableBreadcrumbs = true,\n maxBreadcrumbs = 50,\n children,\n fallback,\n}: GlitchgrabProviderProps) {\n const visitedPagesRef = useRef<string[]>([]);\n\n // Initialize breadcrumbs\n useEffect(() => {\n if (enableBreadcrumbs) {\n initBreadcrumbs(maxBreadcrumbs);\n }\n }, [enableBreadcrumbs, maxBreadcrumbs]);\n\n // Track page visits\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n\n const trackPage = () => {\n try {\n const sanitized = sanitizeUrl(window.location.href);\n const pages = visitedPagesRef.current;\n if (pages[pages.length - 1] !== sanitized) {\n pages.push(sanitized);\n if (pages.length > 20) {\n pages.splice(0, pages.length - 20);\n }\n }\n } catch {\n // Silently fail\n }\n };\n\n trackPage();\n const handlePopState = () => trackPage();\n window.addEventListener(\"popstate\", handlePopState);\n\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPushState(...args);\n trackPage();\n };\n history.replaceState = function (...args) {\n origReplaceState(...args);\n trackPage();\n };\n\n return () => {\n window.removeEventListener(\"popstate\", handlePopState);\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n };\n } catch {\n // Never crash\n }\n }, []);\n\n // Unhandled errors and rejections — skip in development\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n if (process.env.NODE_ENV === \"development\") return;\n\n const handleError = (event: ErrorEvent) => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: event.message,\n errorStack: event.error?.stack,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n filename: event.filename ?? \"\",\n lineno: String(event.lineno ?? \"\"),\n colno: String(event.colno ?? \"\"),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && event.error) onError(event.error);\n } catch {\n // Silently fail\n }\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const reason = event.reason;\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: reason instanceof Error ? reason.message : String(reason),\n errorStack: reason instanceof Error ? reason.stack : undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n type: \"unhandledrejection\",\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && reason instanceof Error) onError(reason);\n } catch {\n // Silently fail\n }\n };\n\n window.addEventListener(\"error\", handleError);\n window.addEventListener(\"unhandledrejection\", handleRejection);\n\n return () => {\n window.removeEventListener(\"error\", handleError);\n window.removeEventListener(\"unhandledrejection\", handleRejection);\n };\n } catch {\n // Never crash\n }\n }, [token, baseUrl, onError, onReportSent]);\n\n const report = useCallback(\n async (\n type: ReportType,\n description: string,\n metadata?: Record<string, string>\n ): Promise<ReportResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_USER_REPORT\",\n type,\n description,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n ...metadata,\n },\n };\n const result = await sendReport(payload, baseUrl);\n if (result && onReportSent) onReportSent(result);\n return result;\n } catch {\n return null;\n }\n },\n [token, baseUrl, onReportSent]\n );\n\n const reportBug = useCallback(\n (description: string, metadata?: Record<string, string>) =>\n report(\"BUG\", description, metadata),\n [report]\n );\n\n const addBreadcrumb = useCallback(\n (message: string, data?: Record<string, string>) => {\n addBreadcrumbInternal(\"custom\", message, data);\n },\n []\n );\n\n return (\n <GlitchgrabContext.Provider\n value={{\n token,\n baseUrl: baseUrl ?? DEFAULT_BASE_URL,\n reportBug,\n report,\n addBreadcrumb,\n }}\n >\n <GlitchgrabErrorBoundary\n token={token}\n baseUrl={baseUrl}\n onError={onError}\n fallback={fallback}\n visitedPages={visitedPagesRef.current}\n >\n {children}\n </GlitchgrabErrorBoundary>\n </GlitchgrabContext.Provider>\n );\n}\n\nexport function GlitchgrabProvider(props: GlitchgrabProviderProps) {\n // No token = passthrough (SDK disabled)\n if (!props.token) return <>{props.children}</>;\n\n const resolvedProps = {\n ...props,\n baseUrl: props.baseUrl || DEFAULT_BASE_URL,\n };\n\n try {\n return <GlitchgrabProviderInner {...resolvedProps} />;\n } catch {\n return <>{props.children}</>;\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { ReportPayload } from \"./types\";\nimport { captureContext, sendReport } from \"./utils\";\n\ninterface ErrorBoundaryProps {\n token: string;\n baseUrl?: string;\n onError?: (error: Error) => void;\n fallback?: React.ReactNode;\n visitedPages: string[];\n children: React.ReactNode;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n}\n\nexport class GlitchgrabErrorBoundary extends React.Component<\n ErrorBoundaryProps,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): ErrorBoundaryState {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n try {\n const context = captureContext(this.props.visitedPages);\n\n const payload: ReportPayload = {\n token: this.props.token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: error.message,\n errorStack: error.stack,\n componentStack: errorInfo.componentStack ?? undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n },\n };\n\n sendReport(payload, this.props.baseUrl);\n\n if (this.props.onError) {\n this.props.onError(error);\n }\n } catch {\n // Never crash the host app\n }\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n // Re-render children — allows recovery from transient errors\n return this.props.children;\n }\n\n return this.props.children;\n }\n}\n","import type { Breadcrumb, BreadcrumbType } from \"./types\";\n\nconst MAX_DEFAULT = 50;\n\nlet breadcrumbs: Breadcrumb[] = [];\nlet maxBreadcrumbs = MAX_DEFAULT;\nlet initialized = false;\n\nexport function initBreadcrumbs(max?: number) {\n if (initialized) return;\n maxBreadcrumbs = max ?? MAX_DEFAULT;\n\n try {\n if (typeof window === \"undefined\") return;\n interceptConsole();\n interceptFetch();\n interceptNavigation();\n interceptClicks();\n initialized = true;\n } catch {\n // Never crash\n }\n}\n\nexport function addBreadcrumb(\n type: BreadcrumbType,\n message: string,\n data?: Record<string, string>\n) {\n try {\n breadcrumbs.push({\n type,\n message: message.slice(0, 200),\n timestamp: new Date().toISOString(),\n data,\n });\n if (breadcrumbs.length > maxBreadcrumbs) {\n breadcrumbs = breadcrumbs.slice(-maxBreadcrumbs);\n }\n } catch {\n // Never crash\n }\n}\n\nexport function getBreadcrumbs(): Breadcrumb[] {\n return [...breadcrumbs];\n}\n\nexport function clearBreadcrumbs() {\n breadcrumbs = [];\n}\n\n// ─── Console Interception ────────────────────────────────\n\nfunction interceptConsole() {\n const origLog = console.log;\n const origWarn = console.warn;\n const origError = console.error;\n\n console.log = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[log] ${argsToString(args)}`);\n origLog.apply(console, args);\n };\n\n console.warn = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[warn] ${argsToString(args)}`);\n origWarn.apply(console, args);\n };\n\n console.error = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[error] ${argsToString(args)}`);\n origError.apply(console, args);\n };\n}\n\nfunction argsToString(args: unknown[]): string {\n try {\n return args\n .map((a) => {\n if (typeof a === \"string\") return a;\n if (a instanceof Error) return a.message;\n try {\n return JSON.stringify(a);\n } catch {\n return String(a);\n }\n })\n .join(\" \")\n .slice(0, 200);\n } catch {\n return \"[unknown]\";\n }\n}\n\n// ─── Fetch Interception ──────────────────────────────────\n\nfunction interceptFetch() {\n const origFetch = window.fetch;\n\n window.fetch = async function (input, init) {\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input instanceof Request\n ? input.url\n : String(input);\n const method = init?.method ?? \"GET\";\n const start = Date.now();\n\n try {\n const response = await origFetch.apply(window, [input, init]);\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → ${response.status}`, {\n method,\n status: String(response.status),\n duration: `${Date.now() - start}ms`,\n });\n return response;\n } catch (err) {\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → FAILED`, {\n method,\n error: err instanceof Error ? err.message : \"unknown\",\n duration: `${Date.now() - start}ms`,\n });\n throw err;\n }\n };\n}\n\n// ─── Navigation Interception ─────────────────────────────\n\nfunction interceptNavigation() {\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPush(...args);\n addBreadcrumb(\"navigation\", `Navigate to ${window.location.pathname}`);\n };\n\n history.replaceState = function (...args) {\n origReplace(...args);\n addBreadcrumb(\"navigation\", `Replace to ${window.location.pathname}`);\n };\n\n window.addEventListener(\"popstate\", () => {\n addBreadcrumb(\"navigation\", `Back/Forward to ${window.location.pathname}`);\n });\n}\n\n// ─── Click Interception ──────────────────────────────────\n\nfunction interceptClicks() {\n document.addEventListener(\n \"click\",\n (e) => {\n try {\n const target = e.target as HTMLElement;\n const tag = target.tagName?.toLowerCase();\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(\" \")[0]}`\n : \"\";\n\n addBreadcrumb(\"click\", `Click ${tag}${id}${cls} \"${text}\"`);\n } catch {\n // Never crash\n }\n },\n { capture: true }\n );\n}\n","import type { ReportPayload, ReportResult, CapturedContext, DeviceInfo } from \"./types\";\nimport { getBreadcrumbs } from \"./breadcrumbs\";\n\nconst SENSITIVE_PARAMS = [\n \"token\", \"key\", \"secret\", \"password\", \"passwd\", \"auth\", \"authorization\",\n \"session\", \"sessionid\", \"session_id\", \"api_key\", \"apikey\", \"access_token\",\n \"refresh_token\", \"client_secret\", \"code\", \"state\", \"nonce\", \"credential\", \"private\",\n];\n\nexport function sanitizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n const params = new URLSearchParams(parsed.search);\n let modified = false;\n for (const key of Array.from(params.keys())) {\n if (SENSITIVE_PARAMS.some((s) => key.toLowerCase().includes(s))) {\n params.set(key, \"[REDACTED]\");\n modified = true;\n }\n }\n if (modified) parsed.search = params.toString();\n return parsed.toString();\n } catch {\n return url.split(\"?\")[0] ?? url;\n }\n}\n\nexport function captureDeviceInfo(): DeviceInfo | null {\n try {\n if (typeof window === \"undefined\") return null;\n return {\n screenWidth: screen.width,\n screenHeight: screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n platform: navigator.platform ?? \"unknown\",\n language: navigator.language ?? \"unknown\",\n online: navigator.onLine,\n colorScheme: window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\",\n devicePixelRatio: window.devicePixelRatio ?? 1,\n };\n } catch {\n return null;\n }\n}\n\nexport function captureContext(visitedPages: string[]): CapturedContext {\n try {\n return {\n url: sanitizeUrl(typeof window !== \"undefined\" ? window.location.href : \"\"),\n userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"\",\n timestamp: new Date().toISOString(),\n visitedPages: visitedPages.map(sanitizeUrl),\n breadcrumbs: getBreadcrumbs(),\n deviceInfo: captureDeviceInfo(),\n };\n } catch {\n return {\n url: \"\",\n userAgent: \"\",\n timestamp: new Date().toISOString(),\n visitedPages: [],\n breadcrumbs: [],\n deviceInfo: null,\n };\n }\n}\n\nconst DEFAULT_BASE_URL = \"https://www.glitchgrab.dev\";\nconst MAX_RETRIES = 3;\nconst RETRY_BASE_MS = 500;\n\n/**\n * Send a report and return the result.\n * Never throws — returns null on failure.\n */\nexport async function sendReport(\n payload: ReportPayload,\n baseUrl?: string\n): Promise<ReportResult | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/report`;\n const body = JSON.stringify(payload);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${payload.token}`,\n };\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n keepalive: true,\n });\n\n if (response.ok) {\n const data = (await response.json()) as { success: boolean; data?: ReportResult };\n return data.data ?? { success: data.success };\n }\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return null;\n }\n } catch {\n // Will retry\n }\n\n if (attempt < MAX_RETRIES - 1) {\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_BASE_MS * Math.pow(2, attempt))\n );\n }\n }\n\n // Fallback: sendBeacon (fire-and-forget, no result)\n if (typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n try {\n navigator.sendBeacon(url, new Blob([body], { type: \"application/json\" }));\n } catch {\n // Silently fail\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n","\"use client\";\n\nimport { useState, useRef, useEffect, type CSSProperties, type ReactNode } from \"react\";\n// @ts-expect-error react-dom types handled by host app\nimport { createPortal } from \"react-dom\";\nimport type { ReportButtonProps, UseGlitchgrabReturn } from \"./types\";\nimport { useGlitchgrab } from \"./provider\";\n\n/** Safe version of useGlitchgrab that returns null when outside provider */\nfunction useGlitchgrabSafe(): UseGlitchgrabReturn | null {\n try {\n return useGlitchgrab();\n } catch {\n return null;\n }\n}\n\n/** Detect if the host page uses a dark or light theme */\nfunction useIsDark(): boolean {\n if (typeof window === \"undefined\") return true;\n try {\n const bg = getComputedStyle(document.body).backgroundColor;\n const match = bg.match(/\\d+/g);\n if (match && match.length >= 3) {\n const [r, g, b] = match.map(Number);\n return (r * 299 + g * 587 + b * 114) / 1000 < 128;\n }\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n } catch {\n return true;\n }\n}\n\nfunction getTheme(dark: boolean) {\n return dark\n ? { bg: \"#1c1c1e\", bgSecondary: \"#27272a\", border: \"#2c2c2e\", text: \"#fafafa\", textMuted: \"#a1a1aa\", accent: \"#22d3ee\", accentText: \"#09090b\", inputBg: \"#27272a\", inputBorder: \"#3f3f46\" }\n : { bg: \"#ffffff\", bgSecondary: \"#f4f4f5\", border: \"#e4e4e7\", text: \"#18181b\", textMuted: \"#71717a\", accent: \"#0891b2\", accentText: \"#ffffff\", inputBg: \"#fafafa\", inputBorder: \"#d4d4d8\" };\n}\n\nexport function ReportButton({\n position = \"bottom-right\",\n label = \"Report Bug\",\n className,\n children,\n}: ReportButtonProps & {\n /** Render prop — receives { onClick, capturing } so you can use your own trigger button */\n children?: (props: { onClick: () => void; capturing: boolean }) => ReactNode;\n}) {\n const [capturing, setCapturing] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [description, setDescription] = useState(\"\");\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const [screenshot, setScreenshot] = useState<string | null>(null);\n const [previewOpen, setPreviewOpen] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const modalRef = useRef<HTMLDivElement>(null);\n const glitchgrab = useGlitchgrabSafe();\n\n // If no provider context, render nothing\n if (!glitchgrab) return null;\n\n const { reportBug } = glitchgrab;\n const isDark = useIsDark();\n const t = getTheme(isDark);\n\n const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => {\n setScreenshot(reader.result as string);\n };\n reader.readAsDataURL(file);\n e.target.value = \"\";\n };\n\n const retakeScreenshot = async () => {\n setPreviewOpen(false);\n setIsOpen(false);\n setScreenshot(null);\n // Small delay so the modal is gone before capture\n await new Promise((r) => setTimeout(r, 300));\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const canvas = await html2canvas(document.body, {\n scale: 0.5,\n logging: false,\n useCORS: true,\n allowTaint: true,\n });\n setScreenshot(canvas.toDataURL(\"image/jpeg\", 0.6));\n } catch {\n // silently fail\n }\n setIsOpen(true);\n };\n\n const handleOpen = async () => {\n setCapturing(true);\n setSubmitted(false);\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const canvas = await html2canvas(document.body, {\n scale: 0.5,\n logging: false,\n useCORS: true,\n allowTaint: true,\n });\n setScreenshot(canvas.toDataURL(\"image/jpeg\", 0.6));\n } catch {\n // screenshot failed — open without it\n }\n setCapturing(false);\n setIsOpen(true);\n };\n\n // Close modal on Escape key\n useEffect(() => {\n if (!isOpen) return;\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n if (previewOpen) setPreviewOpen(false);\n else setIsOpen(false);\n }\n };\n document.addEventListener(\"keydown\", handleEsc);\n return () => document.removeEventListener(\"keydown\", handleEsc);\n }, [isOpen, previewOpen]);\n\n const handleSubmit = async () => {\n try {\n if (!description.trim() || isSubmitting) return;\n\n setIsSubmitting(true);\n const result = await reportBug(description.trim(), screenshot ? { screenshot } : undefined);\n\n if (result) {\n setSubmitted(true);\n setDescription(\"\");\n setScreenshot(null);\n\n setTimeout(() => {\n setSubmitted(false);\n setIsOpen(false);\n }, 2000);\n }\n setIsSubmitting(false);\n } catch {\n setIsSubmitting(false);\n }\n };\n\n const isTop = position?.startsWith(\"top\") ?? false;\n const isLeft = position?.endsWith(\"left\") ?? false;\n\n const modalPositionStyles: CSSProperties = children\n ? {} // user controls positioning\n : {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"64px\" } : { bottom: \"64px\" }),\n };\n\n return (\n <>\n {/* Trigger: user's custom button OR default floating button */}\n {children ? (\n children({ onClick: handleOpen, capturing })\n ) : (\n <DefaultTrigger\n onClick={handleOpen}\n capturing={capturing}\n label={label}\n className={className}\n position={position}\n isLeft={isLeft}\n isTop={isTop}\n />\n )}\n\n {/* Report modal — rendered in portal to escape host stacking contexts */}\n {isOpen && typeof document !== \"undefined\" && createPortal(\n <div\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"rgba(0,0,0,0.5)\",\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n }}\n onClick={() => { if (!previewOpen) setIsOpen(false); }}\n >\n <div\n ref={modalRef}\n onClick={(e) => e.stopPropagation()}\n style={{\n position: children ? \"relative\" : \"fixed\",\n ...modalPositionStyles,\n zIndex: 2147483647,\n width: \"340px\",\n maxWidth: \"calc(100% - 32px)\",\n backgroundColor: t.bg,\n borderRadius: \"12px\",\n boxShadow:\n \"0 20px 60px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.1)\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n overflow: \"hidden\",\n color: t.text,\n isolation: \"isolate\",\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px 16px 12px\",\n borderBottom: `1px solid ${t.border}`,\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n fontSize: \"15px\",\n fontWeight: 600,\n color: t.text,\n }}\n >\n Report a Bug\n </span>\n <button\n type=\"button\"\n onClick={() => setIsOpen(false)}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Close\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" style={{ display: \"block\" }}>\n <path d=\"M4 4L12 12M12 4L4 12\" stroke={t.textMuted} strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Body */}\n <div style={{ padding: \"16px\" }}>\n {submitted ? (\n <div\n style={{\n textAlign: \"center\",\n padding: \"20px 0\",\n color: t.accent,\n fontSize: \"14px\",\n fontWeight: 500,\n }}\n >\n Bug report sent. Thank you!\n </div>\n ) : (\n <>\n {/* Screenshot preview */}\n {screenshot && (\n <div style={{ marginBottom: \"10px\", position: \"relative\" }}>\n <img\n src={screenshot}\n alt=\"Page screenshot\"\n onClick={() => setPreviewOpen(true)}\n style={{\n width: \"100%\",\n borderRadius: \"6px\",\n border: `1px solid ${t.border}`,\n maxHeight: \"120px\",\n objectFit: \"cover\",\n objectPosition: \"top\",\n cursor: \"pointer\",\n }}\n />\n <button\n type=\"button\"\n onClick={() => setScreenshot(null)}\n style={{\n position: \"absolute\",\n top: \"4px\",\n right: \"4px\",\n background: \"rgba(0,0,0,0.6)\",\n border: \"none\",\n borderRadius: \"50%\",\n width: \"20px\",\n height: \"20px\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Remove screenshot\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M1 1L9 9M9 1L1 9\" stroke=\"#fff\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n </button>\n <div\n style={{\n position: \"absolute\",\n bottom: \"4px\",\n left: \"6px\",\n right: \"6px\",\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n background: \"rgba(0,0,0,0.6)\",\n color: \"#fff\",\n fontSize: \"10px\",\n padding: \"2px 6px\",\n borderRadius: \"4px\",\n }}\n >\n Screenshot ({Math.round(screenshot.length * 0.75 / 1024)}KB) — click to preview\n </span>\n <div style={{ display: \"flex\", gap: \"4px\" }}>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n style={{\n background: t.accent,\n color: t.accentText,\n fontSize: \"10px\",\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontWeight: 600,\n }}\n >\n Upload\n </button>\n <button\n type=\"button\"\n onClick={retakeScreenshot}\n style={{\n background: t.accent,\n color: t.accentText,\n fontSize: \"10px\",\n padding: \"3px 8px\",\n borderRadius: \"4px\",\n border: \"none\",\n cursor: \"pointer\",\n fontWeight: 600,\n }}\n >\n Retake\n </button>\n </div>\n </div>\n </div>\n )}\n {!screenshot && !submitted && (\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n style={{\n marginBottom: \"10px\",\n padding: \"10px\",\n borderRadius: \"6px\",\n border: `1px dashed ${t.inputBorder}`,\n textAlign: \"center\",\n fontSize: \"11px\",\n color: t.textMuted,\n width: \"100%\",\n background: \"none\",\n cursor: \"pointer\",\n }}\n >\n Click to upload a screenshot\n </button>\n )}\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Describe what went wrong...\"\n style={{\n width: \"100%\",\n minHeight: \"100px\",\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n fontSize: \"14px\",\n fontFamily: \"inherit\",\n resize: \"vertical\",\n outline: \"none\",\n boxSizing: \"border-box\",\n color: t.text,\n backgroundColor: t.inputBg,\n }}\n onFocus={(e) => {\n (e.target as HTMLTextAreaElement).style.borderColor = t.accent;\n }}\n onBlur={(e) => {\n (e.target as HTMLTextAreaElement).style.borderColor = t.inputBorder;\n }}\n autoFocus\n />\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!description.trim() || isSubmitting}\n style={{\n marginTop: \"12px\",\n width: \"100%\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor:\n !description.trim() || isSubmitting\n ? t.bgSecondary\n : t.accent,\n color:\n !description.trim() || isSubmitting\n ? t.textMuted\n : t.accentText,\n fontSize: \"14px\",\n fontWeight: 600,\n cursor:\n !description.trim() || isSubmitting\n ? \"not-allowed\"\n : \"pointer\",\n fontFamily: \"inherit\",\n transition: \"background-color 0.15s ease\",\n }}\n >\n {isSubmitting ? \"Sending...\" : \"Send Report\"}\n </button>\n </>\n )}\n </div>\n\n {/* Footer */}\n <div\n style={{\n padding: \"8px 16px 10px\",\n borderTop: `1px solid ${t.border}`,\n textAlign: \"center\",\n }}\n >\n <span style={{ fontSize: \"11px\", color: t.textMuted }}>\n Powered by Glitchgrab\n </span>\n </div>\n </div>\n </div>,\n document.body\n )}\n\n {/* Hidden file input for screenshot upload */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileUpload}\n style={{ display: \"none\" }}\n />\n\n {/* Full-screen screenshot preview */}\n {previewOpen && screenshot && typeof document !== \"undefined\" && createPortal(\n <div\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.85)\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n cursor: \"pointer\",\n }}\n onClick={(e) => { e.stopPropagation(); setPreviewOpen(false); }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n <img\n src={screenshot}\n alt=\"Screenshot preview\"\n onClick={(e) => e.stopPropagation()}\n style={{\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 80px)\",\n borderRadius: \"8px\",\n objectFit: \"contain\",\n cursor: \"default\",\n }}\n />\n <span\n style={{\n marginTop: \"12px\",\n color: t.textMuted,\n fontSize: \"12px\",\n }}\n >\n Click outside to close\n </span>\n </div>,\n document.body\n )}\n </>\n );\n}\n\n/** Default floating trigger button (used when no children provided) */\nfunction DefaultTrigger({\n onClick,\n capturing,\n label,\n className,\n position,\n isLeft,\n isTop,\n}: {\n onClick: () => void;\n capturing: boolean;\n label: string;\n className?: string;\n position?: string;\n isLeft: boolean;\n isTop: boolean;\n}) {\n const positionStyles: CSSProperties = {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"16px\" } : { bottom: \"16px\" }),\n };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={capturing}\n className={className}\n style={{\n position: \"fixed\",\n ...positionStyles,\n zIndex: 99999,\n padding: \"10px 18px\",\n borderRadius: \"24px\",\n border: \"none\",\n backgroundColor: \"#18181b\",\n color: \"#fafafa\",\n fontSize: \"14px\",\n fontWeight: 500,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n cursor: capturing ? \"wait\" : \"pointer\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.15s ease, box-shadow 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n opacity: capturing ? 0.7 : 1,\n }}\n onMouseEnter={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1)\";\n }}\n aria-label={label}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n >\n <path\n d=\"M8 1C4.134 1 1 4.134 1 8s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zm.75-3.5a.75.75 0 01-1.5 0V5a.75.75 0 011.5 0v5z\"\n fill=\"currentColor\"\n />\n </svg>\n {capturing ? \"Capturing...\" : label}\n </button>\n );\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\n\ninterface GlitchgrabReport {\n id: string;\n source: string;\n status: string;\n rawInput: string | null;\n reporterPrimaryKey: string;\n reporterName: string;\n reporterEmail: string | null;\n reporterPhone: string | null;\n pageUrl: string | null;\n createdAt: string;\n issue: {\n githubNumber: number;\n githubUrl: string;\n title: string;\n labels: string[];\n severity: string | null;\n githubState: string | null;\n } | null;\n}\n\nconst BASE_URL = \"https://www.glitchgrab.dev\";\n\n/**\n * Hook to fetch bug reports for a specific user.\n *\n * ```tsx\n * const { reports, isLoading, error, refetch } = useGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * });\n * ```\n */\nexport function useGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n /** Max results (default 100, max 100) */\n limit?: number;\n}): {\n reports: GlitchgrabReport[];\n isLoading: boolean;\n isFetching: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n} {\n const [reports, setReports] = useState<GlitchgrabReport[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fetchReports = useCallback(async () => {\n if (!token || !userId) {\n setIsLoading(false);\n return;\n }\n\n setIsFetching(true);\n setError(null);\n\n try {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n\n if (data.success) {\n setReports(data.data ?? []);\n } else {\n setError(data.error ?? \"Failed to fetch reports\");\n }\n } catch {\n setError(\"Network error\");\n } finally {\n setIsLoading(false);\n setIsFetching(false);\n }\n }, [token, userId, limit]);\n\n useEffect(() => {\n fetchReports();\n }, [fetchReports]);\n\n return { reports, isLoading, isFetching, error, refetch: fetchReports };\n}\n\n/**\n * Standalone fetcher — use with TanStack Query or any data fetching library.\n *\n * ```tsx\n * const { data } = useQuery({\n * queryKey: [\"glitchgrab-reports\", userId],\n * queryFn: () => fetchGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * }),\n * });\n * ```\n */\nexport async function fetchGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n limit?: number;\n}): Promise<GlitchgrabReport[]> {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n if (!data.success) throw new Error(data.error ?? \"Failed to fetch reports\");\n return data.data ?? [];\n}\n\n// ─── Report Actions ─────────────────────────────────────\n\nasync function reportAction(\n token: string,\n reportId: string,\n body: Record<string, string>\n): Promise<void> {\n const res = await fetch(`${BASE_URL}/api/v1/reports/${reportId}/actions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok || !data.success) throw new Error(data.error ?? \"Action failed\");\n}\n\n/**\n * Hook to manage report actions with loading/error states.\n *\n * ```tsx\n * const { approve, reject, close, isPending, error } = useGlitchgrabActions({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * onSuccess: () => refetch(),\n * onError: (err) => toast.error(err.message),\n * });\n *\n * <button onClick={() => approve(reportId)} disabled={isPending}>\n * {isPending ? \"...\" : \"Approve\"}\n * </button>\n * ```\n */\nexport function useGlitchgrabActions({\n token,\n onSuccess,\n onError,\n}: {\n token: string;\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n}) {\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const run = useCallback(\n async (reportId: string, body: Record<string, string>) => {\n setIsPending(true);\n setError(null);\n try {\n await reportAction(token, reportId, body);\n onSuccess?.();\n } catch (e) {\n const err = e instanceof Error ? e : new Error(\"Action failed\");\n setError(err.message);\n onError?.(err);\n } finally {\n setIsPending(false);\n }\n },\n [token, onSuccess, onError]\n );\n\n return {\n approve: (reportId: string) => run(reportId, { action: \"label\", label: \"approved\" }),\n reject: (reportId: string) => run(reportId, { action: \"label\", label: \"rejected\" }),\n close: (reportId: string) => run(reportId, { action: \"close\" }),\n reopen: (reportId: string) => run(reportId, { action: \"reopen\" }),\n label: (reportId: string, label: string) => run(reportId, { action: \"label\", label }),\n unlabel: (reportId: string, label: string) => run(reportId, { action: \"unlabel\", label }),\n isPending,\n error,\n };\n}\n"],"mappings":"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","names":["e","DEFAULT_BASE_URL","maxBreadcrumbs","addBreadcrumb","useState","useRef","useEffect","Fragment","jsx","useState","useRef","_a","useEffect","useState","useEffect","useCallback"]}
|