glitchgrab 0.1.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 ADDED
@@ -0,0 +1,167 @@
1
+ # glitchgrab
2
+
3
+ Drop-in error capture and bug reporting for Next.js apps. Production errors automatically become GitHub issues.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install glitchgrab
9
+ # or
10
+ bun add glitchgrab
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ Wrap your app with `GlitchgrabProvider` — that's it:
16
+
17
+ ```tsx
18
+ // app/layout.tsx
19
+ import { GlitchgrabProvider } from "glitchgrab";
20
+
21
+ export default function RootLayout({ children }) {
22
+ return (
23
+ <GlitchgrabProvider token="gg_your_token">
24
+ {children}
25
+ </GlitchgrabProvider>
26
+ );
27
+ }
28
+ ```
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)
35
+
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:
56
+
57
+ ```tsx
58
+ "use client";
59
+ import { useGlitchgrab } from "glitchgrab";
60
+
61
+ function MyReportButton() {
62
+ const { reportBug } = useGlitchgrab();
63
+
64
+ return (
65
+ <button onClick={() => reportBug("The checkout flow is broken")}>
66
+ Report Bug
67
+ </button>
68
+ );
69
+ }
70
+ ```
71
+
72
+ With metadata:
73
+
74
+ ```tsx
75
+ reportBug("Payment failed", {
76
+ userId: "123",
77
+ plan: "pro",
78
+ browser: "Chrome 120",
79
+ });
80
+ ```
81
+
82
+ ### 3. Pre-built Report Button (optional)
83
+
84
+ If you want a ready-made floating button:
85
+
86
+ ```tsx
87
+ import { GlitchgrabProvider, ReportButton } from "glitchgrab";
88
+
89
+ <GlitchgrabProvider token="gg_your_token">
90
+ {children}
91
+ <ReportButton />
92
+ </GlitchgrabProvider>
93
+ ```
94
+
95
+ Options:
96
+
97
+ ```tsx
98
+ <ReportButton
99
+ position="bottom-left" // "bottom-right" (default) | "bottom-left"
100
+ label="Report Issue" // default: "Report Bug"
101
+ />
102
+ ```
103
+
104
+ ### 4. Custom Error Boundary
105
+
106
+ Wrap specific sections with a custom fallback:
107
+
108
+ ```tsx
109
+ import { GlitchgrabErrorBoundary } from "glitchgrab";
110
+
111
+ <GlitchgrabErrorBoundary
112
+ token="gg_your_token"
113
+ fallback={<div>Something went wrong in this section</div>}
114
+ >
115
+ <DangerousComponent />
116
+ </GlitchgrabErrorBoundary>
117
+ ```
118
+
119
+ ### 5. Provider Options
120
+
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>
132
+ ```
133
+
134
+ ## API Reference
135
+
136
+ ### Components
137
+
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. |
143
+
144
+ ### Hooks
145
+
146
+ | Hook | Returns | Description |
147
+ |------|---------|-------------|
148
+ | `useGlitchgrab()` | `{ reportBug, token, baseUrl }` | Access bug reporting in any component. |
149
+
150
+ ### Utilities
151
+
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. |
157
+
158
+ ## Safety
159
+
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.
164
+
165
+ ## License
166
+
167
+ MIT
@@ -0,0 +1,149 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React, { ReactNode } from 'react';
3
+
4
+ interface GlitchgrabConfig {
5
+ token: string;
6
+ baseUrl?: string;
7
+ onError?: (error: Error) => void;
8
+ /** Called after a report is sent — use to sync with your own ticket system */
9
+ onReportSent?: (result: ReportResult) => void;
10
+ /** Enable breadcrumb tracking (default: true) */
11
+ breadcrumbs?: boolean;
12
+ /** Max breadcrumbs to keep (default: 50) */
13
+ maxBreadcrumbs?: number;
14
+ }
15
+ type ReportType = "BUG" | "FEATURE_REQUEST" | "QUESTION" | "OTHER";
16
+ interface ReportPayload {
17
+ token: string;
18
+ source: "SDK_AUTO" | "SDK_USER_REPORT";
19
+ type?: ReportType;
20
+ description?: string;
21
+ errorMessage?: string;
22
+ errorStack?: string;
23
+ componentStack?: string;
24
+ pageUrl?: string;
25
+ userAgent?: string;
26
+ breadcrumbs?: Breadcrumb[];
27
+ deviceInfo?: DeviceInfo;
28
+ metadata?: Record<string, string>;
29
+ }
30
+ interface ReportResult {
31
+ success: boolean;
32
+ reportId?: string;
33
+ issueUrl?: string;
34
+ issueNumber?: number;
35
+ title?: string;
36
+ intent?: string;
37
+ message?: string;
38
+ }
39
+ type BreadcrumbType = "console" | "navigation" | "api" | "click" | "error" | "custom";
40
+ interface Breadcrumb {
41
+ type: BreadcrumbType;
42
+ message: string;
43
+ timestamp: string;
44
+ data?: Record<string, string>;
45
+ }
46
+ interface DeviceInfo {
47
+ screenWidth: number;
48
+ screenHeight: number;
49
+ viewportWidth: number;
50
+ viewportHeight: number;
51
+ platform: string;
52
+ language: string;
53
+ online: boolean;
54
+ colorScheme: string;
55
+ devicePixelRatio: number;
56
+ }
57
+ interface CapturedContext {
58
+ url: string;
59
+ userAgent: string;
60
+ timestamp: string;
61
+ visitedPages: string[];
62
+ breadcrumbs: Breadcrumb[];
63
+ deviceInfo: DeviceInfo | null;
64
+ }
65
+ interface GlitchgrabProviderProps {
66
+ token: string;
67
+ baseUrl?: string;
68
+ onError?: (error: Error) => void;
69
+ onReportSent?: (result: ReportResult) => void;
70
+ breadcrumbs?: boolean;
71
+ maxBreadcrumbs?: number;
72
+ children: ReactNode;
73
+ fallback?: ReactNode;
74
+ }
75
+ interface ReportButtonProps {
76
+ position?: "bottom-right" | "bottom-left";
77
+ label?: string;
78
+ className?: string;
79
+ /** Allow reporting feature requests, questions, not just bugs */
80
+ types?: ReportType[];
81
+ }
82
+ interface UseGlitchgrabReturn {
83
+ /** Report a bug programmatically */
84
+ reportBug: (description: string, metadata?: Record<string, string>) => Promise<ReportResult | null>;
85
+ /** Report with a specific type */
86
+ report: (type: ReportType, description: string, metadata?: Record<string, string>) => Promise<ReportResult | null>;
87
+ /** Add a custom breadcrumb */
88
+ addBreadcrumb: (message: string, data?: Record<string, string>) => void;
89
+ /** The token being used */
90
+ token: string;
91
+ /** The base URL of the Glitchgrab API */
92
+ baseUrl: string;
93
+ }
94
+
95
+ /**
96
+ * Hook to access Glitchgrab in your components.
97
+ *
98
+ * @example
99
+ * ```tsx
100
+ * const { reportBug, report, addBreadcrumb } = useGlitchgrab();
101
+ *
102
+ * // Report a bug
103
+ * reportBug("Login button crashes on mobile");
104
+ *
105
+ * // Report a feature request
106
+ * report("FEATURE_REQUEST", "Add dark mode");
107
+ *
108
+ * // Add a custom breadcrumb
109
+ * addBreadcrumb("User clicked checkout", { cartItems: "3" });
110
+ * ```
111
+ */
112
+ declare function useGlitchgrab(): UseGlitchgrabReturn;
113
+ declare function GlitchgrabProvider(props: GlitchgrabProviderProps): react_jsx_runtime.JSX.Element;
114
+
115
+ declare function ReportButton({ position, label, className, }: ReportButtonProps): react_jsx_runtime.JSX.Element;
116
+
117
+ interface ErrorBoundaryProps {
118
+ token: string;
119
+ baseUrl?: string;
120
+ onError?: (error: Error) => void;
121
+ fallback?: React.ReactNode;
122
+ visitedPages: string[];
123
+ children: React.ReactNode;
124
+ }
125
+ interface ErrorBoundaryState {
126
+ hasError: boolean;
127
+ }
128
+ declare class GlitchgrabErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
129
+ constructor(props: ErrorBoundaryProps);
130
+ static getDerivedStateFromError(): ErrorBoundaryState;
131
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
132
+ render(): React.ReactNode;
133
+ }
134
+
135
+ declare function initBreadcrumbs(max?: number): void;
136
+ declare function addBreadcrumb(type: BreadcrumbType, message: string, data?: Record<string, string>): void;
137
+ declare function getBreadcrumbs(): Breadcrumb[];
138
+ declare function clearBreadcrumbs(): void;
139
+
140
+ declare function sanitizeUrl(url: string): string;
141
+ declare function captureDeviceInfo(): DeviceInfo | null;
142
+ declare function captureContext(visitedPages: string[]): CapturedContext;
143
+ /**
144
+ * Send a report and return the result.
145
+ * Never throws — returns null on failure.
146
+ */
147
+ declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<ReportResult | null>;
148
+
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 };
@@ -0,0 +1,149 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React, { ReactNode } from 'react';
3
+
4
+ interface GlitchgrabConfig {
5
+ token: string;
6
+ baseUrl?: string;
7
+ onError?: (error: Error) => void;
8
+ /** Called after a report is sent — use to sync with your own ticket system */
9
+ onReportSent?: (result: ReportResult) => void;
10
+ /** Enable breadcrumb tracking (default: true) */
11
+ breadcrumbs?: boolean;
12
+ /** Max breadcrumbs to keep (default: 50) */
13
+ maxBreadcrumbs?: number;
14
+ }
15
+ type ReportType = "BUG" | "FEATURE_REQUEST" | "QUESTION" | "OTHER";
16
+ interface ReportPayload {
17
+ token: string;
18
+ source: "SDK_AUTO" | "SDK_USER_REPORT";
19
+ type?: ReportType;
20
+ description?: string;
21
+ errorMessage?: string;
22
+ errorStack?: string;
23
+ componentStack?: string;
24
+ pageUrl?: string;
25
+ userAgent?: string;
26
+ breadcrumbs?: Breadcrumb[];
27
+ deviceInfo?: DeviceInfo;
28
+ metadata?: Record<string, string>;
29
+ }
30
+ interface ReportResult {
31
+ success: boolean;
32
+ reportId?: string;
33
+ issueUrl?: string;
34
+ issueNumber?: number;
35
+ title?: string;
36
+ intent?: string;
37
+ message?: string;
38
+ }
39
+ type BreadcrumbType = "console" | "navigation" | "api" | "click" | "error" | "custom";
40
+ interface Breadcrumb {
41
+ type: BreadcrumbType;
42
+ message: string;
43
+ timestamp: string;
44
+ data?: Record<string, string>;
45
+ }
46
+ interface DeviceInfo {
47
+ screenWidth: number;
48
+ screenHeight: number;
49
+ viewportWidth: number;
50
+ viewportHeight: number;
51
+ platform: string;
52
+ language: string;
53
+ online: boolean;
54
+ colorScheme: string;
55
+ devicePixelRatio: number;
56
+ }
57
+ interface CapturedContext {
58
+ url: string;
59
+ userAgent: string;
60
+ timestamp: string;
61
+ visitedPages: string[];
62
+ breadcrumbs: Breadcrumb[];
63
+ deviceInfo: DeviceInfo | null;
64
+ }
65
+ interface GlitchgrabProviderProps {
66
+ token: string;
67
+ baseUrl?: string;
68
+ onError?: (error: Error) => void;
69
+ onReportSent?: (result: ReportResult) => void;
70
+ breadcrumbs?: boolean;
71
+ maxBreadcrumbs?: number;
72
+ children: ReactNode;
73
+ fallback?: ReactNode;
74
+ }
75
+ interface ReportButtonProps {
76
+ position?: "bottom-right" | "bottom-left";
77
+ label?: string;
78
+ className?: string;
79
+ /** Allow reporting feature requests, questions, not just bugs */
80
+ types?: ReportType[];
81
+ }
82
+ interface UseGlitchgrabReturn {
83
+ /** Report a bug programmatically */
84
+ reportBug: (description: string, metadata?: Record<string, string>) => Promise<ReportResult | null>;
85
+ /** Report with a specific type */
86
+ report: (type: ReportType, description: string, metadata?: Record<string, string>) => Promise<ReportResult | null>;
87
+ /** Add a custom breadcrumb */
88
+ addBreadcrumb: (message: string, data?: Record<string, string>) => void;
89
+ /** The token being used */
90
+ token: string;
91
+ /** The base URL of the Glitchgrab API */
92
+ baseUrl: string;
93
+ }
94
+
95
+ /**
96
+ * Hook to access Glitchgrab in your components.
97
+ *
98
+ * @example
99
+ * ```tsx
100
+ * const { reportBug, report, addBreadcrumb } = useGlitchgrab();
101
+ *
102
+ * // Report a bug
103
+ * reportBug("Login button crashes on mobile");
104
+ *
105
+ * // Report a feature request
106
+ * report("FEATURE_REQUEST", "Add dark mode");
107
+ *
108
+ * // Add a custom breadcrumb
109
+ * addBreadcrumb("User clicked checkout", { cartItems: "3" });
110
+ * ```
111
+ */
112
+ declare function useGlitchgrab(): UseGlitchgrabReturn;
113
+ declare function GlitchgrabProvider(props: GlitchgrabProviderProps): react_jsx_runtime.JSX.Element;
114
+
115
+ declare function ReportButton({ position, label, className, }: ReportButtonProps): react_jsx_runtime.JSX.Element;
116
+
117
+ interface ErrorBoundaryProps {
118
+ token: string;
119
+ baseUrl?: string;
120
+ onError?: (error: Error) => void;
121
+ fallback?: React.ReactNode;
122
+ visitedPages: string[];
123
+ children: React.ReactNode;
124
+ }
125
+ interface ErrorBoundaryState {
126
+ hasError: boolean;
127
+ }
128
+ declare class GlitchgrabErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
129
+ constructor(props: ErrorBoundaryProps);
130
+ static getDerivedStateFromError(): ErrorBoundaryState;
131
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
132
+ render(): React.ReactNode;
133
+ }
134
+
135
+ declare function initBreadcrumbs(max?: number): void;
136
+ declare function addBreadcrumb(type: BreadcrumbType, message: string, data?: Record<string, string>): void;
137
+ declare function getBreadcrumbs(): Breadcrumb[];
138
+ declare function clearBreadcrumbs(): void;
139
+
140
+ declare function sanitizeUrl(url: string): string;
141
+ declare function captureDeviceInfo(): DeviceInfo | null;
142
+ declare function captureContext(visitedPages: string[]): CapturedContext;
143
+ /**
144
+ * Send a report and return the result.
145
+ * Never throws — returns null on failure.
146
+ */
147
+ declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<ReportResult | null>;
148
+
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 };