Files
sim/app/api/function/execute/route.ts
2025-03-04 13:48:27 -08:00

121 lines
3.4 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { Script, createContext } from 'vm'
// Explicitly export allowed methods
export const dynamic = 'force-dynamic' // Disable static optimization
export const runtime = 'nodejs' // Use Node.js runtime
/**
* Resolves environment variables and tags in code
* @param code - Code with variables
* @param params - Parameters that may contain variable values
* @param envVars - Environment variables from the workflow
* @returns Resolved code
*/
function resolveCodeVariables(
code: string,
params: Record<string, any>,
envVars: Record<string, string> = {}
): string {
let resolvedCode = code
// Resolve environment variables with {{var_name}} syntax
const envVarMatches = resolvedCode.match(/\{\{([^}]+)\}\}/g) || []
for (const match of envVarMatches) {
const varName = match.slice(2, -2).trim()
// Priority: 1. Environment variables from workflow, 2. Params, 3. process.env
const varValue = envVars[varName] || params[varName] || process.env[varName] || ''
resolvedCode = resolvedCode.replace(match, varValue)
}
// Resolve tags with <tag_name> syntax
const tagMatches = resolvedCode.match(/<([^>]+)>/g) || []
for (const match of tagMatches) {
const tagName = match.slice(1, -1).trim()
const tagValue = params[tagName] || ''
resolvedCode = resolvedCode.replace(match, tagValue)
}
return resolvedCode
}
export async function POST(req: NextRequest) {
const startTime = Date.now()
let stdout = ''
try {
const body = await req.json()
const { code, params = {}, timeout = 3000, envVars = {} } = body
// Resolve variables in the code with workflow environment variables
const resolvedCode = resolveCodeVariables(code, params, envVars)
// Create a secure context with console logging
const context = createContext({
params,
environmentVariables: envVars, // Make environment variables available in the context
console: {
log: (...args: any[]) => {
const logMessage =
args
.map((arg) => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)))
.join(' ') + '\n'
stdout += logMessage
},
error: (...args: any[]) => {
const errorMessage =
args
.map((arg) => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)))
.join(' ') + '\n'
console.error('❌ Code Console Error:', errorMessage.trim())
stdout += 'ERROR: ' + errorMessage
},
},
})
const script = new Script(`
(async () => {
try {
${resolvedCode}
} catch (error) {
console.error(error);
throw error;
}
})()
`)
const result = await script.runInContext(context, {
timeout,
displayErrors: true,
})
const executionTime = Date.now() - startTime
const response = {
success: true,
output: {
result,
stdout,
executionTime,
},
}
return NextResponse.json(response)
} catch (error: any) {
const executionTime = Date.now() - startTime
const errorResponse = {
success: false,
error: error.message || 'Code execution failed',
output: {
result: null,
stdout,
executionTime,
},
}
return NextResponse.json(errorResponse, { status: 500 })
}
}