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 +151 -99
- package/dist/index.d.mts +25 -4
- package/dist/index.d.ts +25 -4
- package/dist/index.js +522 -204
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +509 -191
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# glitchgrab
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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=
|
|
23
|
+
<GlitchgrabProvider token={process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!}>
|
|
24
24
|
{children}
|
|
25
25
|
</GlitchgrabProvider>
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
59
|
-
import {
|
|
60
|
-
|
|
61
|
-
function
|
|
62
|
-
const {
|
|
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
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
62
|
+
### GlitchgrabSession type
|
|
73
63
|
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
userId:
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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
|
-
|
|
78
|
+
### Default floating button
|
|
85
79
|
|
|
86
80
|
```tsx
|
|
87
|
-
import {
|
|
81
|
+
import { ReportButton } from "glitchgrab";
|
|
88
82
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
<ReportButton />
|
|
92
|
-
</GlitchgrabProvider>
|
|
83
|
+
// Floating button at bottom-right (default)
|
|
84
|
+
<ReportButton position="bottom-right" label="Report Bug" />
|
|
93
85
|
```
|
|
94
86
|
|
|
95
|
-
|
|
87
|
+
### Custom trigger (headless)
|
|
88
|
+
|
|
89
|
+
Use the render prop to bring your own button UI:
|
|
96
90
|
|
|
97
91
|
```tsx
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
103
|
+
The modal handles screenshot capture, preview, upload, retake, and submission. Your custom button just triggers it.
|
|
104
|
+
|
|
105
|
+
## Programmatic Reporting
|
|
105
106
|
|
|
106
|
-
|
|
107
|
+
Use the `useGlitchgrab` hook to report bugs from code:
|
|
107
108
|
|
|
108
109
|
```tsx
|
|
109
|
-
import {
|
|
110
|
+
import { useGlitchgrab } from "glitchgrab";
|
|
110
111
|
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
115
|
+
// Report a bug
|
|
116
|
+
await reportBug("Button not working on mobile");
|
|
120
117
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
##
|
|
126
|
+
## Fetching Reports by User
|
|
135
127
|
|
|
136
|
-
|
|
128
|
+
Use the REST API to fetch reports for a specific user by their primary key:
|
|
137
129
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
178
|
+
<GlitchgrabErrorBoundary fallback={<p>Something went wrong</p>}>
|
|
179
|
+
<MyComponent />
|
|
180
|
+
</GlitchgrabErrorBoundary>
|
|
181
|
+
```
|
|
159
182
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 };
|