glitchgrab 1.0.1 → 1.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # glitchgrab
2
2
 
3
- Drop-in error capture and bug reporting for Next.js apps. Production errors automatically become GitHub issues.
3
+ Turn messy bugs into structured GitHub issues with AI. Drop-in SDK for Next.js apps.
4
4
 
5
5
  ## Install
6
6
 
@@ -12,7 +12,7 @@ bun add glitchgrab
12
12
 
13
13
  ## Quick Start
14
14
 
15
- Wrap your app with `GlitchgrabProvider` — that's it:
15
+ Wrap your app with `GlitchgrabProvider`:
16
16
 
17
17
  ```tsx
18
18
  // app/layout.tsx
@@ -20,147 +20,199 @@ import { GlitchgrabProvider } from "glitchgrab";
20
20
 
21
21
  export default function RootLayout({ children }) {
22
22
  return (
23
- <GlitchgrabProvider token="gg_your_token">
23
+ <GlitchgrabProvider token={process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!}>
24
24
  {children}
25
25
  </GlitchgrabProvider>
26
26
  );
27
27
  }
28
28
  ```
29
29
 
30
- This gives you:
31
- - Auto-capture of unhandled errors and promise rejections
32
- - Error boundary around your entire app
33
- - Page visit tracking for reproduction context
34
- - URL sanitization (strips tokens, keys, passwords)
30
+ ## Session (User Tracking)
35
31
 
