mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-11 07:04:58 -05:00
v0.2.4: feat, improvement, fix (#595)
* feat(function): added more granular error logs for function execution for easier debugging (#593) * added more granular error logs for function execution * added tests * fixed syntax error reporting * feat(models): added temp controls for gpt-4.1 family of models (#594) * improvement(knowledge-upload): create and upload document to KB (#579) * improvement: added knowledge upload * improvement: added greptile comments (#579) * improvement: changed to text to doc (#579) * improvement: removed comment (#579) * added input validation, tested persistence of KB selector * update docs --------- Co-authored-by: Adam Gough <adamgough@Mac.attlocal.net> Co-authored-by: Waleed Latif <walif6@gmail.com> * fix(remove workflow.state usage): no more usage of deprecated state column in any routes (#586) * fix(remove workflow.state usage): no more usage of deprecated state col in routes * fix lint * fix chat route to only use deployed state * fix lint * better typing * remove useless logs * fix lint * restore workflow handler file * removed all other usages of deprecated 'state' column from workflows table, updated tests --------- Co-authored-by: Vikhyath Mondreti <vikhyathmondreti@Vikhyaths-MacBook-Air.local> Co-authored-by: Waleed Latif <walif6@gmail.com> --------- Co-authored-by: Waleed Latif <walif6@gmail.com> Co-authored-by: Adam Gough <77861281+aadamgough@users.noreply.github.com> Co-authored-by: Adam Gough <adamgough@Mac.attlocal.net> Co-authored-by: Vikhyath Mondreti <vikhyathmondreti@Vikhyaths-MacBook-Air.local>
This commit is contained in:
committed by
GitHub
parent
86168f1a87
commit
1604ce4d7c
@@ -391,6 +391,225 @@ describe('Function Execute API Route', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('Enhanced Error Handling', () => {
|
||||
it('should provide detailed syntax error with line content', async () => {
|
||||
// Mock VM Script to throw a syntax error
|
||||
const mockScript = vi.fn().mockImplementation(() => {
|
||||
const error = new Error('Invalid or unexpected token')
|
||||
error.name = 'SyntaxError'
|
||||
error.stack = `user-function.js:5
|
||||
description: "This has a missing closing quote
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
SyntaxError: Invalid or unexpected token
|
||||
at new Script (node:vm:117:7)
|
||||
at POST (/path/to/route.ts:123:24)`
|
||||
throw error
|
||||
})
|
||||
|
||||
vi.doMock('vm', () => ({
|
||||
createContext: mockCreateContext,
|
||||
Script: mockScript,
|
||||
}))
|
||||
|
||||
const req = createMockRequest('POST', {
|
||||
code: 'const obj = {\n name: "test",\n description: "This has a missing closing quote\n};\nreturn obj;',
|
||||
timeout: 5000,
|
||||
})
|
||||
|
||||
const { POST } = await import('./route')
|
||||
const response = await POST(req)
|
||||
const data = await response.json()
|
||||
|
||||
expect(response.status).toBe(500)
|
||||
expect(data.success).toBe(false)
|
||||
expect(data.error).toContain('Syntax Error')
|
||||
expect(data.error).toContain('Line 3')
|
||||
expect(data.error).toContain('description: "This has a missing closing quote')
|
||||
expect(data.error).toContain('Invalid or unexpected token')
|
||||
expect(data.error).toContain('(Check for missing quotes, brackets, or semicolons)')
|
||||
|
||||
// Check debug information
|
||||
expect(data.debug).toBeDefined()
|
||||
expect(data.debug.line).toBe(3)
|
||||
expect(data.debug.errorType).toBe('SyntaxError')
|
||||
expect(data.debug.lineContent).toBe('description: "This has a missing closing quote')
|
||||
})
|
||||
|
||||
it('should provide detailed runtime error with line and column', async () => {
|
||||
// Create the error object first
|
||||
const runtimeError = new Error("Cannot read properties of null (reading 'someMethod')")
|
||||
runtimeError.name = 'TypeError'
|
||||
runtimeError.stack = `TypeError: Cannot read properties of null (reading 'someMethod')
|
||||
at user-function.js:4:16
|
||||
at user-function.js:9:3
|
||||
at Script.runInContext (node:vm:147:14)`
|
||||
|
||||
// Mock successful script creation but runtime error
|
||||
const mockScript = vi.fn().mockImplementation(() => ({
|
||||
runInContext: vi.fn().mockRejectedValue(runtimeError),
|
||||
}))
|
||||
|
||||
vi.doMock('vm', () => ({
|
||||
createContext: mockCreateContext,
|
||||
Script: mockScript,
|
||||
}))
|
||||
|
||||
const req = createMockRequest('POST', {
|
||||
code: 'const obj = null;\nreturn obj.someMethod();',
|
||||
timeout: 5000,
|
||||
})
|
||||
|
||||
const { POST } = await import('./route')
|
||||
const response = await POST(req)
|
||||
const data = await response.json()
|
||||
|
||||
expect(response.status).toBe(500)
|
||||
expect(data.success).toBe(false)
|
||||
expect(data.error).toContain('Type Error')
|
||||
expect(data.error).toContain('Line 2')
|
||||
expect(data.error).toContain('return obj.someMethod();')
|
||||
expect(data.error).toContain('Cannot read properties of null')
|
||||
|
||||
// Check debug information
|
||||
expect(data.debug).toBeDefined()
|
||||
expect(data.debug.line).toBe(2)
|
||||
expect(data.debug.column).toBe(16)
|
||||
expect(data.debug.errorType).toBe('TypeError')
|
||||
expect(data.debug.lineContent).toBe('return obj.someMethod();')
|
||||
})
|
||||
|
||||
it('should handle ReferenceError with enhanced details', async () => {
|
||||
// Create the error object first
|
||||
const referenceError = new Error('undefinedVariable is not defined')
|
||||
referenceError.name = 'ReferenceError'
|
||||
referenceError.stack = `ReferenceError: undefinedVariable is not defined
|
||||
at user-function.js:4:8
|
||||
at Script.runInContext (node:vm:147:14)`
|
||||
|
||||
const mockScript = vi.fn().mockImplementation(() => ({
|
||||
runInContext: vi.fn().mockRejectedValue(referenceError),
|
||||
}))
|
||||
|
||||
vi.doMock('vm', () => ({
|
||||
createContext: mockCreateContext,
|
||||
Script: mockScript,
|
||||
}))
|
||||
|
||||
const req = createMockRequest('POST', {
|
||||
code: 'const x = 42;\nreturn undefinedVariable + x;',
|
||||
timeout: 5000,
|
||||
})
|
||||
|
||||
const { POST } = await import('./route')
|
||||
const response = await POST(req)
|
||||
const data = await response.json()
|
||||
|
||||
expect(response.status).toBe(500)
|
||||
expect(data.success).toBe(false)
|
||||
expect(data.error).toContain('Reference Error')
|
||||
expect(data.error).toContain('Line 2')
|
||||
expect(data.error).toContain('return undefinedVariable + x;')
|
||||
expect(data.error).toContain('undefinedVariable is not defined')
|
||||
})
|
||||
|
||||
it('should handle errors without line content gracefully', async () => {
|
||||
const mockScript = vi.fn().mockImplementation(() => {
|
||||
const error = new Error('Generic error without stack trace')
|
||||
error.name = 'Error'
|
||||
// No stack trace
|
||||
throw error
|
||||
})
|
||||
|
||||
vi.doMock('vm', () => ({
|
||||
createContext: mockCreateContext,
|
||||
Script: mockScript,
|
||||
}))
|
||||
|
||||
const req = createMockRequest('POST', {
|
||||
code: 'return "test";',
|
||||
timeout: 5000,
|
||||
})
|
||||
|
||||
const { POST } = await import('./route')
|
||||
const response = await POST(req)
|
||||
const data = await response.json()
|
||||
|
||||
expect(response.status).toBe(500)
|
||||
expect(data.success).toBe(false)
|
||||
expect(data.error).toBe('Generic error without stack trace')
|
||||
|
||||
// Should still have debug info, but without line details
|
||||
expect(data.debug).toBeDefined()
|
||||
expect(data.debug.errorType).toBe('Error')
|
||||
expect(data.debug.line).toBeUndefined()
|
||||
expect(data.debug.lineContent).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should extract line numbers from different stack trace formats', async () => {
|
||||
const mockScript = vi.fn().mockImplementation(() => {
|
||||
const error = new Error('Test error')
|
||||
error.name = 'Error'
|
||||
error.stack = `Error: Test error
|
||||
at user-function.js:7:25
|
||||
at async function
|
||||
at Script.runInContext (node:vm:147:14)`
|
||||
throw error
|
||||
})
|
||||
|
||||
vi.doMock('vm', () => ({
|
||||
createContext: mockCreateContext,
|
||||
Script: mockScript,
|
||||
}))
|
||||
|
||||
const req = createMockRequest('POST', {
|
||||
code: 'const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;\nreturn a + b + c + d;',
|
||||
timeout: 5000,
|
||||
})
|
||||
|
||||
const { POST } = await import('./route')
|
||||
const response = await POST(req)
|
||||
const data = await response.json()
|
||||
|
||||
expect(response.status).toBe(500)
|
||||
expect(data.success).toBe(false)
|
||||
|
||||
// Line 7 in VM should map to line 5 in user code (7 - 3 + 1 = 5)
|
||||
expect(data.debug.line).toBe(5)
|
||||
expect(data.debug.column).toBe(25)
|
||||
expect(data.debug.lineContent).toBe('return a + b + c + d;')
|
||||
})
|
||||
|
||||
it('should provide helpful suggestions for common syntax errors', async () => {
|
||||
const mockScript = vi.fn().mockImplementation(() => {
|
||||
const error = new Error('Unexpected end of input')
|
||||
error.name = 'SyntaxError'
|
||||
error.stack = 'user-function.js:4\nSyntaxError: Unexpected end of input'
|
||||
throw error
|
||||
})
|
||||
|
||||
vi.doMock('vm', () => ({
|
||||
createContext: mockCreateContext,
|
||||
Script: mockScript,
|
||||
}))
|
||||
|
||||
const req = createMockRequest('POST', {
|
||||
code: 'const obj = {\n name: "test"\n// Missing closing brace',
|
||||
timeout: 5000,
|
||||
})
|
||||
|
||||
const { POST } = await import('./route')
|
||||
const response = await POST(req)
|
||||
const data = await response.json()
|
||||
|
||||
expect(response.status).toBe(500)
|
||||
expect(data.success).toBe(false)
|
||||
expect(data.error).toContain('Syntax Error')
|
||||
expect(data.error).toContain('Unexpected end of input')
|
||||
expect(data.error).toContain('(Check for missing closing brackets or braces)')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Utility Functions', () => {
|
||||
it('should properly escape regex special characters', async () => {
|
||||
// This tests the escapeRegExp function indirectly
|
||||
|
||||
@@ -8,6 +8,210 @@ export const maxDuration = 60
|
||||
|
||||
const logger = createLogger('FunctionExecuteAPI')
|
||||
|
||||
/**
|
||||
* Enhanced error information interface
|
||||
*/
|
||||
interface EnhancedError {
|
||||
message: string
|
||||
line?: number
|
||||
column?: number
|
||||
stack?: string
|
||||
name: string
|
||||
originalError: any
|
||||
lineContent?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract enhanced error information from VM execution errors
|
||||
*/
|
||||
function extractEnhancedError(
|
||||
error: any,
|
||||
userCodeStartLine: number,
|
||||
userCode?: string
|
||||
): EnhancedError {
|
||||
const enhanced: EnhancedError = {
|
||||
message: error.message || 'Unknown error',
|
||||
name: error.name || 'Error',
|
||||
originalError: error,
|
||||
}
|
||||
|
||||
if (error.stack) {
|
||||
enhanced.stack = error.stack
|
||||
|
||||
// Parse stack trace to extract line and column information
|
||||
// Handle both compilation errors and runtime errors
|
||||
const stackLines: string[] = error.stack.split('\n')
|
||||
|
||||
for (const line of stackLines) {
|
||||
// Pattern 1: Compilation errors - "user-function.js:6"
|
||||
let match = line.match(/user-function\.js:(\d+)(?::(\d+))?/)
|
||||
|
||||
// Pattern 2: Runtime errors - "at user-function.js:5:12"
|
||||
if (!match) {
|
||||
match = line.match(/at\s+user-function\.js:(\d+):(\d+)/)
|
||||
}
|
||||
|
||||
// Pattern 3: Generic patterns for any line containing our filename
|
||||
if (!match) {
|
||||
match = line.match(/user-function\.js:(\d+)(?::(\d+))?/)
|
||||
}
|
||||
|
||||
if (match) {
|
||||
const stackLine = Number.parseInt(match[1], 10)
|
||||
const stackColumn = match[2] ? Number.parseInt(match[2], 10) : undefined
|
||||
|
||||
// Adjust line number to account for wrapper code
|
||||
// The user code starts at a specific line in our wrapper
|
||||
const adjustedLine = stackLine - userCodeStartLine + 1
|
||||
|
||||
// Check if this is a syntax error in wrapper code caused by incomplete user code
|
||||
const isWrapperSyntaxError =
|
||||
stackLine > userCodeStartLine &&
|
||||
error.name === 'SyntaxError' &&
|
||||
(error.message.includes('Unexpected token') ||
|
||||
error.message.includes('Unexpected end of input'))
|
||||
|
||||
if (isWrapperSyntaxError && userCode) {
|
||||
// Map wrapper syntax errors to the last line of user code
|
||||
const codeLines = userCode.split('\n')
|
||||
const lastUserLine = codeLines.length
|
||||
enhanced.line = lastUserLine
|
||||
enhanced.column = codeLines[lastUserLine - 1]?.length || 0
|
||||
enhanced.lineContent = codeLines[lastUserLine - 1]?.trim()
|
||||
break
|
||||
}
|
||||
|
||||
if (adjustedLine > 0) {
|
||||
enhanced.line = adjustedLine
|
||||
enhanced.column = stackColumn
|
||||
|
||||
// Extract the actual line content from user code
|
||||
if (userCode) {
|
||||
const codeLines = userCode.split('\n')
|
||||
if (adjustedLine <= codeLines.length) {
|
||||
enhanced.lineContent = codeLines[adjustedLine - 1]?.trim()
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if (stackLine <= userCodeStartLine) {
|
||||
// Error is in wrapper code itself
|
||||
enhanced.line = stackLine
|
||||
enhanced.column = stackColumn
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up stack trace to show user-relevant information
|
||||
const cleanedStackLines: string[] = stackLines
|
||||
.filter(
|
||||
(line: string) =>
|
||||
line.includes('user-function.js') ||
|
||||
(!line.includes('vm.js') && !line.includes('internal/'))
|
||||
)
|
||||
.map((line: string) => line.replace(/\s+at\s+/, ' at '))
|
||||
|
||||
if (cleanedStackLines.length > 0) {
|
||||
enhanced.stack = cleanedStackLines.join('\n')
|
||||
}
|
||||
}
|
||||
|
||||
// Keep original message without adding error type prefix
|
||||
// The error type will be added later in createUserFriendlyErrorMessage
|
||||
|
||||
return enhanced
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a detailed error message for users
|
||||
*/
|
||||
function createUserFriendlyErrorMessage(
|
||||
enhanced: EnhancedError,
|
||||
requestId: string,
|
||||
userCode?: string
|
||||
): string {
|
||||
let errorMessage = enhanced.message
|
||||
|
||||
// Add line and column information if available
|
||||
if (enhanced.line !== undefined) {
|
||||
let lineInfo = `Line ${enhanced.line}${enhanced.column !== undefined ? `:${enhanced.column}` : ''}`
|
||||
|
||||
// Add the actual line content if available
|
||||
if (enhanced.lineContent) {
|
||||
lineInfo += `: \`${enhanced.lineContent}\``
|
||||
}
|
||||
|
||||
errorMessage = `${lineInfo} - ${errorMessage}`
|
||||
} else {
|
||||
// If no line number, try to extract it from stack trace for display
|
||||
if (enhanced.stack) {
|
||||
const stackMatch = enhanced.stack.match(/user-function\.js:(\d+)(?::(\d+))?/)
|
||||
if (stackMatch) {
|
||||
const line = Number.parseInt(stackMatch[1], 10)
|
||||
const column = stackMatch[2] ? Number.parseInt(stackMatch[2], 10) : undefined
|
||||
let lineInfo = `Line ${line}${column ? `:${column}` : ''}`
|
||||
|
||||
// Try to get line content if we have userCode
|
||||
if (userCode) {
|
||||
const codeLines = userCode.split('\n')
|
||||
// Note: stackMatch gives us VM line number, need to adjust
|
||||
// This is a fallback case, so we might not have perfect line mapping
|
||||
if (line <= codeLines.length) {
|
||||
const lineContent = codeLines[line - 1]?.trim()
|
||||
if (lineContent) {
|
||||
lineInfo += `: \`${lineContent}\``
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorMessage = `${lineInfo} - ${errorMessage}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add error type prefix with consistent naming
|
||||
if (enhanced.name !== 'Error') {
|
||||
const errorTypePrefix =
|
||||
enhanced.name === 'SyntaxError'
|
||||
? 'Syntax Error'
|
||||
: enhanced.name === 'TypeError'
|
||||
? 'Type Error'
|
||||
: enhanced.name === 'ReferenceError'
|
||||
? 'Reference Error'
|
||||
: enhanced.name
|
||||
|
||||
// Only add prefix if not already present
|
||||
if (!errorMessage.toLowerCase().includes(errorTypePrefix.toLowerCase())) {
|
||||
errorMessage = `${errorTypePrefix}: ${errorMessage}`
|
||||
}
|
||||
}
|
||||
|
||||
// For syntax errors, provide additional context
|
||||
if (enhanced.name === 'SyntaxError') {
|
||||
if (errorMessage.includes('Invalid or unexpected token')) {
|
||||
errorMessage += ' (Check for missing quotes, brackets, or semicolons)'
|
||||
} else if (errorMessage.includes('Unexpected end of input')) {
|
||||
errorMessage += ' (Check for missing closing brackets or braces)'
|
||||
} else if (errorMessage.includes('Unexpected token')) {
|
||||
// Check if this might be due to incomplete code
|
||||
if (
|
||||
enhanced.lineContent &&
|
||||
((enhanced.lineContent.includes('(') && !enhanced.lineContent.includes(')')) ||
|
||||
(enhanced.lineContent.includes('[') && !enhanced.lineContent.includes(']')) ||
|
||||
(enhanced.lineContent.includes('{') && !enhanced.lineContent.includes('}')))
|
||||
) {
|
||||
errorMessage += ' (Check for missing closing parentheses, brackets, or braces)'
|
||||
} else {
|
||||
errorMessage += ' (Check your syntax)'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorMessage
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves environment variables and tags in code
|
||||
* @param code - Code with variables
|
||||
@@ -121,6 +325,8 @@ export async function POST(req: NextRequest) {
|
||||
const requestId = crypto.randomUUID().slice(0, 8)
|
||||
const startTime = Date.now()
|
||||
let stdout = ''
|
||||
let userCodeStartLine = 3 // Default value for error reporting
|
||||
let resolvedCode = '' // Store resolved code for error reporting
|
||||
|
||||
try {
|
||||
const body = await req.json()
|
||||
@@ -149,13 +355,15 @@ export async function POST(req: NextRequest) {
|
||||
})
|
||||
|
||||
// Resolve variables in the code with workflow environment variables
|
||||
const { resolvedCode, contextVariables } = resolveCodeVariables(
|
||||
const codeResolution = resolveCodeVariables(
|
||||
code,
|
||||
executionParams,
|
||||
envVars,
|
||||
blockData,
|
||||
blockNameMapping
|
||||
)
|
||||
resolvedCode = codeResolution.resolvedCode
|
||||
const contextVariables = codeResolution.contextVariables
|
||||
|
||||
const executionMethod = 'vm' // Default execution method
|
||||
|
||||
@@ -301,16 +509,12 @@ export async function POST(req: NextRequest) {
|
||||
// timeout,
|
||||
// displayErrors: true,
|
||||
// })
|
||||
// logger.info(`[${requestId}] VM execution result`, {
|
||||
// result,
|
||||
// stdout,
|
||||
// })
|
||||
// }
|
||||
// } else {
|
||||
logger.info(`[${requestId}] Using VM for code execution`, {
|
||||
resolvedCode,
|
||||
executionParams,
|
||||
envVars,
|
||||
hasEnvVars: Object.keys(envVars).length > 0,
|
||||
})
|
||||
|
||||
// Create a secure context with console logging
|
||||
@@ -336,28 +540,40 @@ export async function POST(req: NextRequest) {
|
||||
},
|
||||
})
|
||||
|
||||
const script = new Script(`
|
||||
(async () => {
|
||||
try {
|
||||
${
|
||||
isCustomTool
|
||||
? `// For custom tools, make parameters directly accessible
|
||||
${Object.keys(executionParams)
|
||||
.map((key) => `const ${key} = params.${key};`)
|
||||
.join('\n ')}`
|
||||
: ''
|
||||
}
|
||||
${resolvedCode}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
}
|
||||
})()
|
||||
`)
|
||||
// Calculate line offset for user code to provide accurate error reporting
|
||||
const wrapperLines = ['(async () => {', ' try {']
|
||||
|
||||
// Add custom tool parameter declarations if needed
|
||||
if (isCustomTool) {
|
||||
wrapperLines.push(' // For custom tools, make parameters directly accessible')
|
||||
Object.keys(executionParams).forEach((key) => {
|
||||
wrapperLines.push(` const ${key} = params.${key};`)
|
||||
})
|
||||
}
|
||||
|
||||
userCodeStartLine = wrapperLines.length + 1 // +1 because user code starts on next line
|
||||
|
||||
// Build the complete script with proper formatting for line numbers
|
||||
const fullScript = [
|
||||
...wrapperLines,
|
||||
` ${resolvedCode.split('\n').join('\n ')}`, // Indent user code
|
||||
' } catch (error) {',
|
||||
' console.error(error);',
|
||||
' throw error;',
|
||||
' }',
|
||||
'})()',
|
||||
].join('\n')
|
||||
|
||||
const script = new Script(fullScript, {
|
||||
filename: 'user-function.js', // This filename will appear in stack traces
|
||||
lineOffset: 0, // Start line numbering from 0
|
||||
columnOffset: 0, // Start column numbering from 0
|
||||
})
|
||||
|
||||
const result = await script.runInContext(context, {
|
||||
timeout,
|
||||
displayErrors: true,
|
||||
breakOnSigint: true, // Allow breaking on SIGINT for better debugging
|
||||
})
|
||||
// }
|
||||
|
||||
@@ -384,14 +600,40 @@ export async function POST(req: NextRequest) {
|
||||
executionTime,
|
||||
})
|
||||
|
||||
const enhancedError = extractEnhancedError(error, userCodeStartLine, resolvedCode)
|
||||
const userFriendlyErrorMessage = createUserFriendlyErrorMessage(
|
||||
enhancedError,
|
||||
requestId,
|
||||
resolvedCode
|
||||
)
|
||||
|
||||
// Log enhanced error details for debugging
|
||||
logger.error(`[${requestId}] Enhanced error details`, {
|
||||
originalMessage: error.message,
|
||||
enhancedMessage: userFriendlyErrorMessage,
|
||||
line: enhancedError.line,
|
||||
column: enhancedError.column,
|
||||
lineContent: enhancedError.lineContent,
|
||||
errorType: enhancedError.name,
|
||||
userCodeStartLine,
|
||||
})
|
||||
|
||||
const errorResponse = {
|
||||
success: false,
|
||||
error: error.message || 'Code execution failed',
|
||||
error: userFriendlyErrorMessage,
|
||||
output: {
|
||||
result: null,
|
||||
stdout,
|
||||
executionTime,
|
||||
},
|
||||
// Include debug information in development or for debugging
|
||||
debug: {
|
||||
line: enhancedError.line,
|
||||
column: enhancedError.column,
|
||||
errorType: enhancedError.name,
|
||||
lineContent: enhancedError.lineContent,
|
||||
stack: enhancedError.stack,
|
||||
},
|
||||
}
|
||||
|
||||
return NextResponse.json(errorResponse, { status: 500 })
|
||||
|
||||
Reference in New Issue
Block a user