bugstack-sdk 1.0.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.
@@ -0,0 +1,391 @@
1
+ import { NextRequest } from 'next/server';
2
+
3
+ /**
4
+ * Configuration options for the BugStack error capture SDK
5
+ */
6
+ interface ErrorCaptureConfig {
7
+ /**
8
+ * API key for authenticating with the BugStack error service
9
+ */
10
+ apiKey: string;
11
+ /**
12
+ * URL of the BugStack error service endpoint
13
+ * @default process.env.BUGSTACK_ENDPOINT || "http://localhost:3001/api/errors"
14
+ */
15
+ endpoint?: string;
16
+ /**
17
+ * Unique identifier for your project
18
+ */
19
+ projectId?: string;
20
+ /**
21
+ * Environment name (e.g., "production", "staging", "development")
22
+ * @default process.env.NODE_ENV || "development"
23
+ */
24
+ environment?: string;
25
+ /**
26
+ * Enable or disable error capture
27
+ * Useful for disabling in certain environments
28
+ * @default true
29
+ */
30
+ enabled?: boolean;
31
+ /**
32
+ * Whether to capture request body in error reports
33
+ * @default true
34
+ */
35
+ captureRequestBody?: boolean;
36
+ /**
37
+ * Whether to capture query parameters in error reports
38
+ * @default true
39
+ */
40
+ captureQueryParams?: boolean;
41
+ /**
42
+ * Whether to capture request headers in error reports
43
+ * @default true
44
+ */
45
+ captureHeaders?: boolean;
46
+ /**
47
+ * Maximum size of request body to capture (in bytes)
48
+ * Bodies larger than this will be truncated
49
+ * @default 10000 (10KB)
50
+ */
51
+ maxBodySize?: number;
52
+ /**
53
+ * Additional fields to redact from request body and headers
54
+ * Common sensitive fields are redacted by default
55
+ */
56
+ redactFields?: string[];
57
+ /**
58
+ * Custom metadata to include with every error report
59
+ */
60
+ metadata?: Record<string, unknown>;
61
+ /**
62
+ * Timeout for sending error reports (in milliseconds)
63
+ * @default 5000
64
+ */
65
+ timeout?: number;
66
+ /**
67
+ * Whether to log SDK errors to console
68
+ * @default true in development, false in production
69
+ */
70
+ debug?: boolean;
71
+ /**
72
+ * Custom error filter function
73
+ * Return false to skip reporting certain errors
74
+ */
75
+ shouldCapture?: (error: Error, request: NextRequest) => boolean;
76
+ /**
77
+ * Hook called before sending error report
78
+ * Can be used to modify or enrich error data
79
+ */
80
+ beforeSend?: (error: CapturedError) => CapturedError | null;
81
+ }
82
+ /**
83
+ * Resolved configuration with all defaults applied
84
+ */
85
+ interface ResolvedConfig {
86
+ apiKey: string;
87
+ endpoint: string;
88
+ projectId: string;
89
+ environment: string;
90
+ enabled: boolean;
91
+ captureRequestBody: boolean;
92
+ captureQueryParams: boolean;
93
+ captureHeaders: boolean;
94
+ maxBodySize: number;
95
+ redactFields: string[];
96
+ metadata: Record<string, unknown>;
97
+ timeout: number;
98
+ debug: boolean;
99
+ shouldCapture?: (error: Error, request: NextRequest) => boolean;
100
+ beforeSend?: (error: CapturedError) => CapturedError | null;
101
+ }
102
+ /**
103
+ * Captured error data sent to the error service
104
+ */
105
+ interface CapturedError {
106
+ /**
107
+ * Unique identifier for this error instance
108
+ */
109
+ id: string;
110
+ /**
111
+ * Error message
112
+ */
113
+ message: string;
114
+ /**
115
+ * Error name/type (e.g., "TypeError", "ReferenceError")
116
+ */
117
+ name: string;
118
+ /**
119
+ * Full stack trace
120
+ */
121
+ stack?: string;
122
+ /**
123
+ * Parsed stack frames for easier analysis
124
+ */
125
+ stackFrames?: StackFrame[];
126
+ /**
127
+ * ISO 8601 timestamp when the error occurred
128
+ */
129
+ timestamp: string;
130
+ /**
131
+ * API route path (e.g., "/api/users/[id]")
132
+ */
133
+ route: string;
134
+ /**
135
+ * HTTP method (GET, POST, etc.)
136
+ */
137
+ method: string;
138
+ /**
139
+ * HTTP status code
140
+ * @default 500
141
+ */
142
+ statusCode: number;
143
+ /**
144
+ * Full request URL
145
+ */
146
+ url: string;
147
+ /**
148
+ * Query parameters (sanitized)
149
+ */
150
+ queryParams?: Record<string, string>;
151
+ /**
152
+ * Request body (sanitized and truncated)
153
+ */
154
+ requestBody?: unknown;
155
+ /**
156
+ * Request headers (sanitized)
157
+ */
158
+ requestHeaders?: Record<string, string>;
159
+ /**
160
+ * Environment (production, staging, development)
161
+ */
162
+ environment: string;
163
+ /**
164
+ * Project identifier
165
+ */
166
+ projectId?: string;
167
+ /**
168
+ * Route parameters (e.g., { id: "123" })
169
+ */
170
+ routeParams?: Record<string, string>;
171
+ /**
172
+ * Additional custom metadata
173
+ */
174
+ metadata?: Record<string, unknown>;
175
+ /**
176
+ * SDK version that captured this error
177
+ */
178
+ sdkVersion: string;
179
+ /**
180
+ * Node.js version
181
+ */
182
+ nodeVersion: string;
183
+ /**
184
+ * Next.js version (if available)
185
+ */
186
+ nextVersion?: string;
187
+ }
188
+ /**
189
+ * Parsed stack frame for easier debugging
190
+ */
191
+ interface StackFrame {
192
+ /**
193
+ * Function name
194
+ */
195
+ function?: string;
196
+ /**
197
+ * File path
198
+ */
199
+ file?: string;
200
+ /**
201
+ * Line number
202
+ */
203
+ line?: number;
204
+ /**
205
+ * Column number
206
+ */
207
+ column?: number;
208
+ /**
209
+ * Whether this frame is from node_modules
210
+ */
211
+ isNodeModule?: boolean;
212
+ /**
213
+ * Whether this frame is from internal Node.js code
214
+ */
215
+ isInternal?: boolean;
216
+ }
217
+ /**
218
+ * Payload sent to the error service
219
+ */
220
+ interface ErrorReportPayload {
221
+ /**
222
+ * The captured error data
223
+ */
224
+ error: CapturedError;
225
+ /**
226
+ * Source code context around the error (if available)
227
+ */
228
+ sourceContext?: SourceContext;
229
+ }
230
+ /**
231
+ * Source code context around the error location
232
+ */
233
+ interface SourceContext {
234
+ /**
235
+ * File path
236
+ */
237
+ filePath: string;
238
+ /**
239
+ * Line number where error occurred
240
+ */
241
+ lineNumber: number;
242
+ /**
243
+ * Lines of code before the error line
244
+ */
245
+ preContext: string[];
246
+ /**
247
+ * The line where the error occurred
248
+ */
249
+ contextLine: string;
250
+ /**
251
+ * Lines of code after the error line
252
+ */
253
+ postContext: string[];
254
+ }
255
+ /**
256
+ * Next.js App Router route handler type
257
+ */
258
+ type NextRouteHandler<T = unknown> = (request: NextRequest, context: RouteContext<T>) => Response | Promise<Response>;
259
+ /**
260
+ * Route context passed to Next.js handlers
261
+ */
262
+ interface RouteContext<T = unknown> {
263
+ params: T extends Record<string, string> ? T : Record<string, string>;
264
+ }
265
+ /**
266
+ * Options that can be passed to withErrorCapture per-route
267
+ */
268
+ interface RouteOptions {
269
+ /**
270
+ * Override the status code reported for errors in this route
271
+ */
272
+ statusCode?: number;
273
+ /**
274
+ * Additional metadata specific to this route
275
+ */
276
+ metadata?: Record<string, unknown>;
277
+ /**
278
+ * Custom error filter for this route
279
+ */
280
+ shouldCapture?: (error: Error) => boolean;
281
+ }
282
+ type BugStackConfig = ErrorCaptureConfig;
283
+
284
+ /**
285
+ * Type for the wrapped handler function
286
+ */
287
+ type WrappedHandler<T> = (request: NextRequest, context: RouteContext<T>) => Response | Promise<Response>;
288
+ /**
289
+ * Wrap a Next.js App Router API route handler with error capture
290
+ *
291
+ * @example
292
+ * ```typescript
293
+ * // Basic usage
294
+ * export const GET = withErrorCapture(async (request) => {
295
+ * return NextResponse.json({ data: "hello" });
296
+ * });
297
+ *
298
+ * // With configuration (first call only)
299
+ * export const GET = withErrorCapture(
300
+ * async (request) => {
301
+ * return NextResponse.json({ data: "hello" });
302
+ * },
303
+ * { apiKey: "your-api-key" }
304
+ * );
305
+ *
306
+ * // With route-specific options
307
+ * export const POST = withErrorCapture(
308
+ * async (request) => {
309
+ * return NextResponse.json({ data: "created" });
310
+ * },
311
+ * undefined,
312
+ * { statusCode: 400, metadata: { operation: "create" } }
313
+ * );
314
+ * ```
315
+ */
316
+ declare function withErrorCapture<T = Record<string, string>>(handler: WrappedHandler<T>, config?: ErrorCaptureConfig, routeOptions?: RouteOptions): WrappedHandler<T>;
317
+ declare const withBugStack: typeof withErrorCapture;
318
+
319
+ /**
320
+ * BugStack Error Capture Client
321
+ *
322
+ * Singleton client for capturing and reporting errors to the BugStack service.
323
+ */
324
+ declare class ErrorCaptureClient {
325
+ private config;
326
+ private static instance;
327
+ constructor(config: ErrorCaptureConfig);
328
+ /**
329
+ * Initialize the singleton client instance
330
+ */
331
+ static init(config: ErrorCaptureConfig): ErrorCaptureClient;
332
+ /**
333
+ * Get the singleton client instance
334
+ */
335
+ static getInstance(): ErrorCaptureClient | null;
336
+ /**
337
+ * Check if the client has been initialized
338
+ */
339
+ static isInitialized(): boolean;
340
+ /**
341
+ * Reset the client (mainly for testing)
342
+ */
343
+ static reset(): void;
344
+ /**
345
+ * Report an error to the BugStack service
346
+ */
347
+ reportError(error: CapturedError, sourceContext?: SourceContext): Promise<boolean>;
348
+ /**
349
+ * Get the resolved configuration
350
+ */
351
+ getConfig(): ResolvedConfig;
352
+ /**
353
+ * Check if a field should be redacted
354
+ */
355
+ shouldRedact(fieldName: string): boolean;
356
+ /**
357
+ * Get the SDK version
358
+ */
359
+ static getVersion(): string;
360
+ private log;
361
+ private logError;
362
+ }
363
+ declare const BugStackClient: typeof ErrorCaptureClient;
364
+
365
+ /**
366
+ * Parse a V8 stack trace into structured frames
367
+ */
368
+ declare function parseStackTrace(stack: string | undefined): StackFrame[];
369
+ /**
370
+ * Get the first application frame (non-node_modules, non-internal)
371
+ */
372
+ declare function getFirstAppFrame(frames: StackFrame[]): StackFrame | undefined;
373
+ /**
374
+ * Filter stack frames to only include application code
375
+ */
376
+ declare function getAppFrames(frames: StackFrame[]): StackFrame[];
377
+
378
+ /**
379
+ * Sanitize headers by removing sensitive values
380
+ */
381
+ declare function sanitizeHeaders(headers: Headers, client?: ErrorCaptureClient | null): Record<string, string>;
382
+ /**
383
+ * Sanitize query parameters by redacting sensitive values
384
+ */
385
+ declare function sanitizeQueryParams(url: URL, client?: ErrorCaptureClient | null): Record<string, string>;
386
+ /**
387
+ * Recursively sanitize an object by redacting sensitive fields
388
+ */
389
+ declare function sanitizeObject(obj: unknown, client?: ErrorCaptureClient | null, maxDepth?: number, currentDepth?: number): unknown;
390
+
391
+ export { BugStackClient, type BugStackConfig, type CapturedError, ErrorCaptureClient, type ErrorCaptureConfig, type ErrorReportPayload, type NextRouteHandler, type ResolvedConfig, type RouteContext, type RouteOptions, type SourceContext, type StackFrame, getAppFrames, getFirstAppFrame, parseStackTrace, sanitizeHeaders, sanitizeObject, sanitizeQueryParams, withBugStack, withErrorCapture };