36
- ## Get a Token
37
-
38
- 1. Go to [glitchgrab.dev](https://glitchgrab.dev)
39
- 2. Sign in with GitHub
40
- 3. Connect a repo
41
- 4. Generate an API token
42
-
43
- ## Usage
44
-
45
- ### 1. Auto-Capture (zero config)
46
-
47
- Just add the provider. Production errors are captured automatically with:
48
- - Error message and stack trace
49
- - Current URL (sanitized)
50
- - User agent
51
- - Visited pages history
52
-
53
- ### 2. Manual Bug Reporting (`useGlitchgrab` hook)
54
-
55
- Build your own report button or trigger:
32
+ Pass a `session` prop so bug reports include the reporter's identity. This lets you trace which user reported each bug.
56
33
 
57
34
  ```tsx
58
- "use client";
59
- import { useGlitchgrab } from "glitchgrab";
60
-
61
- function MyReportButton() {
62
- const { reportBug } = useGlitchgrab();
35
+ import { GlitchgrabProvider, type GlitchgrabSession } from "glitchgrab";
36
+ import { useSession } from "next-auth/react"; // or your auth library
37
+
38
+ function Providers({ children }) {
39
+ const { data: authSession } = useSession();
40
+
41
+ // Map your auth session to GlitchgrabSession
42
+ const session: GlitchgrabSession | null = authSession?.user
43
+ ? {
44
+ userId: authSession.user.id, // required - your DB primary key
45
+ name: authSession.user.name, // required - display name
46
+ email: authSession.user.email, // optional
47
+ phone: authSession.user.phone, // optional
48
+ }
49
+ : null;
63
50
 
64
51
  return (
65
- <button onClick={() => reportBug("The checkout flow is broken")}>
66
- Report Bug
67
- </button>
52
+ <GlitchgrabProvider
53
+ token={process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!}
54
+ session={session}
55
+ >
56
+ {children}
57
+ </GlitchgrabProvider>
68
58
  );
69
59
  }
70
60
  ```
71
61
 
72
- With metadata:
62
+ ### GlitchgrabSession type
73
63
 
74
- ```tsx
75
- reportBug("Payment failed", {
76
- userId: "123",
77
- plan: "pro",
78
- browser: "Chrome 120",
79
- });
64
+ ```ts
65
+ interface GlitchgrabSession {
66
+ userId: string; // required - primary key from your database
67
+ name: string; // required - reporter's display name
68
+ email?: string | null; // optional
69
+ phone?: string | null; // optional
70
+ [key: string]: unknown; // any extra fields
71
+ }
80
72
  ```
81
73
 
82
- ### 3. Pre-built Report Button (optional)
74
+ The `userId` is stored with every report. Use it to look up which user reported a bug in your own database.
75
+
76
+ ## Report Button
83
77
 
84
- If you want a ready-made floating button:
78
+ ### Default floating button
85
79
 
86
80
  ```tsx
87
- import { GlitchgrabProvider, ReportButton } from "glitchgrab";
81
+ import { ReportButton } from "glitchgrab";
88
82
 
89
- <GlitchgrabProvider token="gg_your_token">
90
- {children}
91
- <ReportButton />
92
- </GlitchgrabProvider>
83
+ // Floating button at bottom-right (default)
84
+ <ReportButton position="bottom-right" label="Report Bug" />
93
85
  ```
94
86
 
95
- Options:
87
+ ### Custom trigger (headless)
88
+
89
+ Use the render prop to bring your own button UI:
96
90
 
97
91
  ```tsx
98
- <ReportButton
99
- position="bottom-left" // "bottom-right" (default) | "bottom-left"
100
- label="Report Issue" // default: "Report Bug"
101
- />
92
+ import { ReportButton } from "glitchgrab";
93
+
94
+ <ReportButton>
95
+ {({ onClick, capturing }) => (
96
+ <button onClick={onClick} disabled={capturing}>
97
+ {capturing ? "Capturing..." : "Report a Bug"}
98
+ </button>
99
+ )}
100
+ </ReportButton>
102
101
  ```
103
102
 
104
- ### 4. Custom Error Boundary
103
+ The modal handles screenshot capture, preview, upload, retake, and submission. Your custom button just triggers it.
104
+
105
+ ## Programmatic Reporting
105
106
 
106
- Wrap specific sections with a custom fallback:
107
+ Use the `useGlitchgrab` hook to report bugs from code:
107
108
 
108
109
  ```tsx
109
- import { GlitchgrabErrorBoundary } from "glitchgrab";
110
+ import { useGlitchgrab } from "glitchgrab";
110
111
 
111
- <GlitchgrabErrorBoundary
112
- token="gg_your_token"
113
- fallback={<div>Something went wrong in this section</div>}
114
- >
115
- <DangerousComponent />
116
- </GlitchgrabErrorBoundary>
117
- ```
112
+ function MyComponent() {
113
+ const { reportBug, report, addBreadcrumb } = useGlitchgrab();
118
114
 
119
- ### 5. Provider Options
115
+ // Report a bug
116
+ await reportBug("Button not working on mobile");
120
117
 
121
- ```tsx
122
- <GlitchgrabProvider
123
- token="gg_your_token" // Required — your API token
124
- baseUrl="https://your-api.com" // Optional — custom API URL (default: glitchgrab.dev)
125
- onError={(error) => { // Optional — callback when errors are captured
126
- console.log("Captured:", error.message);
127
- }}
128
- fallback={<ErrorPage />} // Optional — what to show when the app crashes
129
- >
130
- {children}
131
- </GlitchgrabProvider>
118
+ // Report with a specific type
119
+ await report("FEATURE_REQUEST", "Add dark mode support");
120
+
121
+ // Add custom breadcrumbs for debugging context
122
+ addBreadcrumb("User clicked checkout", { cartSize: "3" });
123
+ }
132
124
  ```
133
125
 
134
- ## API Reference
126
+ ## Fetching Reports by User
135
127
 
136
- ### Components
128
+ Use the REST API to fetch reports for a specific user by their primary key:
137
129
 
138
- | Component | Description |
139
- |-----------|-------------|
140
- | `GlitchgrabProvider` | Wraps your app. Captures errors, tracks pages. |
141
- | `ReportButton` | Optional floating bug report button with modal. |
142
- | `GlitchgrabErrorBoundary` | Standalone error boundary for specific sections. |
130
+ ```bash
131
+ # Fetch all reports
132
+ curl -H "Authorization: Bearer gg_your_token" \
133
+ https://glitchgrab.dev/api/v1/sdk/reports
143
134
 
144
- ### Hooks
135
+ # Fetch reports by a specific user
136
+ curl -H "Authorization: Bearer gg_your_token" \
137
+ "https://glitchgrab.dev/api/v1/sdk/reports?reporterPrimaryKey=user_123"
145
138
 
146
- | Hook | Returns | Description |
147
- |------|---------|-------------|
148
- | `useGlitchgrab()` | `{ reportBug, token, baseUrl }` | Access bug reporting in any component. |
139
+ # Filter by status
140
+ curl -H "Authorization: Bearer gg_your_token" \
141
+ "https://glitchgrab.dev/api/v1/sdk/reports?status=CREATED&limit=20"
142
+ ```
149
143
 
150
- ### Utilities
144
+ ### Response
145
+
146
+ ```json
147
+ {
148
+ "success": true,
149
+ "data": [
150
+ {
151
+ "id": "cmn7abc123",
152
+ "source": "SDK_USER_REPORT",
153
+ "status": "CREATED",
154
+ "rawInput": "Button not working",
155
+ "reporterPrimaryKey": "user_123",
156
+ "reporterName": "John Doe",
157
+ "reporterEmail": "john@example.com",
158
+ "reporterPhone": null,
159
+ "pageUrl": "/dashboard/settings",
160
+ "createdAt": "2026-03-26T12:00:00.000Z",
161
+ "issue": {
162
+ "githubNumber": 42,
163
+ "githubUrl": "https://github.com/your/repo/issues/42",
164
+ "title": "Button not working"
165
+ }
166
+ }
167
+ ]
168
+ }
169
+ ```
170
+
171
+ ## Error Boundary
172
+
173
+ Wrap components to auto-capture React errors:
151
174
 
152
- | Function | Description |
153
- |----------|-------------|
154
- | `sanitizeUrl(url)` | Strips sensitive query params from URLs. |
155
- | `captureContext(pages)` | Returns current URL, user agent, timestamp. |
156
- | `sendReport(payload, baseUrl)` | Low-level function to send a report. |
175
+ ```tsx
176
+ import { GlitchgrabErrorBoundary } from "glitchgrab";
157
177
 
