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/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
- declare function initBreadcrumbs(max?: number): void;
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 };