const fs = require("fs"); const path = require("path"); const vm = require("vm"); const rootDir = path.resolve(__dirname, "..", ".."); const loadModule = (relativePath, injected = {}) => { const filePath = path.join(rootDir, relativePath); let source = fs.readFileSync(filePath, "utf8"); const defaultExportNames = []; source = source.replace(/import[\s\S]*?from\s+"[^"]+";\n?/g, ""); source = source.replace( /export default async function\s+(\w+)\s*\(/g, (match, name) => { defaultExportNames.push(name); return `async function ${name}(`; } ); source = source.replace( /export default function\s+(\w+)\s*\(/g, (match, name) => { defaultExportNames.push(name); return `function ${name}(`; } ); source = source.replace(/export const\s+/g, "const "); source = source.replace(/export default\s+(\w+);/g, (match, name) => { defaultExportNames.push(name); return `module.exports.default = ${name};`; }); defaultExportNames.forEach((name) => { source += `\nif (typeof ${name} !== "undefined" && !module.exports.default) module.exports.default = ${name};\n`; }); source += '\nif (typeof respondSuccess !== "undefined") module.exports.respondSuccess = respondSuccess;\n'; source += '\nif (typeof respondError !== "undefined") module.exports.respondError = respondError;\n'; source += '\nif (typeof ApiProxy !== "undefined" && !module.exports.default) module.exports.default = ApiProxy;\n'; const defaultRelayGet = async () => ({}); const context = { module: { exports: {} }, exports: {}, require, process, console: { log: () => {}, info: () => {}, warn: () => {}, error: () => {} }, relayGet: defaultRelayGet, RELAY_POLICY_STRICT_LOGIN: { method: "GET", timeoutMs: 5000, maxRetries: 0, retryBaseDelayMs: 0, retryMaxDelayMs: 0 }, RELAY_POLICY_LOOKUP: { method: "GET", timeoutMs: 6000, maxRetries: 1, retryBaseDelayMs: 100, retryMaxDelayMs: 500 }, RELAY_POLICY_BOUNDED_READ: { method: "GET", timeoutMs: 8000, maxRetries: 2, retryBaseDelayMs: 150, retryMaxDelayMs: 800 }, RELAY_POLICY_SEARCH_PAGED: { method: "GET", timeoutMs: 9000, maxRetries: 2, retryBaseDelayMs: 150, retryMaxDelayMs: 1000 }, ...injected }; vm.runInNewContext(source, context, { filename: filePath }); return context.module.exports; }; const createRes = () => { const state = { statusCode: null, jsonBody: undefined, sentBody: undefined, headers: {} }; return { state, status(code) { state.statusCode = code; return this; }, json(payload) { state.jsonBody = payload; return payload; }, send(payload) { state.sentBody = payload; return payload; }, setHeader(key, value) { state.headers[key.toLowerCase()] = value; } }; }; const createNextConnectMock = () => { const router = { handler: null, use: () => {}, get(fn) { this.handler = fn; }, post(fn) { this.handler = fn; } }; return () => router; }; const respondSuccessMock = (res, data, status = 200) => { return res.status(status).json(data); }; const respondErrorMock = ( res, { status = 500, code = "INTERNAL_SERVER_ERROR", message = "Request failed" } = {} ) => { return res.status(status).json({ success: false, error: { code, message } }); }; module.exports = { loadModule, createRes, createNextConnectMock, respondSuccessMock, respondErrorMock };