158
- ## Safety
178
+ <GlitchgrabErrorBoundary fallback={<p>Something went wrong</p>}>
179
+ <MyComponent />
180
+ </GlitchgrabErrorBoundary>
181
+ ```
159
182
 
160
- - **Never crashes your app.** Every function is wrapped in try/catch.
161
- - **Non-blocking.** Uses `fetch` with `keepalive` and `sendBeacon` fallback.
162
- - **No sensitive data leaked.** URLs are sanitized before sending.
163
- - **Zero external dependencies.** Only peer deps on React and Next.js.
183
+ ## Configuration
184
+
185
+ | Prop | Type | Default | Description |
186
+ |------|------|---------|-------------|
187
+ | `token` | `string` | required | Your Glitchgrab API token (`gg_...`) |
188
+ | `session` | `GlitchgrabSession \| null` | `null` | Logged-in user info for report attribution |
189
+ | `baseUrl` | `string` | `https://glitchgrab.dev` | API base URL |
190
+ | `breadcrumbs` | `boolean` | `true` | Enable automatic breadcrumb tracking |
191
+ | `maxBreadcrumbs` | `number` | `50` | Max breadcrumbs to keep |
192
+ | `onError` | `(error: Error) => void` | - | Called on unhandled errors |
193
+ | `onReportSent` | `(result: ReportResult) => void` | - | Called after a report is sent |
194
+ | `fallback` | `ReactNode` | - | Error boundary fallback UI |
195
+
196
+ ## Auto-Capture
197
+
198
+ In production (`NODE_ENV=production`), the SDK automatically captures:
199
+ - Unhandled JavaScript errors
200
+ - Unhandled promise rejections
201
+ - Console errors (as breadcrumbs)
202
+ - Navigation events (as breadcrumbs)
203
+ - API calls (as breadcrumbs)
204
+
205
+ Auto-capture is **disabled in development** to avoid noisy issues.
206
+
207
+ ## What gets included in each report
208
+
209
+ - Description from the user
210
+ - Screenshot (auto-captured or uploaded)
211
+ - Page URL and user agent
212
+ - Device info (screen size, viewport, platform, language, color scheme)
213
+ - Page navigation history
214
+ - Activity log (last 15 breadcrumbs)
215
+ - Session info (userId, name, email, phone)
164
216
 
165
217
  ## License
166
218
 
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React, { ReactNode } from 'react';
2
+ import * as React from 'react';
3
+ import { ReactNode } from 'react';
3
4
 
