/** * Configuration for the error tracker. * Pass to `init()` at app startup. */ interface ErrorTrackerConfig { /** GitHub Personal Access Token with `repo` scope */ githubToken: string; /** Repository in "owner/repo" format */ githubRepo: string; /** Environment name included in issue body. Default: "development" */ environment?: string; /** Additional labels applied to created issues (beyond "error-report"). */ labels?: string[]; /** Create missing labels (`error-report`, fingerprints, extras) on first use. Default: true */ autoCreateLabels?: boolean; /** Kill switch. Default: true */ enabled?: boolean; /** Called when GitHub API fails. Default: console.error */ onError?: (err: unknown) => void; /** Max new issues created per minute. Default: 10 */ rateLimitPerMinute?: number; /** Suppress duplicate fingerprints within this window (ms). Default: 60_000 */ dedupeWindowMs?: number; /** Reopen closed issues on recurrence instead of ignoring. Default: true */ reopenClosed?: boolean; /** * How bug-report screenshots are stored. * `"user-attachment"` (default): GitHub user-attachments CDN (`gh --attach`). * `"branch"`: Contents API + optional proxy. GHES / existing setups only. */ screenshotUpload?: 'user-attachment' | 'branch'; /** * Branch where bug-report screenshots are committed when * `screenshotUpload` is `"branch"`. Default: "bug-report-screenshots" */ screenshotBranch?: string; /** * Proxy base URL, no trailing slash. Only used when `screenshotUpload` is `"branch"`. */ appBaseUrl?: string; /** Path segment for the screenshot proxy route. Default: "api/bug-screenshots" */ screenshotProxyPath?: string; } /** * Additional context attached to a captured error. */ interface ErrorContext { tags?: Record; extras?: Record; user?: { id: string; email?: string; }; requestUrl?: string; serverName?: string; } /** Who filed a bug report. */ interface BugReportReporter { id: string; email?: string; name?: string; role?: string; } /** Raw screenshot bytes to attach to a bug report. */ interface BugReportScreenshot { data: Uint8Array; filename: string; /** Defaults to "image/png". */ contentType?: string; } /** Input to `captureBugReport()`. */ interface BugReportInput { /** User-written description of the problem. */ message: string; /** URL of the page the report was filed from. */ pageUrl: string; reporter: BugReportReporter; /** Optional pin location as a percentage of the viewport (0–100). */ pin?: { x: number; y: number; }; /** Free-form environment metadata rendered into the issue body. */ metadata?: Record; /** Optional screenshot, uploaded as a GitHub user attachment and embedded. */ screenshot?: BugReportScreenshot; /** Extra labels added alongside the default "bug-report" label. */ labels?: string[]; } /** Result of `captureBugReport()`. */ interface BugReportResult { issueNumber: number; issueUrl: string; screenshotUrl?: string; } /** Options for `fetchIssueImage()` — the screenshot read-through proxy. */ interface FetchIssueImageOptions { /** GitHub token with contents read on the repo. */ token: string; /** Repository in "owner/repo" format. */ repo: string; /** Image path of shape `yyyy/mm/`. */ path: string; /** Branch the image was committed to. Default: "bug-report-screenshots" */ branch?: string; } /** Result of `fetchIssueImage()`. */ interface FetchIssueImageResult { /** HTTP status to relay (200, 400, 404, 502, 503). */ status: number; /** Image bytes, present on 200. */ body?: ArrayBuffer; /** MIME type, present on 200. */ contentType?: string; } /** * Error tracker client — the main orchestrator. * * Singleton pattern: call `init()` once at startup, then use * `captureException()` / `captureMessage()` anywhere in your app. * All GitHub API calls are fire-and-forget. Call `flush()` in * serverless environments to wait for pending operations before returning. */ /** * Initialize the error tracker. Call once at app startup. */ declare function init(cfg: ErrorTrackerConfig): void; /** * Capture an exception. Fire-and-forget — use `flush()` if you * need to wait for the GitHub API call to complete. */ declare function captureException(error: Error, context?: ErrorContext): void; /** * Capture a plain message as an error event. */ declare function captureMessage(message: string, level?: 'error' | 'warning', context?: ErrorContext): void; /** * Capture a user-submitted bug report as a GitHub issue, optionally with a * screenshot. Unlike `captureException`, this is NOT fire-and-forget or deduped * — it awaits the GitHub calls and returns the created issue so the caller (an * API route) can surface the result. Requires `init()` to have been called. * * If `input.screenshot` is set, the image is uploaded as a GitHub user * attachment by default (same path as `gh issue create --attach`) and * embedded in the issue. Set `screenshotUpload: "branch"` to keep the * Contents-API + proxy path (GitHub Enterprise Server / existing setups). */ declare function captureBugReport(input: BugReportInput): Promise; /** * Wait for all pending error reports to complete. * Call before serverless function returns. */ declare function flush(): Promise; /** * Screenshot read-through proxy for `screenshotUpload: "branch"` (legacy). * Default bug reports use GitHub user-attachments and do not need this. */ declare function fetchIssueImage(opts: FetchIssueImageOptions): Promise; /** * Route-handler wrapper — capture every server error a handler produces. * * Frameworks surface server errors two ways: a handler can THROW, or it can * deliberately RETURN a 5xx response. A thrown-error hook (e.g. Next.js * `onRequestError`) only sees the first. `withErrorReporting` covers both, so * "a 500 is a server error → it files an issue" holds no matter how the 500 is * produced. * * Framework-agnostic: works with anything whose handler takes a Web `Request` * first and returns a `Response` (Next.js route handlers, Remix, Hono, * Cloudflare Workers, plain fetch handlers). Edge-native, zero deps. * * export const POST = withErrorReporting(async (req) => { ... }) * * Requires `init()` to have run. Capture is deduplicated, so even if a thrown * error is ALSO reported by a framework hook, only one issue is created. */ interface WithErrorReportingOptions { /** Report responses whose status is >= this. Default: 500. */ minStatus?: number; /** Also capture thrown errors (not just returned 5xx). Default: true. */ catchThrows?: boolean; /** * Re-throw a caught error after reporting it (so the framework still handles * it). Default: true. When false, the error is swallowed and a 500 response * is returned instead. */ rethrow?: boolean; /** Extra context merged into every report (tags, user, etc.). */ context?: ErrorContext; } declare function withErrorReporting(handler: (...args: A) => Response | Promise, options?: WithErrorReportingOptions): (...args: A) => Promise; export { type BugReportInput, type BugReportReporter, type BugReportResult, type BugReportScreenshot, type ErrorContext, type ErrorTrackerConfig, type FetchIssueImageOptions, type FetchIssueImageResult, type WithErrorReportingOptions, captureBugReport, captureException, captureMessage, fetchIssueImage, flush, init, withErrorReporting };