glitchgrab 1.30.0 → 1.31.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 +254 -2
- package/dist/index.d.mts +266 -3
- package/dist/index.d.ts +266 -3
- package/dist/index.js +1474 -233
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1413 -180
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,21 @@ interface ReportPayload {
|
|
|
35
35
|
deviceInfo?: DeviceInfo;
|
|
36
36
|
metadata?: Record<string, string>;
|
|
37
37
|
}
|
|
38
|
+
/** Extra context for an error your app already caught — see `captureError` */
|
|
39
|
+
interface CaptureErrorOptions {
|
|
40
|
+
/** React component stack, e.g. from `componentDidCatch` / `onCaughtError` */
|
|
41
|
+
componentStack?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Next.js error digest. In production Next replaces server-boundary error
|
|
44
|
+
* messages with a generic string — the digest is the only thing that tells
|
|
45
|
+
* two different crashes apart, so it also feeds the dedup signature.
|
|
46
|
+
*/
|
|
47
|
+
digest?: string;
|
|
48
|
+
/** Which boundary caught it, e.g. `"next-app-router"` — attached as metadata */
|
|
49
|
+
boundary?: string;
|
|
50
|
+
/** Extra metadata merged into the report */
|
|
51
|
+
metadata?: Record<string, string>;
|
|
52
|
+
}
|
|
38
53
|
interface ReportResult {
|
|
39
54
|
success: boolean;
|
|
40
55
|
reportId?: string;
|
|
@@ -44,6 +59,34 @@ interface ReportResult {
|
|
|
44
59
|
intent?: string;
|
|
45
60
|
message?: string;
|
|
46
61
|
}
|
|
62
|
+
interface FeedbackPayload {
|
|
63
|
+
token: string;
|
|
64
|
+
/** 1–5 stars */
|
|
65
|
+
rating: number;
|
|
66
|
+
message?: string;
|
|
67
|
+
pageUrl?: string;
|
|
68
|
+
userAgent?: string;
|
|
69
|
+
metadata?: Record<string, string>;
|
|
70
|
+
}
|
|
71
|
+
interface FeedbackResult {
|
|
72
|
+
success: boolean;
|
|
73
|
+
feedbackId?: string;
|
|
74
|
+
rating?: number;
|
|
75
|
+
createdAt?: string;
|
|
76
|
+
message?: string;
|
|
77
|
+
}
|
|
78
|
+
/** One stored feedback entry, as returned by the read endpoint. */
|
|
79
|
+
interface GlitchgrabFeedback {
|
|
80
|
+
id: string;
|
|
81
|
+
rating: number;
|
|
82
|
+
message: string | null;
|
|
83
|
+
pageUrl: string | null;
|
|
84
|
+
/** Whether the repo owner published this entry for public display */
|
|
85
|
+
approved: boolean;
|
|
86
|
+
reporterPrimaryKey: string;
|
|
87
|
+
reporterName: string;
|
|
88
|
+
createdAt: string;
|
|
89
|
+
}
|
|
47
90
|
type BreadcrumbType = "console" | "navigation" | "api" | "click" | "error" | "custom";
|
|
48
91
|
interface Breadcrumb {
|
|
49
92
|
type: BreadcrumbType;
|
|
@@ -62,6 +105,26 @@ interface DeviceInfo {
|
|
|
62
105
|
colorScheme: string;
|
|
63
106
|
devicePixelRatio: number;
|
|
64
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Machine state at the moment of the crash, as opposed to `DeviceInfo`, which
|
|
110
|
+
* describes the machine itself. Most fields are Chromium-only and simply absent
|
|
111
|
+
* elsewhere — never assume one is present.
|
|
112
|
+
*/
|
|
113
|
+
interface RuntimeInfo {
|
|
114
|
+
/** ms since this page loaded */
|
|
115
|
+
timeOnPageMs: number;
|
|
116
|
+
/** How many errors the SDK has already auto-captured in this page session */
|
|
117
|
+
errorCount: number;
|
|
118
|
+
/** `document.visibilityState` — a crash in a background tab reads differently */
|
|
119
|
+
visibility: string;
|
|
120
|
+
jsHeapUsedMb?: number;
|
|
121
|
+
jsHeapLimitMb?: number;
|
|
122
|
+
/** `navigator.connection.effectiveType` — "4g", "3g", "2g", "slow-2g" */
|
|
123
|
+
connectionType?: string;
|
|
124
|
+
downlinkMbps?: number;
|
|
125
|
+
rttMs?: number;
|
|
126
|
+
saveData?: boolean;
|
|
127
|
+
}
|
|
65
128
|
interface CapturedContext {
|
|
66
129
|
url: string;
|
|
67
130
|
userAgent: string;
|
|
@@ -69,6 +132,12 @@ interface CapturedContext {
|
|
|
69
132
|
visitedPages: string[];
|
|
70
133
|
breadcrumbs: Breadcrumb[];
|
|
71
134
|
deviceInfo: DeviceInfo | null;
|
|
135
|
+
/** Runtime health snapshot — null when unavailable (SSR) */
|
|
136
|
+
runtime: RuntimeInfo | null;
|
|
137
|
+
/** Key-values the host app attached via `setContext` */
|
|
138
|
+
appContext: Record<string, string>;
|
|
139
|
+
/** Build identifier this crash came from, if known */
|
|
140
|
+
release?: string;
|
|
72
141
|
}
|
|
73
142
|
interface GlitchgrabSession {
|
|
74
143
|
/** Primary key of the user in your database (required) */
|
|
@@ -103,17 +172,69 @@ interface GlitchgrabProviderProps {
|
|
|
103
172
|
* signatures that aren't app bugs — e.g. browser extension bridge errors.
|
|
104
173
|
*/
|
|
105
174
|
ignoreErrors?: (string | RegExp)[];
|
|
175
|
+
/**
|
|
176
|
+
* Build identifier attached to every report — a version, a tag, a commit SHA.
|
|
177
|
+
* Tells you which deploy introduced a crash. Falls back to
|
|
178
|
+
* `NEXT_PUBLIC_APP_VERSION`, `NEXT_PUBLIC_RELEASE`, then
|
|
179
|
+
* `NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA` when not passed.
|
|
180
|
+
*/
|
|
181
|
+
release?: string;
|
|
182
|
+
/**
|
|
183
|
+
* App-owned context attached to every report — orgId, plan, role, feature
|
|
184
|
+
* flags. Merged with anything set imperatively via `setContext`.
|
|
185
|
+
*/
|
|
186
|
+
context?: Record<string, unknown>;
|
|
187
|
+
/**
|
|
188
|
+
* Extra origins whose failed-request bodies may be recorded in breadcrumbs,
|
|
189
|
+
* e.g. `["https://api.myapp.com"]`. Same-origin requests are always recorded;
|
|
190
|
+
* third-party APIs are excluded by default because their error envelopes carry
|
|
191
|
+
* data you don't control and shouldn't forward into a GitHub issue.
|
|
192
|
+
*/
|
|
193
|
+
responseBodyOrigins?: string[];
|
|
106
194
|
}
|
|
107
195
|
interface ReportButtonProps {
|
|
108
196
|
position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
|
|
109
197
|
label?: string;
|
|
110
198
|
className?: string;
|
|
111
199
|
}
|
|
200
|
+
interface FeedbackButtonProps {
|
|
201
|
+
position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
|
|
202
|
+
label?: string;
|
|
203
|
+
className?: string;
|
|
204
|
+
/** Heading inside the dialog (default: "How are we doing?") */
|
|
205
|
+
title?: string;
|
|
206
|
+
/** Placeholder for the message box */
|
|
207
|
+
placeholder?: string;
|
|
208
|
+
/** Shown after a successful submit */
|
|
209
|
+
thanksMessage?: string;
|
|
210
|
+
}
|
|
112
211
|
interface UseGlitchgrabReturn {
|
|
113
212
|
/** Report a bug programmatically */
|
|
114
213
|
reportBug: (description: string, metadata?: Record<string, string>) => Promise<ReportResult | null>;
|
|
115
214
|
/** Report with a specific type */
|
|
116
215
|
report: (type: ReportType, description: string, metadata?: Record<string, string>) => Promise<ReportResult | null>;
|
|
216
|
+
/**
|
|
217
|
+
* Report an error your app already caught — a framework error boundary
|
|
218
|
+
* (`app/error.tsx`, React Router `errorElement`, Remix `ErrorBoundary`) or a
|
|
219
|
+
* `try/catch`. These never reach `window.onerror`, so auto-capture misses them.
|
|
220
|
+
* Sends `SDK_AUTO`. Fire-and-forget, never throws.
|
|
221
|
+
*/
|
|
222
|
+
captureError: (error: unknown, options?: CaptureErrorOptions) => void;
|
|
223
|
+
/**
|
|
224
|
+
* Attach a key-value to every future report — orgId, plan, role, feature flag.
|
|
225
|
+
* Pass `null` to remove a key. Survives navigation and provider remounts.
|
|
226
|
+
*/
|
|
227
|
+
setContext: (key: string, value: unknown) => void;
|
|
228
|
+
/** Set several context keys at once. Merges; does not replace. */
|
|
229
|
+
setContexts: (values: Record<string, unknown>) => void;
|
|
230
|
+
/**
|
|
231
|
+
* Save a 1–5 star rating your end-user left about your app. Stored by
|
|
232
|
+
* Glitchgrab and shown on your Feedback page — never becomes a GitHub issue.
|
|
233
|
+
* Returns null on any failure (never throws).
|
|
234
|
+
*/
|
|
235
|
+
sendFeedback: (rating: number, message?: string, metadata?: Record<string, string>) => Promise<FeedbackResult | null>;
|
|
236
|
+
/** Open the built-in feedback dialog (stars + message) programmatically */
|
|
237
|
+
openFeedbackDialog: () => void;
|
|
117
238
|
/** Add a custom breadcrumb */
|
|
118
239
|
addBreadcrumb: (message: string, data?: Record<string, string>) => void;
|
|
119
240
|
/** Open the ReportButton modal programmatically (captures screenshot + shows dialog) */
|
|
@@ -144,11 +265,14 @@ interface UseGlitchgrabReturn {
|
|
|
144
265
|
*
|
|
145
266
|
* @example
|
|
146
267
|
* ```tsx
|
|
147
|
-
* const { reportBug, report, addBreadcrumb } = useGlitchgrab();
|
|
268
|
+
* const { reportBug, report, captureError, addBreadcrumb } = useGlitchgrab();
|
|
148
269
|
*
|
|
149
270
|
* // Report a bug
|
|
150
271
|
* reportBug("Login button crashes on mobile");
|
|
151
272
|
*
|
|
273
|
+
* // Report an error your own boundary already caught (e.g. app/error.tsx)
|
|
274
|
+
* captureError(error, { digest: error.digest, boundary: "next-app-router" });
|
|
275
|
+
*
|
|
152
276
|
* // Report a feature request
|
|
153
277
|
* report("FEATURE_REQUEST", "Add dark mode");
|
|
154
278
|
*
|
|
@@ -188,6 +312,31 @@ declare function ReportButton({ position, label, className, children, }: ReportB
|
|
|
188
312
|
}) => ReactNode;
|
|
189
313
|
}): react_jsx_runtime.JSX.Element | null;
|
|
190
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Trigger for the built-in feedback dialog (stars + message).
|
|
317
|
+
*
|
|
318
|
+
* The dialog itself lives inside `GlitchgrabProvider` — this is only the visible
|
|
319
|
+
* trigger. Open it programmatically with `useGlitchgrab().openFeedbackDialog()`,
|
|
320
|
+
* or skip the dialog entirely and call `sendFeedback(rating, message)` from your
|
|
321
|
+
* own UI.
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* ```tsx
|
|
325
|
+
* // Default floating button
|
|
326
|
+
* <FeedbackButton />
|
|
327
|
+
*
|
|
328
|
+
* // Your own trigger
|
|
329
|
+
* <FeedbackButton>
|
|
330
|
+
* {({ onClick }) => <button onClick={onClick}>Rate us</button>}
|
|
331
|
+
* </FeedbackButton>
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
declare function FeedbackButton({ position, label, className, children, }: FeedbackButtonProps & {
|
|
335
|
+
children?: (props: {
|
|
336
|
+
onClick: () => void;
|
|
337
|
+
}) => ReactNode;
|
|
338
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
339
|
+
|
|
191
340
|
interface ErrorBoundaryProps {
|
|
192
341
|
token: string;
|
|
193
342
|
baseUrl?: string;
|
|
@@ -207,6 +356,52 @@ declare class GlitchgrabErrorBoundary extends React.Component<ErrorBoundaryProps
|
|
|
207
356
|
render(): React.ReactNode;
|
|
208
357
|
}
|
|
209
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Report an error your app already caught — a framework error boundary
|
|
361
|
+
* (`app/error.tsx`, `app/global-error.tsx`, React Router `errorElement`, Remix
|
|
362
|
+
* `ErrorBoundary`), a `componentDidCatch`, or a `try/catch` you want filed.
|
|
363
|
+
*
|
|
364
|
+
* These never reach `window.onerror`, so provider auto-capture cannot see them.
|
|
365
|
+
*
|
|
366
|
+
* Fire-and-forget. Never throws, never blocks the fallback UI render. No-ops if
|
|
367
|
+
* no `GlitchgrabProvider` has rendered yet (nothing to authenticate with).
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```tsx
|
|
371
|
+
* // app/global-error.tsx — renders outside the provider tree
|
|
372
|
+
* "use client";
|
|
373
|
+
* import { captureError } from "glitchgrab";
|
|
374
|
+
*
|
|
375
|
+
* export default function GlobalError({ error }: { error: Error & { digest?: string } }) {
|
|
376
|
+
* useEffect(() => {
|
|
377
|
+
* captureError(error, { digest: error.digest, boundary: "next-global-error" });
|
|
378
|
+
* }, [error]);
|
|
379
|
+
* return <html><body><p>Something went wrong</p></body></html>;
|
|
380
|
+
* }
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
declare function captureError(error: unknown, options?: CaptureErrorOptions): void;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* App-owned context: key-values the host app attaches once and every report
|
|
387
|
+
* carries thereafter — orgId, plan, role, active feature flags. The SDK cannot
|
|
388
|
+
* guess these, and they are usually the difference between "a crash" and "a
|
|
389
|
+
* crash for enterprise tenants on the new billing flow".
|
|
390
|
+
*
|
|
391
|
+
* Module-level, not React state, so it survives the provider unmount that
|
|
392
|
+
* `global-error.tsx` causes and is readable from non-React call sites.
|
|
393
|
+
*/
|
|
394
|
+
/**
|
|
395
|
+
* Attach one key-value to every future report. Passing `null`/`undefined`
|
|
396
|
+
* removes the key — so a value that goes away (user logs out of an org) stops
|
|
397
|
+
* being reported instead of going stale.
|
|
398
|
+
*/
|
|
399
|
+
declare function setContext(key: string, value: unknown): void;
|
|
400
|
+
/** Set several keys at once. Merges — it does not replace what's already set. */
|
|
401
|
+
declare function setContexts(values: Record<string, unknown>): void;
|
|
402
|
+
declare function getAppContext(): Record<string, string>;
|
|
403
|
+
declare function clearAppContext(): void;
|
|
404
|
+
|
|
210
405
|
interface GlitchgrabReport {
|
|
211
406
|
id: string;
|
|
212
407
|
source: string;
|
|
@@ -299,7 +494,60 @@ declare function useGlitchgrabActions({ token, onSuccess, onError, }: {
|
|
|
299
494
|
error: string | null;
|
|
300
495
|
};
|
|
301
496
|
|
|
302
|
-
|
|
497
|
+
interface FeedbackQuery {
|
|
498
|
+
token: string;
|
|
499
|
+
/** Only entries the repo owner published — use this for a public testimonials wall */
|
|
500
|
+
approvedOnly?: boolean;
|
|
501
|
+
/** Only this end-user's feedback (their primary key in your DB) */
|
|
502
|
+
userId?: string;
|
|
503
|
+
/** Floor on the star rating, 1–5 */
|
|
504
|
+
minRating?: number;
|
|
505
|
+
/** Max results (default 50, max 100) */
|
|
506
|
+
limit?: number;
|
|
507
|
+
baseUrl?: string;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Standalone fetcher — use with TanStack Query or any data fetching library.
|
|
511
|
+
*
|
|
512
|
+
* ```tsx
|
|
513
|
+
* const { data } = useQuery({
|
|
514
|
+
* queryKey: ["testimonials"],
|
|
515
|
+
* queryFn: () => fetchGlitchgrabFeedback({
|
|
516
|
+
* token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,
|
|
517
|
+
* approvedOnly: true,
|
|
518
|
+
* minRating: 4,
|
|
519
|
+
* }),
|
|
520
|
+
* });
|
|
521
|
+
* ```
|
|
522
|
+
*/
|
|
523
|
+
declare function fetchGlitchgrabFeedback(query: FeedbackQuery): Promise<GlitchgrabFeedback[]>;
|
|
524
|
+
/**
|
|
525
|
+
* Hook to read back the feedback your end-users left — render it as a
|
|
526
|
+
* testimonials wall, or show a user their own past ratings.
|
|
527
|
+
*
|
|
528
|
+
* ```tsx
|
|
529
|
+
* const { feedback, isLoading, error, refetch } = useGlitchgrabFeedback({
|
|
530
|
+
* token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,
|
|
531
|
+
* approvedOnly: true,
|
|
532
|
+
* });
|
|
533
|
+
* ```
|
|
534
|
+
*/
|
|
535
|
+
declare function useGlitchgrabFeedback(query: FeedbackQuery): {
|
|
536
|
+
feedback: GlitchgrabFeedback[];
|
|
537
|
+
isLoading: boolean;
|
|
538
|
+
isFetching: boolean;
|
|
539
|
+
error: string | null;
|
|
540
|
+
refetch: () => Promise<void>;
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
interface BreadcrumbOptions {
|
|
544
|
+
/**
|
|
545
|
+
* Additional origins to capture error response bodies from, e.g.
|
|
546
|
+
* `["https://api.myapp.com"]`. Same-origin requests are always captured.
|
|
547
|
+
*/
|
|
548
|
+
responseBodyOrigins?: string[];
|
|
549
|
+
}
|
|
550
|
+
declare function initBreadcrumbs(max?: number, options?: BreadcrumbOptions): void;
|
|
303
551
|
declare function addBreadcrumb(type: BreadcrumbType, message: string, data?: Record<string, string>): void;
|
|
304
552
|
declare function getBreadcrumbs(): Breadcrumb[];
|
|
305
553
|
declare function clearBreadcrumbs(): void;
|
|
@@ -330,6 +578,15 @@ declare function captureContext(visitedPages: string[]): CapturedContext;
|
|
|
330
578
|
* Never throws — returns null on failure.
|
|
331
579
|
*/
|
|
332
580
|
declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<ReportResult | null>;
|
|
581
|
+
/**
|
|
582
|
+
* Save a star rating your end-user left about your app.
|
|
583
|
+
* Never throws — returns null on failure.
|
|
584
|
+
*
|
|
585
|
+
* Unlike `sendReport`, this is always a deliberate user action with a dialog
|
|
586
|
+
* open in front of them, so it retries on transient failure but skips the
|
|
587
|
+
* sendBeacon fallback: the caller needs a real result to show a thank-you.
|
|
588
|
+
*/
|
|
589
|
+
declare function sendFeedback(payload: FeedbackPayload, baseUrl?: string): Promise<FeedbackResult | null>;
|
|
333
590
|
interface EnhanceContext {
|
|
334
591
|
url?: string;
|
|
335
592
|
visitedPages?: string[];
|
|
@@ -349,8 +606,14 @@ declare function computeSignature(params: {
|
|
|
349
606
|
errorMessage: string | undefined;
|
|
350
607
|
pageUrl: string | undefined;
|
|
351
608
|
errorStack?: string | undefined;
|
|
609
|
+
/**
|
|
610
|
+
* Next.js error digest. Production strips server-boundary errors to a generic
|
|
611
|
+
* message with no useful stack, so without the digest every distinct server
|
|
612
|
+
* crash on one page collapses into a single signature.
|
|
613
|
+
*/
|
|
614
|
+
digest?: string | undefined;
|
|
352
615
|
}): string;
|
|
353
616
|
declare function shouldSkipDuplicate(signature: string, windowMs?: number, now?: number): boolean;
|
|
354
617
|
declare function clearDedupCache(): void;
|
|
355
618
|
|
|
356
|
-
export { type Breadcrumb, type BreadcrumbType, type CapturedContext, type DeviceInfo, GLITCHGRAB_SHORTCUT, GLITCHGRAB_SHORTCUT_MAC, type GlitchgrabConfig, GlitchgrabErrorBoundary, GlitchgrabProvider, type GlitchgrabProviderProps, type GlitchgrabReport, type GlitchgrabSession, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportSeverity, type ReportType, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, clearBreadcrumbs, clearDedupCache, computeSignature, enhanceText, fetchGlitchgrabReports, getBreadcrumbs, getShortcutLabel, initBreadcrumbs, matchesShortcut, sanitizeUrl, sendReport, shouldSkipDuplicate, useGlitchgrab, useGlitchgrabActions, useGlitchgrabReports };
|
|
619
|
+
export { type Breadcrumb, type BreadcrumbType, type CaptureErrorOptions, type CapturedContext, type DeviceInfo, FeedbackButton, type FeedbackButtonProps, type FeedbackPayload, type FeedbackQuery, type FeedbackResult, GLITCHGRAB_SHORTCUT, GLITCHGRAB_SHORTCUT_MAC, type GlitchgrabConfig, GlitchgrabErrorBoundary, type GlitchgrabFeedback, GlitchgrabProvider, type GlitchgrabProviderProps, type GlitchgrabReport, type GlitchgrabSession, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportSeverity, type ReportType, type RuntimeInfo, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, captureError, clearAppContext, clearBreadcrumbs, clearDedupCache, computeSignature, enhanceText, fetchGlitchgrabFeedback, fetchGlitchgrabReports, getAppContext, getBreadcrumbs, getShortcutLabel, initBreadcrumbs, matchesShortcut, sanitizeUrl, sendFeedback, sendReport, setContext, setContexts, shouldSkipDuplicate, useGlitchgrab, useGlitchgrabActions, useGlitchgrabFeedback, useGlitchgrabReports };
|