4
5
  interface GlitchgrabConfig {
5
6
  token: string;
@@ -62,8 +63,22 @@ interface CapturedContext {
62
63
  breadcrumbs: Breadcrumb[];
63
64
  deviceInfo: DeviceInfo | null;
64
65
  }
66
+ interface GlitchgrabSession {
67
+ /** Primary key of the user in your database (required) */
68
+ userId: string;
69
+ /** Display name (required) */
70
+ name: string;
71
+ /** Email address */
72
+ email?: string | null;
73
+ /** Phone number */
74
+ phone?: string | null;
75
+ /** Any extra fields you want attached to reports */
76
+ [key: string]: unknown;
77
+ }
65
78
  interface GlitchgrabProviderProps {
66
79
  token: string;
80
+ /** Logged-in user session — include userId (your DB primary key) so reports are traceable */
81
+ session?: GlitchgrabSession | null;
67
82
  baseUrl?: string;
68
83
  onError?: (error: Error) => void;
69
84
  onReportSent?: (result: ReportResult) => void;
@@ -73,7 +88,7 @@ interface GlitchgrabProviderProps {
73
88
  fallback?: ReactNode;
74
89
  }
75
90
  interface ReportButtonProps {
76
- position?: "bottom-right" | "bottom-left";
91
+ position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
77
92
  label?: string;
78
93
  className?: string;
79
94
  /** Allow reporting feature requests, questions, not just bugs */
@@ -112,7 +127,13 @@ interface UseGlitchgrabReturn {
112
127
  declare function useGlitchgrab(): UseGlitchgrabReturn;
113
128
  declare function GlitchgrabProvider(props: GlitchgrabProviderProps): react_jsx_runtime.JSX.Element;
114
129
 
115
- declare function ReportButton({ position, label, className, }: ReportButtonProps): react_jsx_runtime.JSX.Element;
130
+ declare function ReportButton({ position, label, className, children, }: ReportButtonProps & {
131
+ /** Render prop — receives { onClick, capturing } so you can use your own trigger button */
132
+ children?: (props: {
133
+ onClick: () => void;
134
+ capturing: boolean;
135
+ }) => ReactNode;
136
+ }): react_jsx_runtime.JSX.Element;
116
137
 
117
138
  interface ErrorBoundaryProps {
118
139
  token: string;
@@ -146,4 +167,4 @@ declare function captureContext(visitedPages: string[]): CapturedContext;
146
167
  */
147
168
  declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<ReportResult | null>;
148
169
 
149
- export { type Breadcrumb, type BreadcrumbType, type CapturedContext, type DeviceInfo, type GlitchgrabConfig, GlitchgrabErrorBoundary, GlitchgrabProvider, type GlitchgrabProviderProps, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportType, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, clearBreadcrumbs, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab };
170
+ 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, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React, { ReactNode } from 'react';
2
+ import * as React from 'react';
3
+ import { ReactNode } from 'react';
3
4
 
4
5
  interface GlitchgrabConfig {
5
6
  token: string;
@@ -62,8 +63,22 @@ interface CapturedContext {
62
63
  breadcrumbs: Breadcrumb[];
63
64
  deviceInfo: DeviceInfo | null;
64
65
  }
66
+ interface GlitchgrabSession {
67
+ /** Primary key of the user in your database (required) */
68
+ userId: string;
69
+ /** Display name (required) */
70
+ name: string;
71
+ /** Email address */
72
+ email?: string | null;
73
+ /** Phone number */
74
+ phone?: string | null;
75
+ /** Any extra fields you want attached to reports */
76
+ [key: string]: unknown;
77
+ }
65
78
  interface GlitchgrabProviderProps {
66
79
  token: string;
80
+ /** Logged-in user session — include userId (your DB primary key) so reports are traceable */
81
+ session?: GlitchgrabSession | null;
67
82
  baseUrl?: string;
68
83
  onError?: (error: Error) => void;
69
84
  onReportSent?: (result: ReportResult) => void;
@@ -73,7 +88,7 @@ interface GlitchgrabProviderProps {
73
88
  fallback?: ReactNode;
74
89
  }
75
90
  interface ReportButtonProps {
76
- position?: "bottom-right" | "bottom-left";
91
+ position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
77
92
  label?: string;
78
93
  className?: string;
79
94
  /** Allow reporting feature requests, questions, not just bugs */
@@ -112,7 +127,13 @@ interface UseGlitchgrabReturn {
112
127
  declare function useGlitchgrab(): UseGlitchgrabReturn;
113
128
  declare function GlitchgrabProvider(props: GlitchgrabProviderProps): react_jsx_runtime.JSX.Element;
114
129
 
115
- declare function ReportButton({ position, label, className, }: ReportButtonProps): react_jsx_runtime.JSX.Element;
130
+ declare function ReportButton({ position, label, className, children, }: ReportButtonProps & {
131
+ /** Render prop — receives { onClick, capturing } so you can use your own trigger button */
132
+ children?: (props: {
133
+ onClick: () => void;
134
+ capturing: boolean;
135
+ }) => ReactNode;
136
+ }): react_jsx_runtime.JSX.Element;
116
137
 
117
138
  interface ErrorBoundaryProps {
118
139
  token: string;
@@ -146,4 +167,4 @@ declare function captureContext(visitedPages: string[]): CapturedContext;
146
167
  */
147
168
  declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<ReportResult | null>;
148
169
 
149
- export { type Breadcrumb, type BreadcrumbType, type CapturedContext, type DeviceInfo, type GlitchgrabConfig, GlitchgrabErrorBoundary, GlitchgrabProvider, type GlitchgrabProviderProps, ReportButton, type ReportButtonProps, type ReportPayload, type ReportResult, type ReportType, type UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, clearBreadcrumbs, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab };
170
+ 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, getBreadcrumbs, initBreadcrumbs, sanitizeUrl, sendReport, useGlitchgrab };