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.
package/dist/index.mjs ADDED
@@ -0,0 +1,503 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/client.ts
9
+ var SDK_VERSION = "1.0.0";
10
+ var DEFAULT_ENDPOINT = "http://localhost:3001/api/capture";
11
+ var DEFAULT_TIMEOUT = 5e3;
12
+ var DEFAULT_MAX_BODY_SIZE = 1e4;
13
+ var DEFAULT_REDACT_FIELDS = [
14
+ "password",
15
+ "secret",
16
+ "token",
17
+ "apikey",
18
+ "api_key",
19
+ "apiKey",
20
+ "authorization",
21
+ "auth",
22
+ "credential",
23
+ "private",
24
+ "credit_card",
25
+ "creditcard",
26
+ "card_number",
27
+ "cvv",
28
+ "ssn",
29
+ "social_security"
30
+ ];
31
+ var ErrorCaptureClient = class _ErrorCaptureClient {
32
+ config;
33
+ static instance = null;
34
+ constructor(config) {
35
+ const isProduction = process.env.NODE_ENV === "production";
36
+ this.config = {
37
+ apiKey: config.apiKey,
38
+ endpoint: config.endpoint ?? process.env.BUGSTACK_ENDPOINT ?? DEFAULT_ENDPOINT,
39
+ projectId: config.projectId ?? process.env.BUGSTACK_PROJECT_ID ?? "",
40
+ environment: config.environment ?? process.env.NODE_ENV ?? "development",
41
+ enabled: config.enabled ?? true,
42
+ captureRequestBody: config.captureRequestBody ?? true,
43
+ captureQueryParams: config.captureQueryParams ?? true,
44
+ captureHeaders: config.captureHeaders ?? true,
45
+ maxBodySize: config.maxBodySize ?? DEFAULT_MAX_BODY_SIZE,
46
+ redactFields: [
47
+ ...DEFAULT_REDACT_FIELDS,
48
+ ...config.redactFields ?? []
49
+ ],
50
+ metadata: config.metadata ?? {},
51
+ timeout: config.timeout ?? DEFAULT_TIMEOUT,
52
+ debug: config.debug ?? !isProduction,
53
+ shouldCapture: config.shouldCapture,
54
+ beforeSend: config.beforeSend
55
+ };
56
+ }
57
+ /**
58
+ * Initialize the singleton client instance
59
+ */
60
+ static init(config) {
61
+ _ErrorCaptureClient.instance = new _ErrorCaptureClient(config);
62
+ return _ErrorCaptureClient.instance;
63
+ }
64
+ /**
65
+ * Get the singleton client instance
66
+ */
67
+ static getInstance() {
68
+ return _ErrorCaptureClient.instance;
69
+ }
70
+ /**
71
+ * Check if the client has been initialized
72
+ */
73
+ static isInitialized() {
74
+ return _ErrorCaptureClient.instance !== null;
75
+ }
76
+ /**
77
+ * Reset the client (mainly for testing)
78
+ */
79
+ static reset() {
80
+ _ErrorCaptureClient.instance = null;
81
+ }
82
+ /**
83
+ * Report an error to the BugStack service
84
+ */
85
+ async reportError(error, sourceContext) {
86
+ if (!this.config.enabled) {
87
+ this.log("Error capture is disabled, skipping report");
88
+ return false;
89
+ }
90
+ let errorToSend = error;
91
+ if (this.config.beforeSend) {
92
+ const modified = this.config.beforeSend(error);
93
+ if (modified === null) {
94
+ this.log("Error filtered by beforeSend hook");
95
+ return false;
96
+ }
97
+ errorToSend = modified;
98
+ }
99
+ const payload = {
100
+ error: {
101
+ ...errorToSend,
102
+ projectId: this.config.projectId || errorToSend.projectId,
103
+ environment: this.config.environment,
104
+ metadata: {
105
+ ...this.config.metadata,
106
+ ...errorToSend.metadata
107
+ }
108
+ },
109
+ sourceContext
110
+ };
111
+ try {
112
+ const controller = new AbortController();
113
+ const timeoutId = setTimeout(
114
+ () => controller.abort(),
115
+ this.config.timeout
116
+ );
117
+ const response = await fetch(this.config.endpoint, {
118
+ method: "POST",
119
+ headers: {
120
+ "Content-Type": "application/json",
121
+ "X-BugStack-API-Key": this.config.apiKey,
122
+ "X-BugStack-SDK-Version": SDK_VERSION
123
+ },
124
+ body: JSON.stringify(payload),
125
+ signal: controller.signal
126
+ });
127
+ clearTimeout(timeoutId);
128
+ if (!response.ok) {
129
+ this.logError(
130
+ `Failed to report error: HTTP ${response.status} ${response.statusText}`
131
+ );
132
+ return false;
133
+ }
134
+ this.log(`Error reported successfully: ${error.id}`);
135
+ return true;
136
+ } catch (err) {
137
+ if (err instanceof Error && err.name === "AbortError") {
138
+ this.logError(`Error report timed out after ${this.config.timeout}ms`);
139
+ } else {
140
+ this.logError("Failed to send error report:", err);
141
+ }
142
+ return false;
143
+ }
144
+ }
145
+ /**
146
+ * Get the resolved configuration
147
+ */
148
+ getConfig() {
149
+ return { ...this.config };
150
+ }
151
+ /**
152
+ * Check if a field should be redacted
153
+ */
154
+ shouldRedact(fieldName) {
155
+ const lowerField = fieldName.toLowerCase();
156
+ return this.config.redactFields.some(
157
+ (redact) => lowerField.includes(redact.toLowerCase()) || redact.toLowerCase().includes(lowerField)
158
+ );
159
+ }
160
+ /**
161
+ * Get the SDK version
162
+ */
163
+ static getVersion() {
164
+ return SDK_VERSION;
165
+ }
166
+ log(message) {
167
+ if (this.config.debug) {
168
+ console.log(`[BugStack] ${message}`);
169
+ }
170
+ }
171
+ logError(message, error) {
172
+ if (this.config.debug) {
173
+ if (error) {
174
+ console.error(`[BugStack] ${message}`, error);
175
+ } else {
176
+ console.error(`[BugStack] ${message}`);
177
+ }
178
+ }
179
+ }
180
+ };
181
+ var BugStackClient = ErrorCaptureClient;
182
+
183
+ // src/sanitize.ts
184
+ var REDACT_PLACEHOLDER = "[REDACTED]";
185
+ var TRUNCATE_PLACEHOLDER = "[TRUNCATED]";
186
+ var SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
187
+ "authorization",
188
+ "cookie",
189
+ "set-cookie",
190
+ "x-api-key",
191
+ "x-auth-token",
192
+ "x-bugstack-api-key",
193
+ "proxy-authorization",
194
+ "www-authenticate"
195
+ ]);
196
+ function sanitizeHeaders(headers, client) {
197
+ const sanitized = {};
198
+ headers.forEach((value, key) => {
199
+ const lowerKey = key.toLowerCase();
200
+ if (SENSITIVE_HEADERS.has(lowerKey)) {
201
+ sanitized[key] = REDACT_PLACEHOLDER;
202
+ return;
203
+ }
204
+ if (client?.shouldRedact(key)) {
205
+ sanitized[key] = REDACT_PLACEHOLDER;
206
+ return;
207
+ }
208
+ sanitized[key] = value;
209
+ });
210
+ return sanitized;
211
+ }
212
+ function sanitizeQueryParams(url, client) {
213
+ const sanitized = {};
214
+ url.searchParams.forEach((value, key) => {
215
+ if (client?.shouldRedact(key)) {
216
+ sanitized[key] = REDACT_PLACEHOLDER;
217
+ } else {
218
+ sanitized[key] = value;
219
+ }
220
+ });
221
+ return sanitized;
222
+ }
223
+ function sanitizeObject(obj, client, maxDepth = 10, currentDepth = 0) {
224
+ if (currentDepth > maxDepth) {
225
+ return TRUNCATE_PLACEHOLDER;
226
+ }
227
+ if (obj === null || obj === void 0) {
228
+ return obj;
229
+ }
230
+ if (typeof obj !== "object") {
231
+ return obj;
232
+ }
233
+ if (Array.isArray(obj)) {
234
+ return obj.map(
235
+ (item) => sanitizeObject(item, client, maxDepth, currentDepth + 1)
236
+ );
237
+ }
238
+ const sanitized = {};
239
+ for (const [key, value] of Object.entries(obj)) {
240
+ if (client?.shouldRedact(key)) {
241
+ sanitized[key] = REDACT_PLACEHOLDER;
242
+ } else if (typeof value === "object" && value !== null) {
243
+ sanitized[key] = sanitizeObject(value, client, maxDepth, currentDepth + 1);
244
+ } else {
245
+ sanitized[key] = value;
246
+ }
247
+ }
248
+ return sanitized;
249
+ }
250
+ function truncateBody(data, maxSize) {
251
+ const serialized = JSON.stringify(data);
252
+ if (serialized.length <= maxSize) {
253
+ return { body: data, truncated: false };
254
+ }
255
+ if (typeof data === "string") {
256
+ return {
257
+ body: data.slice(0, maxSize) + `... ${TRUNCATE_PLACEHOLDER}`,
258
+ truncated: true
259
+ };
260
+ }
261
+ return {
262
+ body: {
263
+ __truncated: true,
264
+ __originalSize: serialized.length,
265
+ __maxSize: maxSize,
266
+ preview: serialized.slice(0, maxSize)
267
+ },
268
+ truncated: true
269
+ };
270
+ }
271
+ async function safeParseBody(request, maxSize, client) {
272
+ try {
273
+ const cloned = request.clone();
274
+ const contentType = cloned.headers.get("content-type") ?? "";
275
+ if (contentType.includes("application/json")) {
276
+ const text = await cloned.text();
277
+ if (text.length > maxSize) {
278
+ return {
279
+ body: {
280
+ __truncated: true,
281
+ __originalSize: text.length,
282
+ preview: text.slice(0, maxSize)
283
+ },
284
+ truncated: true
285
+ };
286
+ }
287
+ try {
288
+ const parsed = JSON.parse(text);
289
+ const sanitized = sanitizeObject(parsed, client);
290
+ return truncateBody(sanitized, maxSize);
291
+ } catch {
292
+ return truncateBody(text, maxSize);
293
+ }
294
+ }
295
+ if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
296
+ try {
297
+ const formData = await cloned.formData();
298
+ const data = {};
299
+ formData.forEach((value, key) => {
300
+ if (value instanceof File) {
301
+ data[key] = {
302
+ type: "file",
303
+ name: value.name,
304
+ size: value.size,
305
+ mimeType: value.type
306
+ };
307
+ } else if (client?.shouldRedact(key)) {
308
+ data[key] = REDACT_PLACEHOLDER;
309
+ } else {
310
+ data[key] = value;
311
+ }
312
+ });
313
+ return truncateBody(data, maxSize);
314
+ } catch {
315
+ return { body: "[FormData parsing failed]", truncated: false };
316
+ }
317
+ }
318
+ if (contentType.includes("text/")) {
319
+ const text = await cloned.text();
320
+ return truncateBody(text, maxSize);
321
+ }
322
+ return {
323
+ body: {
324
+ __contentType: contentType,
325
+ __note: "Body not captured for this content type"
326
+ },
327
+ truncated: false
328
+ };
329
+ } catch (err) {
330
+ return null;
331
+ }
332
+ }
333
+
334
+ // src/stack-parser.ts
335
+ var V8_STACK_FRAME_REGEX = /^\s*at\s+(?:async\s+)?(?:(.+?)\s+\()?(?:(.+?):(\d+):(\d+))\)?$/;
336
+ function isNodeModule(filePath) {
337
+ return filePath.includes("node_modules");
338
+ }
339
+ function isInternalCode(filePath) {
340
+ return filePath.startsWith("node:") || filePath.startsWith("internal/") || !filePath.includes("/");
341
+ }
342
+ function cleanFunctionName(name) {
343
+ if (!name) return void 0;
344
+ return name.replace(/^Object\./, "").replace(/^Module\./, "").replace(/^__webpack_require__\./, "").replace(/^webpack_require\./, "").trim();
345
+ }
346
+ function parseStackTrace(stack) {
347
+ if (!stack) return [];
348
+ const lines = stack.split("\n");
349
+ const frames = [];
350
+ for (const line of lines) {
351
+ const match = V8_STACK_FRAME_REGEX.exec(line);
352
+ if (match) {
353
+ const [, functionName, file, lineStr, columnStr] = match;
354
+ const frame = {
355
+ function: cleanFunctionName(functionName),
356
+ file: file ?? void 0,
357
+ line: lineStr ? parseInt(lineStr, 10) : void 0,
358
+ column: columnStr ? parseInt(columnStr, 10) : void 0
359
+ };
360
+ if (frame.file) {
361
+ frame.isNodeModule = isNodeModule(frame.file);
362
+ frame.isInternal = isInternalCode(frame.file);
363
+ }
364
+ frames.push(frame);
365
+ }
366
+ }
367
+ return frames;
368
+ }
369
+ function getFirstAppFrame(frames) {
370
+ return frames.find((frame) => !frame.isNodeModule && !frame.isInternal);
371
+ }
372
+ function getAppFrames(frames) {
373
+ return frames.filter((frame) => !frame.isNodeModule && !frame.isInternal);
374
+ }
375
+
376
+ // src/wrapper.ts
377
+ var SDK_VERSION2 = "0.1.0";
378
+ function generateErrorId() {
379
+ const timestamp = Date.now().toString(36);
380
+ const random = Math.random().toString(36).substring(2, 9);
381
+ return `err_${timestamp}_${random}`;
382
+ }
383
+ function extractRoute(request) {
384
+ try {
385
+ const url = new URL(request.url);
386
+ return url.pathname;
387
+ } catch {
388
+ return "unknown";
389
+ }
390
+ }
391
+ function getNodeVersion() {
392
+ try {
393
+ return process.version;
394
+ } catch {
395
+ return "unknown";
396
+ }
397
+ }
398
+ function getNextVersion() {
399
+ try {
400
+ const pkg = __require("next/package.json");
401
+ return pkg.version;
402
+ } catch {
403
+ return void 0;
404
+ }
405
+ }
406
+ async function buildCapturedError(error, request, context, client, routeOptions) {
407
+ const config = client.getConfig();
408
+ const url = new URL(request.url);
409
+ const stackFrames = parseStackTrace(error.stack);
410
+ const firstAppFrame = getFirstAppFrame(stackFrames);
411
+ const capturedError = {
412
+ id: generateErrorId(),
413
+ name: error.name || "Error",
414
+ message: error.message,
415
+ stack: error.stack,
416
+ stackFrames,
417
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
418
+ route: extractRoute(request),
419
+ method: request.method,
420
+ statusCode: routeOptions?.statusCode ?? 500,
421
+ url: request.url,
422
+ environment: config.environment,
423
+ projectId: config.projectId,
424
+ sdkVersion: SDK_VERSION2,
425
+ nodeVersion: getNodeVersion(),
426
+ nextVersion: getNextVersion()
427
+ };
428
+ if (context?.params && Object.keys(context.params).length > 0) {
429
+ capturedError.routeParams = context.params;
430
+ }
431
+ if (config.captureQueryParams && url.searchParams.toString()) {
432
+ capturedError.queryParams = sanitizeQueryParams(url, client);
433
+ }
434
+ if (config.captureHeaders) {
435
+ capturedError.requestHeaders = sanitizeHeaders(request.headers, client);
436
+ }
437
+ if (config.captureRequestBody && hasBody(request.method)) {
438
+ const bodyResult = await safeParseBody(request, config.maxBodySize, client);
439
+ if (bodyResult) {
440
+ capturedError.requestBody = bodyResult.body;
441
+ if (bodyResult.truncated) {
442
+ capturedError.metadata = {
443
+ ...capturedError.metadata,
444
+ bodyTruncated: true
445
+ };
446
+ }
447
+ }
448
+ }
449
+ if (firstAppFrame) {
450
+ capturedError.metadata = {
451
+ ...capturedError.metadata,
452
+ sourceLocation: {
453
+ file: firstAppFrame.file,
454
+ line: firstAppFrame.line,
455
+ column: firstAppFrame.column,
456
+ function: firstAppFrame.function
457
+ }
458
+ };
459
+ }
460
+ if (routeOptions?.metadata) {
461
+ capturedError.metadata = {
462
+ ...capturedError.metadata,
463
+ ...routeOptions.metadata
464
+ };
465
+ }
466
+ return capturedError;
467
+ }
468
+ function hasBody(method) {
469
+ return ["POST", "PUT", "PATCH", "DELETE"].includes(method.toUpperCase());
470
+ }
471
+ function withErrorCapture(handler, config, routeOptions) {
472
+ if (config && !ErrorCaptureClient.isInitialized()) {
473
+ ErrorCaptureClient.init(config);
474
+ }
475
+ return async (request, context) => {
476
+ const client = ErrorCaptureClient.getInstance();
477
+ try {
478
+ const response = await handler(request, context);
479
+ return response;
480
+ } catch (error) {
481
+ const err = error instanceof Error ? error : new Error(String(error));
482
+ if (client) {
483
+ const clientConfig = client.getConfig();
484
+ if (clientConfig.shouldCapture && !clientConfig.shouldCapture(err, request)) {
485
+ throw error;
486
+ }
487
+ if (routeOptions?.shouldCapture && !routeOptions.shouldCapture(err)) {
488
+ throw error;
489
+ }
490
+ buildCapturedError(err, request, context, client, routeOptions).then((capturedError) => {
491
+ return client.reportError(capturedError);
492
+ }).catch(() => {
493
+ });
494
+ }
495
+ throw error;
496
+ }
497
+ };
498
+ }
499
+ var withBugStack = withErrorCapture;
500
+
501
+ export { BugStackClient, ErrorCaptureClient, getAppFrames, getFirstAppFrame, parseStackTrace, sanitizeHeaders, sanitizeObject, sanitizeQueryParams, withBugStack, withErrorCapture };
502
+ //# sourceMappingURL=index.mjs.map
503
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts","../src/sanitize.ts","../src/stack-parser.ts","../src/wrapper.ts"],"names":["SDK_VERSION"],"mappings":"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","file":"index.mjs","sourcesContent":["import type {\n ErrorCaptureConfig,\n ResolvedConfig,\n CapturedError,\n ErrorReportPayload,\n SourceContext,\n} from \"./types\";\n\nconst SDK_VERSION = \"1.0.0\";\nconst DEFAULT_ENDPOINT = \"http://localhost:3001/api/capture\";\nconst DEFAULT_TIMEOUT = 5000;\nconst DEFAULT_MAX_BODY_SIZE = 10000;\n\n/**\n * Default sensitive fields to redact from requests\n */\nconst DEFAULT_REDACT_FIELDS = [\n \"password\",\n \"secret\",\n \"token\",\n \"apikey\",\n \"api_key\",\n \"apiKey\",\n \"authorization\",\n \"auth\",\n \"credential\",\n \"private\",\n \"credit_card\",\n \"creditcard\",\n \"card_number\",\n \"cvv\",\n \"ssn\",\n \"social_security\",\n];\n\n/**\n * BugStack Error Capture Client\n *\n * Singleton client for capturing and reporting errors to the BugStack service.\n */\nexport class ErrorCaptureClient {\n private config: ResolvedConfig;\n private static instance: ErrorCaptureClient | null = null;\n\n constructor(config: ErrorCaptureConfig) {\n const isProduction = process.env.NODE_ENV === \"production\";\n\n this.config = {\n apiKey: config.apiKey,\n endpoint:\n config.endpoint ??\n process.env.BUGSTACK_ENDPOINT ??\n DEFAULT_ENDPOINT,\n projectId: config.projectId ?? process.env.BUGSTACK_PROJECT_ID ?? \"\",\n environment:\n config.environment ?? process.env.NODE_ENV ?? \"development\",\n enabled: config.enabled ?? true,\n captureRequestBody: config.captureRequestBody ?? true,\n captureQueryParams: config.captureQueryParams ?? true,\n captureHeaders: config.captureHeaders ?? true,\n maxBodySize: config.maxBodySize ?? DEFAULT_MAX_BODY_SIZE,\n redactFields: [\n ...DEFAULT_REDACT_FIELDS,\n ...(config.redactFields ?? []),\n ],\n metadata: config.metadata ?? {},\n timeout: config.timeout ?? DEFAULT_TIMEOUT,\n debug: config.debug ?? !isProduction,\n shouldCapture: config.shouldCapture,\n beforeSend: config.beforeSend,\n };\n }\n\n /**\n * Initialize the singleton client instance\n */\n static init(config: ErrorCaptureConfig): ErrorCaptureClient {\n ErrorCaptureClient.instance = new ErrorCaptureClient(config);\n return ErrorCaptureClient.instance;\n }\n\n /**\n * Get the singleton client instance\n */\n static getInstance(): ErrorCaptureClient | null {\n return ErrorCaptureClient.instance;\n }\n\n /**\n * Check if the client has been initialized\n */\n static isInitialized(): boolean {\n return ErrorCaptureClient.instance !== null;\n }\n\n /**\n * Reset the client (mainly for testing)\n */\n static reset(): void {\n ErrorCaptureClient.instance = null;\n }\n\n /**\n * Report an error to the BugStack service\n */\n async reportError(\n error: CapturedError,\n sourceContext?: SourceContext\n ): Promise<boolean> {\n if (!this.config.enabled) {\n this.log(\"Error capture is disabled, skipping report\");\n return false;\n }\n\n // Apply beforeSend hook if provided\n let errorToSend = error;\n if (this.config.beforeSend) {\n const modified = this.config.beforeSend(error);\n if (modified === null) {\n this.log(\"Error filtered by beforeSend hook\");\n return false;\n }\n errorToSend = modified;\n }\n\n const payload: ErrorReportPayload = {\n error: {\n ...errorToSend,\n projectId: this.config.projectId || errorToSend.projectId,\n environment: this.config.environment,\n metadata: {\n ...this.config.metadata,\n ...errorToSend.metadata,\n },\n },\n sourceContext,\n };\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n this.config.timeout\n );\n\n const response = await fetch(this.config.endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-BugStack-API-Key\": this.config.apiKey,\n \"X-BugStack-SDK-Version\": SDK_VERSION,\n },\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n this.logError(\n `Failed to report error: HTTP ${response.status} ${response.statusText}`\n );\n return false;\n }\n\n this.log(`Error reported successfully: ${error.id}`);\n return true;\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n this.logError(`Error report timed out after ${this.config.timeout}ms`);\n } else {\n this.logError(\"Failed to send error report:\", err);\n }\n return false;\n }\n }\n\n /**\n * Get the resolved configuration\n */\n getConfig(): ResolvedConfig {\n return { ...this.config };\n }\n\n /**\n * Check if a field should be redacted\n */\n shouldRedact(fieldName: string): boolean {\n const lowerField = fieldName.toLowerCase();\n return this.config.redactFields.some(\n (redact) =>\n lowerField.includes(redact.toLowerCase()) ||\n redact.toLowerCase().includes(lowerField)\n );\n }\n\n /**\n * Get the SDK version\n */\n static getVersion(): string {\n return SDK_VERSION;\n }\n\n private log(message: string): void {\n if (this.config.debug) {\n console.log(`[BugStack] ${message}`);\n }\n }\n\n private logError(message: string, error?: unknown): void {\n if (this.config.debug) {\n if (error) {\n console.error(`[BugStack] ${message}`, error);\n } else {\n console.error(`[BugStack] ${message}`);\n }\n }\n }\n}\n\n// Legacy alias for backwards compatibility\nexport const BugStackClient = ErrorCaptureClient;\n","import { ErrorCaptureClient } from \"./client\";\n\nconst REDACT_PLACEHOLDER = \"[REDACTED]\";\nconst TRUNCATE_PLACEHOLDER = \"[TRUNCATED]\";\n\n/**\n * Sensitive headers that are always redacted\n */\nconst SENSITIVE_HEADERS = new Set([\n \"authorization\",\n \"cookie\",\n \"set-cookie\",\n \"x-api-key\",\n \"x-auth-token\",\n \"x-bugstack-api-key\",\n \"proxy-authorization\",\n \"www-authenticate\",\n]);\n\n/**\n * Sanitize headers by removing sensitive values\n */\nexport function sanitizeHeaders(\n headers: Headers,\n client?: ErrorCaptureClient | null\n): Record<string, string> {\n const sanitized: Record<string, string> = {};\n\n headers.forEach((value, key) => {\n const lowerKey = key.toLowerCase();\n\n // Always redact known sensitive headers\n if (SENSITIVE_HEADERS.has(lowerKey)) {\n sanitized[key] = REDACT_PLACEHOLDER;\n return;\n }\n\n // Check against custom redact fields\n if (client?.shouldRedact(key)) {\n sanitized[key] = REDACT_PLACEHOLDER;\n return;\n }\n\n sanitized[key] = value;\n });\n\n return sanitized;\n}\n\n/**\n * Sanitize query parameters by redacting sensitive values\n */\nexport function sanitizeQueryParams(\n url: URL,\n client?: ErrorCaptureClient | null\n): Record<string, string> {\n const sanitized: Record<string, string> = {};\n\n url.searchParams.forEach((value, key) => {\n if (client?.shouldRedact(key)) {\n sanitized[key] = REDACT_PLACEHOLDER;\n } else {\n sanitized[key] = value;\n }\n });\n\n return sanitized;\n}\n\n/**\n * Recursively sanitize an object by redacting sensitive fields\n */\nexport function sanitizeObject(\n obj: unknown,\n client?: ErrorCaptureClient | null,\n maxDepth = 10,\n currentDepth = 0\n): unknown {\n // Prevent infinite recursion\n if (currentDepth > maxDepth) {\n return TRUNCATE_PLACEHOLDER;\n }\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj !== \"object\") {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) =>\n sanitizeObject(item, client, maxDepth, currentDepth + 1)\n );\n }\n\n const sanitized: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (client?.shouldRedact(key)) {\n sanitized[key] = REDACT_PLACEHOLDER;\n } else if (typeof value === \"object\" && value !== null) {\n sanitized[key] = sanitizeObject(value, client, maxDepth, currentDepth + 1);\n } else {\n sanitized[key] = value;\n }\n }\n\n return sanitized;\n}\n\n/**\n * Truncate a string or object to a maximum size\n */\nexport function truncateBody(\n data: unknown,\n maxSize: number\n): { body: unknown; truncated: boolean } {\n const serialized = JSON.stringify(data);\n\n if (serialized.length <= maxSize) {\n return { body: data, truncated: false };\n }\n\n // For strings, truncate directly\n if (typeof data === \"string\") {\n return {\n body: data.slice(0, maxSize) + `... ${TRUNCATE_PLACEHOLDER}`,\n truncated: true,\n };\n }\n\n // For objects, try to preserve structure but indicate truncation\n return {\n body: {\n __truncated: true,\n __originalSize: serialized.length,\n __maxSize: maxSize,\n preview: serialized.slice(0, maxSize),\n },\n truncated: true,\n };\n}\n\n/**\n * Safely parse request body with error handling\n */\nexport async function safeParseBody(\n request: Request,\n maxSize: number,\n client?: ErrorCaptureClient | null\n): Promise<{ body: unknown; truncated: boolean } | null> {\n try {\n // Clone the request to avoid consuming the body\n const cloned = request.clone();\n const contentType = cloned.headers.get(\"content-type\") ?? \"\";\n\n // Handle JSON bodies\n if (contentType.includes(\"application/json\")) {\n const text = await cloned.text();\n\n if (text.length > maxSize) {\n return {\n body: {\n __truncated: true,\n __originalSize: text.length,\n preview: text.slice(0, maxSize),\n },\n truncated: true,\n };\n }\n\n try {\n const parsed = JSON.parse(text);\n const sanitized = sanitizeObject(parsed, client);\n return truncateBody(sanitized, maxSize);\n } catch {\n // Not valid JSON, return as text\n return truncateBody(text, maxSize);\n }\n }\n\n // Handle form data\n if (\n contentType.includes(\"application/x-www-form-urlencoded\") ||\n contentType.includes(\"multipart/form-data\")\n ) {\n try {\n const formData = await cloned.formData();\n const data: Record<string, unknown> = {};\n\n formData.forEach((value, key) => {\n if (value instanceof File) {\n data[key] = {\n type: \"file\",\n name: value.name,\n size: value.size,\n mimeType: value.type,\n };\n } else if (client?.shouldRedact(key)) {\n data[key] = REDACT_PLACEHOLDER;\n } else {\n data[key] = value;\n }\n });\n\n return truncateBody(data, maxSize);\n } catch {\n return { body: \"[FormData parsing failed]\", truncated: false };\n }\n }\n\n // Handle text bodies\n if (contentType.includes(\"text/\")) {\n const text = await cloned.text();\n return truncateBody(text, maxSize);\n }\n\n // For other content types, just note the type\n return {\n body: {\n __contentType: contentType,\n __note: \"Body not captured for this content type\",\n },\n truncated: false,\n };\n } catch (err) {\n // Body may have already been consumed or other error\n return null;\n }\n}\n","import type { StackFrame } from \"./types\";\n\n/**\n * Regular expression to parse V8 stack trace frames\n * Handles formats like:\n * at functionName (file:line:column)\n * at file:line:column\n * at async functionName (file:line:column)\n */\nconst V8_STACK_FRAME_REGEX =\n /^\\s*at\\s+(?:async\\s+)?(?:(.+?)\\s+\\()?(?:(.+?):(\\d+):(\\d+))\\)?$/;\n\n/**\n * Check if a file path is from node_modules\n */\nfunction isNodeModule(filePath: string): boolean {\n return filePath.includes(\"node_modules\");\n}\n\n/**\n * Check if a file path is internal Node.js code\n */\nfunction isInternalCode(filePath: string): boolean {\n return (\n filePath.startsWith(\"node:\") ||\n filePath.startsWith(\"internal/\") ||\n !filePath.includes(\"/\")\n );\n}\n\n/**\n * Clean up function names\n */\nfunction cleanFunctionName(name: string | undefined): string | undefined {\n if (!name) return undefined;\n\n // Remove common prefixes\n return name\n .replace(/^Object\\./, \"\")\n .replace(/^Module\\./, \"\")\n .replace(/^__webpack_require__\\./, \"\")\n .replace(/^webpack_require\\./, \"\")\n .trim();\n}\n\n/**\n * Parse a V8 stack trace into structured frames\n */\nexport function parseStackTrace(stack: string | undefined): StackFrame[] {\n if (!stack) return [];\n\n const lines = stack.split(\"\\n\");\n const frames: StackFrame[] = [];\n\n for (const line of lines) {\n const match = V8_STACK_FRAME_REGEX.exec(line);\n\n if (match) {\n const [, functionName, file, lineStr, columnStr] = match;\n\n const frame: StackFrame = {\n function: cleanFunctionName(functionName),\n file: file ?? undefined,\n line: lineStr ? parseInt(lineStr, 10) : undefined,\n column: columnStr ? parseInt(columnStr, 10) : undefined,\n };\n\n if (frame.file) {\n frame.isNodeModule = isNodeModule(frame.file);\n frame.isInternal = isInternalCode(frame.file);\n }\n\n frames.push(frame);\n }\n }\n\n return frames;\n}\n\n/**\n * Get the first application frame (non-node_modules, non-internal)\n */\nexport function getFirstAppFrame(frames: StackFrame[]): StackFrame | undefined {\n return frames.find((frame) => !frame.isNodeModule && !frame.isInternal);\n}\n\n/**\n * Filter stack frames to only include application code\n */\nexport function getAppFrames(frames: StackFrame[]): StackFrame[] {\n return frames.filter((frame) => !frame.isNodeModule && !frame.isInternal);\n}\n\n/**\n * Format stack frames back to a string (useful for cleaned stack traces)\n */\nexport function formatStackFrames(frames: StackFrame[]): string {\n return frames\n .map((frame) => {\n const location = [frame.file, frame.line, frame.column]\n .filter(Boolean)\n .join(\":\");\n\n if (frame.function) {\n return ` at ${frame.function} (${location})`;\n }\n return ` at ${location}`;\n })\n .join(\"\\n\");\n}\n","import type { NextRequest } from \"next/server\";\nimport { ErrorCaptureClient } from \"./client\";\nimport type {\n ErrorCaptureConfig,\n CapturedError,\n RouteOptions,\n RouteContext,\n} from \"./types\";\nimport { sanitizeHeaders, sanitizeQueryParams, safeParseBody } from \"./sanitize\";\nimport { parseStackTrace, getFirstAppFrame } from \"./stack-parser\";\n\nconst SDK_VERSION = \"0.1.0\";\n\n/**\n * Generate a unique error ID\n */\nfunction generateErrorId(): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 9);\n return `err_${timestamp}_${random}`;\n}\n\n/**\n * Extract route path from request URL\n */\nfunction extractRoute(request: NextRequest): string {\n try {\n const url = new URL(request.url);\n return url.pathname;\n } catch {\n return \"unknown\";\n }\n}\n\n/**\n * Get Node.js version\n */\nfunction getNodeVersion(): string {\n try {\n return process.version;\n } catch {\n return \"unknown\";\n }\n}\n\n/**\n * Try to get Next.js version from package\n */\nfunction getNextVersion(): string | undefined {\n try {\n // This is a best-effort attempt\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pkg = require(\"next/package.json\");\n return pkg.version;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Build the captured error object\n */\nasync function buildCapturedError(\n error: Error,\n request: NextRequest,\n context: RouteContext | undefined,\n client: ErrorCaptureClient,\n routeOptions?: RouteOptions\n): Promise<CapturedError> {\n const config = client.getConfig();\n const url = new URL(request.url);\n const stackFrames = parseStackTrace(error.stack);\n const firstAppFrame = getFirstAppFrame(stackFrames);\n\n const capturedError: CapturedError = {\n id: generateErrorId(),\n name: error.name || \"Error\",\n message: error.message,\n stack: error.stack,\n stackFrames,\n timestamp: new Date().toISOString(),\n route: extractRoute(request),\n method: request.method,\n statusCode: routeOptions?.statusCode ?? 500,\n url: request.url,\n environment: config.environment,\n projectId: config.projectId,\n sdkVersion: SDK_VERSION,\n nodeVersion: getNodeVersion(),\n nextVersion: getNextVersion(),\n };\n\n // Add route params if available\n if (context?.params && Object.keys(context.params).length > 0) {\n capturedError.routeParams = context.params as Record<string, string>;\n }\n\n // Add query params if configured\n if (config.captureQueryParams && url.searchParams.toString()) {\n capturedError.queryParams = sanitizeQueryParams(url, client);\n }\n\n // Add headers if configured\n if (config.captureHeaders) {\n capturedError.requestHeaders = sanitizeHeaders(request.headers, client);\n }\n\n // Add request body if configured\n if (config.captureRequestBody && hasBody(request.method)) {\n const bodyResult = await safeParseBody(request, config.maxBodySize, client);\n if (bodyResult) {\n capturedError.requestBody = bodyResult.body;\n if (bodyResult.truncated) {\n capturedError.metadata = {\n ...capturedError.metadata,\n bodyTruncated: true,\n };\n }\n }\n }\n\n // Add source location from first app frame\n if (firstAppFrame) {\n capturedError.metadata = {\n ...capturedError.metadata,\n sourceLocation: {\n file: firstAppFrame.file,\n line: firstAppFrame.line,\n column: firstAppFrame.column,\n function: firstAppFrame.function,\n },\n };\n }\n\n // Merge route-specific metadata\n if (routeOptions?.metadata) {\n capturedError.metadata = {\n ...capturedError.metadata,\n ...routeOptions.metadata,\n };\n }\n\n return capturedError;\n}\n\n/**\n * Check if HTTP method typically has a body\n */\nfunction hasBody(method: string): boolean {\n return [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"].includes(method.toUpperCase());\n}\n\n/**\n * Type for the wrapped handler function\n */\ntype WrappedHandler<T> = (\n request: NextRequest,\n context: RouteContext<T>\n) => Response | Promise<Response>;\n\n/**\n * Wrap a Next.js App Router API route handler with error capture\n *\n * @example\n * ```typescript\n * // Basic usage\n * export const GET = withErrorCapture(async (request) => {\n * return NextResponse.json({ data: \"hello\" });\n * });\n *\n * // With configuration (first call only)\n * export const GET = withErrorCapture(\n * async (request) => {\n * return NextResponse.json({ data: \"hello\" });\n * },\n * { apiKey: \"your-api-key\" }\n * );\n *\n * // With route-specific options\n * export const POST = withErrorCapture(\n * async (request) => {\n * return NextResponse.json({ data: \"created\" });\n * },\n * undefined,\n * { statusCode: 400, metadata: { operation: \"create\" } }\n * );\n * ```\n */\nexport function withErrorCapture<T = Record<string, string>>(\n handler: WrappedHandler<T>,\n config?: ErrorCaptureConfig,\n routeOptions?: RouteOptions\n): WrappedHandler<T> {\n // Initialize client if config provided and not already initialized\n if (config && !ErrorCaptureClient.isInitialized()) {\n ErrorCaptureClient.init(config);\n }\n\n return async (\n request: NextRequest,\n context: RouteContext<T>\n ): Promise<Response> => {\n const client = ErrorCaptureClient.getInstance();\n\n try {\n // Execute the original handler\n const response = await handler(request, context);\n return response;\n } catch (error) {\n // Normalize error to Error instance\n const err = error instanceof Error ? error : new Error(String(error));\n\n // Only capture if client is initialized and enabled\n if (client) {\n const clientConfig = client.getConfig();\n\n // Check shouldCapture filter (global)\n if (clientConfig.shouldCapture && !clientConfig.shouldCapture(err, request)) {\n throw error; // Re-throw without capturing\n }\n\n // Check shouldCapture filter (route-specific)\n if (routeOptions?.shouldCapture && !routeOptions.shouldCapture(err)) {\n throw error; // Re-throw without capturing\n }\n\n // Build and report error asynchronously (don't block response)\n buildCapturedError(err, request, context as RouteContext, client, routeOptions)\n .then((capturedError) => {\n return client.reportError(capturedError);\n })\n .catch(() => {\n // Silently ignore capture/report failures\n // The original error should still propagate\n });\n }\n\n // Re-throw the original error so Next.js handles it\n throw error;\n }\n };\n}\n\n// Legacy alias for backwards compatibility\nexport const withBugStack = withErrorCapture;\n"]}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "bugstack-sdk",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered error capture SDK for Next.js API routes. Automatically captures errors and creates PRs with fixes using Claude.",
5
+ "author": "Mason Bachmann",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "nextjs",
9
+ "error-handling",
10
+ "error-capture",
11
+ "api-routes",
12
+ "bugstack",
13
+ "debugging",
14
+ "monitoring",
15
+ "app-router",
16
+ "ai",
17
+ "bug-fixing",
18
+ "error-tracking",
19
+ "claude",
20
+ "automatic-fixes"
21
+ ],
22
+ "main": "./dist/index.js",
23
+ "module": "./dist/index.mjs",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/index.mjs",
29
+ "require": "./dist/index.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsup",
38
+ "dev": "tsup --watch",
39
+ "clean": "rimraf dist",
40
+ "lint": "eslint src --ext .ts",
41
+ "typecheck": "tsc --noEmit",
42
+ "prepublishOnly": "pnpm run build"
43
+ },
44
+ "peerDependencies": {
45
+ "next": ">=14.0.0"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "next": {
49
+ "optional": false
50
+ }
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^20.10.0",
54
+ "next": "^14.0.0",
55
+ "rimraf": "^5.0.5",
56
+ "tsup": "^8.0.1",
57
+ "typescript": "^5.3.0"
58
+ },
59
+ "engines": {
60
+ "node": ">=18.0.0"
61
+ },
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "https://github.com/MasonBachmann7/BugStack.git",
65
+ "directory": "packages/error-capture-sdk"
66
+ },
67
+ "bugs": {
68
+ "url": "https://github.com/MasonBachmann7/BugStack/issues"
69
+ },
70
+ "homepage": "https://www.bugstack.ai"
71
+ }