import { join } from 'path'; import { nanoid } from 'nanoid'; import { chmod, mkdir, rm, writeFile } from 'fs/promises'; import { createServer } from 'net'; import { EventEmitter } from 'eventemitter3'; type SetupOptions = { input?: Buffer | string; script: string; secrets?: Record; cacheLocation: string; }; type RunEvents = { message: (event: any) => void; error: (error: Error) => void; exit: () => void; }; const setup = async (options: SetupOptions) => { const { input, script, secrets } = options; const emitter = new EventEmitter(); const dataDir = join(options.cacheLocation, nanoid()); await mkdir(dataDir, { recursive: true }); await chmod(dataDir, 0o700); const hostSocket = join(dataDir, 'host'); const httpGatewaySocket = join(dataDir, 'socket'); const server = createServer(); const inputLocation = join(dataDir, 'input'); const scriptLocation = join(dataDir, 'script.js'); if (input) { await writeFile(inputLocation, input); } await writeFile(scriptLocation, script); const env = { HOST_SOCKET: hostSocket, SECRETS: JSON.stringify(secrets || {}), INPUT_PATH: inputLocation, HTTP_GATEWAY_PATH: httpGatewaySocket, }; const teardown = async () => { server.close(); await rm(dataDir, { recursive: true, force: true }); }; server.on('connection', (socket) => { socket.on('data', (data) => { const message = JSON.parse(data.toString()); emitter.emit('message', message); }); }); server.listen(hostSocket); return { env, emitter, teardown, httpGatewaySocket, scriptLocation, hostSocket, }; }; type Setup = Awaited>; export type { Setup }; export { setup };