@multiplayer-app/sandbox 7.0.0 → 7.0.1
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/README.md +14 -11
- package/dist/cli.js +8 -7
- package/dist/cli.js.map +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/index.js +8 -7
- package/dist/index.js.map +2 -2
- package/package.json +3 -3
package/dist/cli.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/cli.ts", "../package.json", "../src/config.ts", "../src/images.ts", "../../builder-types/src/vm.ts", "../../builder-types/src/events.ts", "../../logger/src/logger.ts", "../../logger/src/config.ts", "../../logger/src/kafkajs-logger-creator.ts", "../../logger/src/index.ts", "../src/executor/mock-executor.ts", "../src/executor/qemu-executor.ts", "../src/executor/reattach-utils.ts", "../src/executor/env-encoding.ts", "../src/executor/firecracker-executor.ts", "../src/executor/docker-executor.ts", "../src/executor/docker-sandbox-executor.ts", "../src/executor/remote-executor.ts", "../src/executor/lambda-microvm-executor.ts", "../src/executor/fargate-executor.ts", "../src/executor/detect.ts", "../src/executor/index.ts", "../src/socket-client.ts", "../src/services/vnc-relay.ts", "../src/services/serial-relay.ts", "../src/console-relays.ts", "../src/prepare-images.ts", "../src/health-server.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n/* eslint-disable no-console -- console output is the CLI's user interface */\n// Worker CLI. Published as the global `sandbox` executable and also available locally via\n// `pnpm --filter @multiplayer-app/sandbox run cli -- <args>`.\nimport 'dotenv/config'\nimport { Command } from 'commander'\nimport { version as WORKER_VERSION } from '../package.json'\nimport { loadWorkerConfigFromEnv } from './config'\nimport { createExecutor } from './executor'\nimport { probeEngines } from './executor/detect'\nimport { defaultImagesDir, hostArch, pullImages, pushImages } from './images'\nimport { connectToSandbox } from './socket-client'\nimport { attachConsoleRelays } from './console-relays'\nimport { artifactImageLocation, prepareWorkerImages } from './prepare-images'\nimport { startSandboxHealthServer } from './health-server'\nimport logger from '@multiplayer-app/logger'\n\nconst program = new Command()\n\nprogram\n .name('sandbox')\n .description('Run and manage a Multiplayer sandbox worker')\n .version(WORKER_VERSION)\n\nprogram\n .command('start')\n .description('start a worker and connect it to the sandbox control plane')\n .option('--token <token>', 'worker authentication token (env: WORKER_TOKEN)')\n .option('--worker-id <id>', 'worker pool/authentication ID (env: WORKER_ID; default: hostname)')\n .option('--sandbox-url <url>', 'control-plane base URL (env: SANDBOX_URL; default: https://api.sandbox.filingramp.com/v0)')\n .option('--max-vms <count>', 'maximum concurrent VMs (env: MAX_VMS)')\n .action(async (opts: { token?: string; workerId?: string; sandboxUrl?: string; maxVms?: string }) => {\n const config = loadWorkerConfigFromEnv({\n ...process.env,\n ...(opts.token ? { WORKER_TOKEN: opts.token } : {}),\n ...(opts.workerId ? { WORKER_ID: opts.workerId } : {}),\n ...(opts.sandboxUrl ? { SANDBOX_URL: opts.sandboxUrl } : {}),\n ...(opts.maxVms ? { MAX_VMS: opts.maxVms } : {}),\n })\n const socketRef: { current?: ReturnType<typeof connectToSandbox> } = {}\n const healthServer = await startSandboxHealthServer({\n host: config.healthHost,\n port: config.healthPort,\n pathPrefix: config.healthPathPrefix,\n isReady: () => socketRef.current?.connected === true,\n })\n await prepareWorkerImages(config)\n const executor = createExecutor(config)\n const socket = connectToSandbox(config, executor)\n socketRef.current = socket\n attachConsoleRelays(executor, socket)\n\n let stopping = false\n const stop = async (signal: string): Promise<void> => {\n if (stopping) return\n stopping = true\n console.log(`\\n${signal} received; shutting down sandbox worker...`)\n socket.disconnect()\n healthServer.close()\n const results = await Promise.allSettled(executor.list().map((vm) => executor.destroy(vm.vmId)))\n const failed = results.filter((result) => result.status === 'rejected')\n if (failed.length) console.error(`Failed to destroy ${failed.length} VM(s) during shutdown`)\n process.exit(failed.length ? 1 : 0)\n }\n\n process.once('SIGINT', () => { void stop('SIGINT') })\n process.once('SIGTERM', () => { void stop('SIGTERM') })\n\n logger.info(`Starting sandbox worker ${config.workerId} \u2192 ${config.sandboxUrl}`)\n // Socket.IO's reconnect timers keep the process alive until a termination signal arrives.\n })\n\nprogram\n .command('detect')\n .description('probe this host and report which micro-VM engines it can run')\n .action(() => {\n const probes = probeEngines(loadWorkerConfigFromEnv({ ...process.env, WORKER_ID: '-', WORKER_TOKEN: '-' }))\n for (const probe of probes) {\n const status = probe.available ? 'available' : `unavailable \u2014 ${probe.reason}`\n console.log(`${probe.engine.padEnd(15)} ${status}`)\n }\n })\n\nconst images = program\n .command('images')\n .description('manage engine base images (kernel + initramfs for QEMU/Firecracker)')\n\nimages\n .command('pull')\n .description('download per-stack base images from S3 or an HTTPS mirror into the standard location')\n .requiredOption('--from <location>', 's3://bucket[/prefix] or https:// base URL (default derived from S3_BUCKET_ARTIFACTS)', artifactImageLocation())\n .option('--arch <arch>', 'image architecture', hostArch())\n .option('--stack <stack...>', 'stacks to pull (default: all)')\n .option('--dest <dir>', 'destination directory (default: ~/.multiplayer/vm-images/<arch>)')\n .option('--endpoint <url>', 'custom S3 endpoint, e.g. a MinIO URL (env: S3_ARTIFACTS_ENDPOINT)', process.env.S3_ARTIFACTS_ENDPOINT)\n .action(async (opts: { from: string; arch: string; stack?: string[]; dest?: string; endpoint?: string }) => {\n const dest = opts.dest ?? defaultImagesDir(opts.arch)\n const files = await pullImages({ location: opts.from, arch: opts.arch, stacks: opts.stack, endpoint: opts.endpoint }, dest)\n for (const file of files) console.log(`pulled ${file}`)\n console.log('\\nbase images ready \u2014 \"sandbox detect\" shows which engines they enable')\n })\n\nimages\n .command('push')\n .description('upload locally built per-stack base images (scripts/setup-vm-images.sh) to S3')\n .requiredOption('--to <location>', 's3://bucket[/prefix] (default derived from S3_BUCKET_ARTIFACTS)', artifactImageLocation())\n .option('--arch <arch>', 'image architecture', hostArch())\n .option('--stack <stack...>', 'stacks to push (default: all found locally)')\n .option('--src <dir>', 'source directory (default: ~/.multiplayer/vm-images/<arch>)')\n .option('--endpoint <url>', 'custom S3 endpoint, e.g. a MinIO URL (env: S3_ARTIFACTS_ENDPOINT)', process.env.S3_ARTIFACTS_ENDPOINT)\n .action(async (opts: { to: string; arch: string; stack?: string[]; src?: string; endpoint?: string }) => {\n const src = opts.src ?? defaultImagesDir(opts.arch)\n const uploaded = await pushImages({ location: opts.to, arch: opts.arch, stacks: opts.stack, endpoint: opts.endpoint }, src)\n for (const uri of uploaded) console.log(`pushed ${uri}`)\n })\n\nprogram.parseAsync().catch((error: Error) => {\n console.error(`Error: ${error.message}`)\n process.exit(1)\n})\n", "{\n \"name\": \"@multiplayer-app/sandbox\",\n \"version\": \"7.0.0\",\n \"description\": \"Sandbox worker library and CLI (Docker, QEMU, Firecracker, AWS Lambda MicroVM, Fargate)\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"require\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n }\n },\n \"bin\": {\n \"sandbox\": \"dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\",\n \"registry\": \"https://registry.npmjs.org/\"\n },\n \"scripts\": {\n \"build\": \"tsc --build --force && node scripts/bundle.mjs\",\n \"dev\": \"nodemon --watch src --watch scripts/bundle.mjs --watch package.json --ext ts,mjs,json --exec \\\"pnpm run build && pnpm run worker:start\\\"\",\n \"clean\": \"rm -rf ./dist tsconfig.tsbuildinfo\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"eslint src/**/*.ts --config ../../eslint.config.js\",\n \"images:build\": \"bash scripts/build-base-images.sh\",\n \"images:publish:local\": \"bash scripts/publish-base-images-local.sh\",\n \"images:upload:local\": \"SKIP_BUILD=1 bash scripts/publish-base-images-local.sh\",\n \"docker:build\": \"docker build -f Dockerfile -t multiplayer-sandbox-worker:local ../..\",\n \"start\": \"node dist/cli.js\",\n \"worker:start\": \"node dist/cli.js start\",\n \"test\": \"tsc --build --force && node --test 'dist/**/*.test.js'\",\n \"prepublishOnly\": \"pnpm run build\",\n \"postversion\": \"git commit -m \\\"sandbox v$npm_package_version\\\" -- package.json && git tag \\\"sandbox-v$npm_package_version\\\" && git push && git push --tags\"\n },\n \"dependencies\": {\n \"@aws-sdk/client-ec2\": \"^3.1087.0\",\n \"@aws-sdk/client-ecs\": \"^3.1087.0\",\n \"@aws-sdk/client-lambda-microvms\": \"^3.1079.0\",\n \"@aws-sdk/client-s3\": \"^3.1079.0\",\n \"bunyan\": \"1.8.15\",\n \"commander\": \"^14.0.0\",\n \"dotenv\": \"^17.2.3\",\n \"rfb2\": \"^0.2.2\",\n \"socket.io-client\": \"4.8.3\"\n },\n \"devDependencies\": {\n \"@multiplayer-app/builder-types\": \"workspace:*\",\n \"@multiplayer-app/logger\": \"workspace:*\",\n \"@types/node\": \"^25.8.0\",\n \"esbuild\": \"^0.25.12\",\n \"nodemon\": \"3.1.14\",\n \"typescript\": \"^6.0.3\"\n }\n}\n", "import os from 'os'\nimport path from 'path'\nimport { version as WORKER_VERSION } from '../package.json'\nimport { defaultImagesDir } from './images'\n\nexport { WORKER_VERSION }\n\nexport interface RemoteWorkerConfig {\n agentUrl: string\n authToken?: string\n}\n\nexport interface FirecrackerWorkerConfig {\n bin: string\n imagesDir: string\n kernelPath?: string\n initrdPath?: string\n vmDataPath: string\n}\n\nexport interface QemuWorkerConfig {\n bin: string\n imagesDir: string\n kernelPath?: string\n initrdPath?: string\n vmDataPath: string\n portRangeStart: number\n portRangeEnd: number\n accel: string\n cpu: string\n machine: string\n}\n\nexport interface LambdaMicrovmWorkerConfig {\n region?: string\n imageArn: string\n stackImageArns: Record<string, string>\n ingressConnectorArns?: string[]\n egressConnectorArns?: string[]\n executionRoleArn?: string\n maxIdleSeconds: number\n suspendedDurationSeconds: number\n maximumDurationInSeconds: number\n}\n\nexport interface DockerWorkerConfig {\n bin: string\n imagePrefix: string\n imageTag: string\n stackImages: Record<string, string>\n network?: string\n portRangeStart: number\n portRangeEnd: number\n guestPort: number\n}\n\nexport interface DockerSandboxWorkerConfig {\n bin: string\n imagePrefix: string\n imageTag: string\n /** Fully-qualified `sbx template load`ed ref overrides, keyed by stack. */\n stackTemplates: Record<string, string>\n /** In-sandbox start command per stack \u2014 `sbx create shell` doesn't run the image's own CMD. */\n stackAgentCommands: Record<string, string>\n workspaceRoot: string\n portRangeStart: number\n portRangeEnd: number\n guestPort: number\n minMemoryMib: number\n}\n\nexport interface FargateWorkerConfig {\n region?: string\n cluster: string\n taskDefinition?: string\n stackTaskDefinitions: Record<string, string>\n subnets: string[]\n securityGroups?: string[]\n assignPublicIp: boolean\n guestPort: number\n startTimeoutMs: number\n}\n\nexport interface WorkerConfig {\n /** Credential/pool identity. Multiple instances may intentionally share it. */\n workerId: string\n token?: string\n sandboxUrl: string\n workerSocketPath: string\n maxVms: number\n healthHost: string\n healthPort: number\n healthPathPrefix: string\n region?: string\n remote: RemoteWorkerConfig\n firecracker: FirecrackerWorkerConfig\n qemu: QemuWorkerConfig\n docker: DockerWorkerConfig\n dockerSandbox: DockerSandboxWorkerConfig\n lambdaMicrovm: LambdaMicrovmWorkerConfig\n fargate: FargateWorkerConfig\n}\n\n/** Format: \"node:<value>,python:<value>\" \u2014 per-stack overrides (MicroVM image ARNs, Fargate task defs). */\nfunction parseStackMap(raw: string | undefined): Record<string, string> {\n const map: Record<string, string> = {}\n if (!raw) return map\n for (const pair of raw.split(',')) {\n const idx = pair.indexOf(':')\n if (idx === -1) continue\n const stack = pair.slice(0, idx).trim()\n const arn = pair.slice(idx + 1).trim()\n if (stack && arn) map[stack] = arn\n }\n return map\n}\n\nfunction parseArnList(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined\n const arns = raw.split(',').map((s) => s.trim()).filter(Boolean)\n return arns.length ? arns : undefined\n}\n\nfunction resolveSandboxEndpoint(rawUrl: string, explicitSocketPath?: string): {\n sandboxUrl: string\n workerSocketPath: string\n} {\n const url = new URL(rawUrl)\n const basePath = url.pathname.replace(/\\/+$/, '') || '/v0'\n return {\n // Socket.IO treats a URL pathname as a namespace, so connect to the origin\n // and pass the derived HTTP transport path separately.\n sandboxUrl: url.origin,\n workerSocketPath: explicitSocketPath ?? `${basePath}/sapi/workers/ws`,\n }\n}\n\nexport function loadWorkerConfigFromEnv(env: NodeJS.ProcessEnv = process.env): WorkerConfig {\n const workerId = env.WORKER_ID?.trim() || os.hostname()\n const token = env.WORKER_TOKEN?.trim() || undefined\n const sandboxEndpoint = resolveSandboxEndpoint(\n env.SANDBOX_URL ?? 'https://api.sandbox.filingramp.com/v0',\n env.WORKER_SOCKET_PATH,\n )\n\n return {\n workerId,\n token,\n sandboxUrl: sandboxEndpoint.sandboxUrl,\n workerSocketPath: sandboxEndpoint.workerSocketPath,\n maxVms: Number(env.MAX_VMS) || 10,\n healthHost: env.SANDBOX_HEALTH_HOST ?? '0.0.0.0',\n healthPort: Number(env.SANDBOX_HEALTH_PORT) || 3000,\n healthPathPrefix: (env.API_PREFIX ?? '/v0/api').replace(/\\/+$/, ''),\n region: env.WORKER_REGION,\n remote: {\n // No default: an unset AGENT_URL means the remote engine is not configured on this worker\n agentUrl: env.AGENT_URL ?? '',\n authToken: env.AGENT_TOKEN,\n },\n firecracker: {\n bin: env.FIRECRACKER_BIN ?? 'firecracker',\n // Per-stack base images (<imagesDir>/<stack>/vmlinuz + initramfs.img) from\n // `worker-cli images pull` / setup-vm-images.sh; engine detection checks\n // existence, so missing images just disable the engine.\n imagesDir: env.FIRECRACKER_IMAGES_DIR ?? env.VM_IMAGES_DIR ?? defaultImagesDir(),\n // Explicit single-image override, applied to every stack when both are set\n kernelPath: env.FIRECRACKER_KERNEL,\n initrdPath: env.FIRECRACKER_INITRD,\n vmDataPath: env.FIRECRACKER_VM_DATA ?? path.join(os.tmpdir(), 'firecracker-vms'),\n },\n lambdaMicrovm: {\n region: env.MICROVM_AWS_REGION ?? env.AWS_REGION,\n imageArn: env.MICROVM_IMAGE_ARN ?? '',\n stackImageArns: parseStackMap(env.MICROVM_STACK_IMAGE_ARNS),\n ingressConnectorArns: parseArnList(env.MICROVM_INGRESS_CONNECTORS),\n egressConnectorArns: parseArnList(env.MICROVM_EGRESS_CONNECTORS),\n executionRoleArn: env.MICROVM_EXECUTION_ROLE_ARN,\n // 0 disables auto-suspend; the sandbox drives pause/resume explicitly by default\n maxIdleSeconds: Number(env.MICROVM_MAX_IDLE_SECONDS ?? 900),\n suspendedDurationSeconds: Number(env.MICROVM_SUSPENDED_DURATION_SECONDS ?? 28_800),\n maximumDurationInSeconds: Number(env.MICROVM_MAX_DURATION_SECONDS ?? 28_800),\n },\n fargate: {\n region: env.FARGATE_AWS_REGION ?? env.AWS_REGION,\n cluster: env.FARGATE_CLUSTER ?? '',\n taskDefinition: env.FARGATE_TASK_DEFINITION,\n // Per-stack task definitions: \"node:builder-node:3,python:builder-python:1\"\n stackTaskDefinitions: parseStackMap(env.FARGATE_STACK_TASK_DEFS),\n subnets: env.FARGATE_SUBNETS?.split(',').map((s) => s.trim()).filter(Boolean) ?? [],\n securityGroups: env.FARGATE_SECURITY_GROUPS?.split(',').map((s) => s.trim()).filter(Boolean),\n // ENABLED when the worker runs outside the task VPC (proxies to the task's public IP)\n assignPublicIp: env.FARGATE_ASSIGN_PUBLIC_IP === 'true',\n guestPort: Number(env.FARGATE_GUEST_PORT) || 8080,\n startTimeoutMs: Number(env.FARGATE_START_TIMEOUT_MS) || 180_000,\n },\n docker: {\n bin: env.DOCKER_BIN ?? 'docker',\n // Local images from `scripts/setup-docker-images.sh`: <imagePrefix>-<stack>:<imageTag>\n imagePrefix: env.DOCKER_IMAGE_PREFIX ?? 'multiplayer-builder-vm',\n imageTag: env.DOCKER_IMAGE_TAG ?? 'local',\n stackImages: parseStackMap(env.DOCKER_STACK_IMAGES),\n network: env.DOCKER_NETWORK,\n portRangeStart: Number(env.DOCKER_PORT_MIN) || 9100,\n portRangeEnd: Number(env.DOCKER_PORT_MAX) || 9199,\n guestPort: Number(env.DOCKER_GUEST_PORT) || 8080,\n },\n dockerSandbox: {\n bin: env.SBX_BIN ?? 'sbx',\n // Bridged from the same local images `docker` (imagePrefix-imageTag) already uses \u2014\n // `docker save` + `sbx template load`, see docker-sandbox-executor.ts.\n imagePrefix: env.SBX_IMAGE_PREFIX ?? env.DOCKER_IMAGE_PREFIX ?? 'multiplayer-builder-vm',\n imageTag: env.SBX_IMAGE_TAG ?? env.DOCKER_IMAGE_TAG ?? 'local',\n stackTemplates: parseStackMap(env.SBX_STACK_TEMPLATES),\n // `sbx create shell` doesn't run the image's own CMD, so the engine launches\n // it explicitly \u2014 defaults match each Dockerfile's own WORKDIR /app + CMD.\n stackAgentCommands: {\n node: 'node app.js',\n python: 'python app.py',\n static: 'node app.js',\n ...parseStackMap(env.SBX_STACK_AGENT_COMMANDS),\n },\n workspaceRoot: env.SBX_WORKSPACE_DIR ?? path.join(os.tmpdir(), 'sbx-vms'),\n portRangeStart: Number(env.SBX_PORT_MIN) || 9200,\n portRangeEnd: Number(env.SBX_PORT_MAX) || 9299,\n guestPort: Number(env.SBX_GUEST_PORT) || 8080,\n // sbx rejects sandboxes below 1 GiB memory.\n minMemoryMib: Number(env.SBX_MIN_MEMORY_MIB) || 1024,\n },\n qemu: {\n bin: env.QEMU_BIN ?? 'qemu-system-aarch64',\n // Per-stack base images (<imagesDir>/<stack>/vmlinuz + initramfs.img) from\n // `worker-cli images pull` / setup-vm-images.sh; engine detection checks\n // existence, so missing images just disable the engine.\n imagesDir: env.QEMU_IMAGES_DIR ?? env.VM_IMAGES_DIR ?? defaultImagesDir(),\n // Explicit single-image override, applied to every stack when both are set\n kernelPath: env.QEMU_KERNEL,\n initrdPath: env.QEMU_INITRD,\n vmDataPath: env.QEMU_VM_DATA ?? path.join(os.tmpdir(), 'qemu-vms'),\n portRangeStart: Number(env.QEMU_PORT_MIN) || 9000,\n portRangeEnd: Number(env.QEMU_PORT_MAX) || 9999,\n // Accelerator: hvf (macOS host), kvm (Linux + /dev/kvm), tcg (software, any host \u2014 slow)\n accel: env.QEMU_ACCEL ?? (process.platform === 'darwin' ? 'hvf' : 'kvm'),\n // CPU model: host requires hvf/kvm; max is best for tcg on aarch64; qemu64 for tcg x86_64\n cpu: env.QEMU_CPU ?? 'host',\n // Machine type: virt (aarch64), q35 (x86_64)\n machine: env.QEMU_MACHINE ?? 'virt',\n },\n }\n}\n", "import fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport { pipeline } from 'stream/promises'\nimport { Readable } from 'stream'\nimport { VM_STACKS, type VmStack } from '@multiplayer-app/builder-types'\n\n/** Files that make up one stack's base image (built by scripts/setup-vm-images.sh). */\nexport const IMAGE_FILES = ['vmlinuz', 'initramfs.img'] as const\n/** Stacks included in the published base-image catalog; `generic` remains a local fallback only. */\nexport const PUBLISHED_IMAGE_STACKS = VM_STACKS.filter((stack) => stack !== 'generic')\n\n/** Normalize Node's process.arch to the uname-style names used in image paths. */\nexport function hostArch(): string {\n switch (process.arch) {\n case 'arm64': return 'aarch64'\n case 'x64': return 'x86_64'\n default: return process.arch\n }\n}\n\n/** Default local image directory \u2014 the same location scripts/setup-vm-images.sh writes to. */\nexport function defaultImagesDir(arch: string = hostArch()): string {\n return path.join(os.homedir(), '.multiplayer', 'vm-images', arch)\n}\n\n/** Kernel + initrd for one stack under an images dir, or undefined if incomplete. */\nexport function resolveStackImages(imagesDir: string, stack: string): { kernelPath: string; initrdPath: string } | undefined {\n const kernelPath = path.join(imagesDir, stack, 'vmlinuz')\n const initrdPath = path.join(imagesDir, stack, 'initramfs.img')\n return fs.existsSync(kernelPath) && fs.existsSync(initrdPath) ? { kernelPath, initrdPath } : undefined\n}\n\n/** Stacks that have a complete base image under an images dir. */\nexport function availableStacks(imagesDir: string): VmStack[] {\n return VM_STACKS.filter((stack) => resolveStackImages(imagesDir, stack) !== undefined)\n}\n\nexport interface ImageSourceOptions {\n /** s3://bucket[/prefix] or http(s):// base URL holding <arch>/<stack>/vmlinuz + initramfs.img */\n location: string\n arch: string\n /** Stacks to transfer (default: all known stacks). */\n stacks?: readonly string[]\n /** Custom S3 endpoint (MinIO, etc.); implies path-style addressing. */\n endpoint?: string\n}\n\nfunction parseS3Uri(uri: string): { bucket: string; prefix: string } {\n const match = /^s3:\\/\\/([^/]+)\\/?(.*)$/.exec(uri)\n if (!match) throw new Error(`invalid S3 URI \"${uri}\" \u2014 expected s3://bucket[/prefix]`)\n return { bucket: match[1], prefix: match[2].replace(/\\/+$/, '') }\n}\n\nfunction s3Key(prefix: string, arch: string, stack: string, file: string): string {\n return [prefix, arch, stack, file].filter(Boolean).join('/')\n}\n\nasync function makeS3Client(endpoint?: string) {\n const { S3Client } = await import('@aws-sdk/client-s3')\n return new S3Client({\n ...(endpoint ? { endpoint, forcePathStyle: true } : {}),\n ...(process.env.AWS_REGION ? {} : { region: 'us-east-1' }),\n // aws-chunked checksum streaming breaks older S3-compatible stores (MinIO)\n requestChecksumCalculation: 'WHEN_REQUIRED',\n })\n}\n\nasync function downloadFromS3(opts: ImageSourceOptions, stack: string, file: string, dest: string): Promise<void> {\n const { GetObjectCommand } = await import('@aws-sdk/client-s3')\n const { bucket, prefix } = parseS3Uri(opts.location)\n const client = await makeS3Client(opts.endpoint)\n const key = s3Key(prefix, opts.arch, stack, file)\n const response = await client.send(new GetObjectCommand({ Bucket: bucket, Key: key }))\n if (!response.Body) throw new Error(`empty response for s3://${bucket}/${key}`)\n await pipeline(response.Body as Readable, fs.createWriteStream(dest))\n}\n\nasync function downloadFromHttp(opts: ImageSourceOptions, stack: string, file: string, dest: string): Promise<void> {\n const url = `${opts.location.replace(/\\/+$/, '')}/${opts.arch}/${stack}/${file}`\n const response = await fetch(url)\n if (!response.ok || !response.body) {\n throw new Error(`GET ${url} failed: ${response.status} ${response.statusText}`)\n }\n await pipeline(Readable.fromWeb(response.body as import('stream/web').ReadableStream), fs.createWriteStream(dest))\n}\n\n/** Download base images for the given stacks into destDir/<stack>/ (atomic per file via .partial rename). */\nexport async function pullImages(opts: ImageSourceOptions, destDir: string): Promise<string[]> {\n const isS3 = opts.location.startsWith('s3://')\n const downloaded: string[] = []\n\n for (const stack of opts.stacks ?? PUBLISHED_IMAGE_STACKS) {\n const stackDir = path.join(destDir, stack)\n fs.mkdirSync(stackDir, { recursive: true })\n for (const file of IMAGE_FILES) {\n const dest = path.join(stackDir, file)\n const partial = `${dest}.partial`\n if (isS3) await downloadFromS3(opts, stack, file, partial)\n else await downloadFromHttp(opts, stack, file, partial)\n fs.renameSync(partial, dest)\n downloaded.push(dest)\n }\n }\n return downloaded\n}\n\n/** Upload base images for the given stacks from srcDir/<stack>/ to s3://bucket[/prefix]/<arch>/<stack>/. */\nexport async function pushImages(opts: ImageSourceOptions, srcDir: string): Promise<string[]> {\n const { PutObjectCommand } = await import('@aws-sdk/client-s3')\n const { bucket, prefix } = parseS3Uri(opts.location)\n const client = await makeS3Client(opts.endpoint)\n const uploaded: string[] = []\n\n const stacks = opts.stacks ?? availableStacks(srcDir)\n if (!stacks.length) {\n throw new Error(`no stack images found under ${srcDir} \u2014 run scripts/setup-vm-images.sh first`)\n }\n\n for (const stack of stacks) {\n for (const file of IMAGE_FILES) {\n const src = path.join(srcDir, stack, file)\n if (!fs.existsSync(src)) {\n throw new Error(`${src} not found \u2014 run scripts/setup-vm-images.sh first`)\n }\n const key = s3Key(prefix, opts.arch, stack, file)\n // Buffer instead of stream: keeps Content-Length exact and avoids aws-chunked\n // encoding that older S3-compatible stores reject. Images are ~20-50 MB.\n await client.send(new PutObjectCommand({\n Bucket: bucket,\n Key: key,\n Body: fs.readFileSync(src),\n }))\n uploaded.push(`s3://${bucket}/${key}`)\n }\n }\n return uploaded\n}\n", "import type { GatewayAccessConfig } from './access'\n\nexport const VM_STACKS = ['generic', 'node', 'python', 'static'] as const\nexport type VmStack = (typeof VM_STACKS)[number]\n\nexport const VM_ENGINES = [\n 'mock',\n 'qemu',\n 'firecracker',\n 'docker',\n 'docker-sandbox',\n 'remote',\n 'lambda-microvm',\n 'fargate',\n] as const\nexport type VmEngine = (typeof VM_ENGINES)[number]\n\n/** 'service': a persistent process the gateway proxies to. 'job': runs its entrypoint once and exits. */\nexport const VM_RUN_MODES = ['service', 'job'] as const\nexport type VmRunMode = (typeof VM_RUN_MODES)[number]\n\nexport type VmState =\n | 'creating'\n | 'running'\n | 'pausing'\n | 'paused'\n | 'resuming'\n | 'stopping'\n | 'stopped'\n | 'restoring'\n | 'destroying'\n | 'error'\n /** Job VM whose entrypoint exited with code 0. See VmRecord.result. */\n | 'completed'\n /** User-initiated teardown that keeps the record around (e.g. as deployment history) instead of deleting it. */\n | 'destroyed'\n\nexport const VM_ACTIONS = ['pause', 'resume', 'stop', 'restore'] as const\nexport type VmAction = (typeof VM_ACTIONS)[number]\n\nexport interface VmResources {\n vcpuCount: number\n memMib: number\n}\n\nexport interface VmRecord {\n vmId: string\n /** Builder session this VM belongs to; optional for VMs not tied to a session. */\n sessionId?: string\n workerId: string\n stack: VmStack\n /** Micro-VM engine the VM runs on. Absent on records created before engines existed. */\n engine?: VmEngine\n /** Release whose artifact the VM pulled and started at boot. */\n releaseId?: string\n /** Gateway-level access protection (Cloudflare Access-style login gate). */\n access?: GatewayAccessConfig\n resources: VmResources\n state: VmState\n /** 'service' (default) for a persistent proxied process, 'job' for a run-once script. */\n runMode: VmRunMode\n /** Custom environment variables for the guest entrypoint. */\n env?: Record<string, string>\n /** Set once a 'job' VM's entrypoint exits (state becomes 'completed' or 'error'). */\n result?: VmRunResult\n /**\n * Opaque, engine-specific data an executor needs to reattach to this VM after a worker\n * restart (e.g. a QEMU QMP socket path, a Fargate task ARN). Sandbox stores it as-is and\n * never interprets it \u2014 only the executor that created it knows the shape.\n */\n runtimeMetadata?: Record<string, unknown>\n createdAt: string\n updatedAt: string\n}\n\nexport interface VmCreateRequest {\n /** Builder session to associate the VM with (not validated; informational for now). */\n sessionId?: string\n stack: VmStack\n /** Requested micro-VM engine. Omit to use the scheduled worker's default engine. */\n engine?: VmEngine\n /** Release to deploy into the VM: the guest pulls the artifact (presigned URL), unzips, and starts it. */\n releaseId?: string\n /** 'service' (default) keeps the entrypoint running and proxied; 'job' runs it once and exits. */\n runMode?: VmRunMode\n /** Custom environment variables for the guest entrypoint. */\n env?: Record<string, string>\n resources?: Partial<VmResources>\n}\n\nexport interface VmExecRequest {\n /** Shell command executed inside the VM workspace. */\n command: string\n /** Working directory relative to the VM workspace root. */\n cwd?: string\n /** Wall-clock limit for the command; capped by the executor. */\n timeoutMs?: number\n}\n\nexport interface VmExecResult {\n exitCode: number\n stdout: string\n stderr: string\n durationMs: number\n /** True when stdout/stderr were cut at the executor's output cap. */\n truncated: boolean\n /** True when the command was killed by the timeout. */\n timedOut: boolean\n}\n\n/** Outcome of a 'job' VM's entrypoint running to completion. */\nexport interface VmRunResult {\n exitCode: number\n stdout: string\n stderr: string\n /** True when stdout/stderr were cut at the executor's output cap. */\n truncated: boolean\n durationMs: number\n finishedAt: string\n}\n\nexport interface VmFileWrite {\n /** Path relative to the VM workspace root (no leading slash, no traversal). */\n path: string\n content: string\n /** How `content` is encoded; utf8 by default, base64 for binary files. */\n encoding?: 'utf8' | 'base64'\n}\n\nexport interface VmWriteFilesResult {\n written: Array<{ path: string; bytes: number }>\n}\n\nexport interface ProxyRequestDescriptor {\n method: string\n path: string\n headers: Record<string, string>\n body?: Buffer\n}\n\nexport interface ProxyResponseDescriptor {\n statusCode: number\n headers: Record<string, string>\n body?: Buffer\n}\n\nexport interface CommandResult {\n ok: boolean\n error?: string\n}\n\nexport interface CommandAck<T = unknown> extends CommandResult {\n result?: T\n}\n\nexport const VM_REDIS_KEY_PREFIX = 'vm:'\n\nexport interface VmRegistryEntry {\n workerId: string\n state: VmState\n access?: GatewayAccessConfig\n}\n", "import type { VmAction, VmRunResult } from './vm'\n\n// \u2500\u2500 Worker socket events (sandbox \u2194 worker) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Events exchanged on the worker socket (sandbox side listens, worker side emits \u2014 and vice versa). */\nexport const WorkerEvent = {\n // worker \u2192 sandbox\n HEARTBEAT: 'worker:heartbeat',\n\n // worker \u2192 sandbox, fire-and-forget like HEARTBEAT \u2014 sent once when a 'job' VM's\n // entrypoint exits on its own (the worker has already torn the resource down by then).\n VM_RUN_EXITED: 'vm:run-exited',\n\n // sandbox \u2192 worker, generated by the control plane and reused by this worker process\n // on Socket.IO reconnects. This keeps duplicate configured WORKER_ID values isolated.\n ASSIGNED_ID: 'worker:assigned-id',\n\n // sandbox \u2192 worker, once right after auth on every (re)connect \u2014 the VMs sandbox's\n // records say this workerId owns, so the worker can try to reattach before its first\n // heartbeat. Always sent, even with an empty array, as a handshake signal.\n REATTACH: 'worker:reattach',\n\n // sandbox \u2192 worker (VM lifecycle commands)\n VM_CREATE: 'vm:create',\n VM_PAUSE: 'vm:pause',\n VM_RESUME: 'vm:resume',\n VM_STOP: 'vm:stop',\n VM_RESTORE: 'vm:restore',\n VM_DESTROY: 'vm:destroy',\n\n // sandbox / gateway \u2192 worker (HTTP proxy)\n PROXY_HTTP: 'proxy:http',\n\n // sandbox \u2192 worker (guest workspace commands)\n VM_EXEC: 'vm:exec',\n VM_WRITE_FILES: 'vm:write-files',\n\n // worker \u2192 sandbox (VNC/terminal media relay)\n VNC_INIT: 'vnc:init',\n VNC_FRAME: 'vnc:frame',\n VNC_COPY_FRAME: 'vnc:copy-frame',\n TERMINAL_DATA: 'terminal:data',\n\n // sandbox \u2192 worker (browser input forwarded downstream)\n VNC_MOUSE: 'vnc:mouse',\n VNC_KEYBOARD: 'vnc:keyboard',\n TERMINAL_INPUT: 'terminal:input',\n} as const\n\nexport type WorkerEventName = (typeof WorkerEvent)[keyof typeof WorkerEvent]\n\n/** Maps a VmAction to its worker socket event name. */\nexport const VM_ACTION_EVENTS: Record<VmAction, string> = {\n pause: WorkerEvent.VM_PAUSE,\n resume: WorkerEvent.VM_RESUME,\n stop: WorkerEvent.VM_STOP,\n restore: WorkerEvent.VM_RESTORE,\n}\n\n// \u2500\u2500 Console socket events (browser \u2194 sandbox /vm-console/ws) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Events on the browser-facing console Socket.io namespaces (/vnc and /terminal). */\nexport const ConsoleEvent = {\n // /vnc namespace: sandbox \u2192 browser\n VNC_INIT: 'init',\n VNC_FRAME: 'frame',\n VNC_COPY_FRAME: 'copy-frame',\n\n // /vnc namespace: browser \u2192 sandbox\n VNC_MOUSE: 'mouse',\n VNC_KEYBOARD: 'keyboard',\n\n // /terminal namespace: sandbox \u2194 browser\n TERMINAL_DATA: 'data',\n TERMINAL_INPUT: 'data',\n} as const\n\n// \u2500\u2500 Payload types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface VncInitPayload {\n vmId: string\n width: number\n height: number\n}\n\nexport interface VncFramePayload {\n vmId: string\n x: number\n y: number\n width: number\n height: number\n encoding: 'raw'\n data: Buffer\n}\n\nexport interface VncCopyFramePayload {\n vmId: string\n x: number\n y: number\n src: { x: number; y: number }\n width: number\n height: number\n}\n\nexport interface TerminalDataPayload {\n vmId: string\n data: Buffer\n}\n\nexport interface VncMousePayload {\n vmId: string\n x: number\n y: number\n button: number\n}\n\nexport interface VncKeyboardPayload {\n vmId: string\n keyCode: number\n isDown: boolean\n}\n\nexport interface TerminalInputPayload {\n vmId: string\n data: string\n}\n\nexport interface VmRunExitedPayload extends VmRunResult {\n vmId: string\n}\n", "import bunyan, {\n type LoggerOptions,\n type LogLevelString,\n} from 'bunyan'\nimport { hostname } from 'os'\nimport {\n APP_NAME,\n LOG_LEVEL,\n} from './config'\n\nconst HOST_NAME = hostname()\n\nconst loggerOptions: LoggerOptions = {\n name: APP_NAME,\n level: LOG_LEVEL as LogLevelString,\n hostname: HOST_NAME,\n serializers: bunyan.stdSerializers,\n}\n\nexport const logger = bunyan.createLogger(loggerOptions)\n\n// const events = [\n// 'exit',\n// 'SIGINT',\n// 'SIGTERM',\n// 'uncaughtException',\n// ]\n\n// const exit = () => {\n// // logger.reopenFileStreams()\n// }\n\n// events.forEach(event => process.on(event, exit))\n", "export const NODE_ENV = process.env.NODE_ENV || 'development'\nexport const isProduction = NODE_ENV === 'production'\n// npm_package_name is only set when launched via `npm run`/`pnpm run` \u2014 production images start\n// services with a plain `node dist/index.js`, so APP_NAME must be set explicitly there.\nexport const APP_NAME =\n process.env.APP_NAME || process.env.npm_package_name?.split('/').pop() || 'unknown-app'\nexport const LOG_LEVEL = process.env.LOG_LEVEL || (isProduction ? 'info' : 'debug')\n", "import bunyan, { type LoggerOptions } from 'bunyan'\nimport { hostname } from 'os'\nimport { isProduction, APP_NAME } from './config'\n\nconst HOST_NAME = hostname()\n\nconst loggerOptions: LoggerOptions = {\n name: APP_NAME,\n level: isProduction ? 'info' : 'debug',\n hostname: HOST_NAME,\n}\n\nexport const KafkaJsLogCreator = (logLevelConverter: any) => (level: any) => {\n if (level) {\n loggerOptions.level = logLevelConverter(level)\n }\n const logger = bunyan.createLogger(loggerOptions)\n\n return ({ level, log }) => {\n const { message, ...extra } = log\n logger[logLevelConverter(level)]({\n extra,\n }, message)\n }\n}\n", "import { logger } from './logger'\n\nexport { middleware as loggerExpressMiddleware } from './middleware'\nexport { default as logError } from './log-error.decorator'\nexport { default as asyncLogError } from './log-error-async.decorator'\nexport * from './kafkajs-logger-creator'\nexport default logger\nexport * from './kafkajs-logger-creator'\n", "import { execFile } from 'child_process'\nimport fs from 'fs/promises'\nimport http from 'http'\nimport type { IncomingMessage, ServerResponse } from 'http'\nimport os from 'os'\nimport path from 'path'\nimport type { AddressInfo } from 'net'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmExecRequest,\n VmExecResult,\n VmFileWrite,\n VmRunMode,\n VmRunResult,\n VmWriteFilesResult,\n} from '@multiplayer-app/builder-types'\nimport logger from '@multiplayer-app/logger'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nconst DEFAULT_EXEC_TIMEOUT_MS = 60_000\nconst MAX_EXEC_TIMEOUT_MS = 300_000\nconst MAX_OUTPUT_BYTES = 1024 * 1024\nconst MAX_FILE_BYTES = 5 * 1024 * 1024\n\nconst CONTENT_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'text/javascript; charset=utf-8',\n '.mjs': 'text/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.txt': 'text/plain; charset=utf-8',\n '.md': 'text/plain; charset=utf-8',\n}\n\ninterface ManagedVm {\n handle: VmHandle\n server: http.Server\n port: number\n workspaceDir: string\n runMode: VmRunMode\n startedAt: number\n}\n\n/** ms until a mock 'job' VM synthesizes a completion result \u2014 short enough for tests to not stall. */\nconst MOCK_JOB_DURATION_MS = 250\n\n/** Resolve a workspace-relative path, rejecting escapes (\"../\", absolute paths). */\nfunction resolveWorkspacePath(workspaceDir: string, relativePath: string): string {\n const normalized = path.normalize(relativePath).replace(/^([/\\\\])+/, '')\n const resolved = path.resolve(workspaceDir, normalized)\n if (resolved !== workspaceDir && !resolved.startsWith(workspaceDir + path.sep)) {\n throw new Error(`Path escapes the VM workspace: ${relativePath}`)\n }\n return resolved\n}\n\n/**\n * Stand-in for a real microVM: serves the VM workspace directory over HTTP\n * (index.html fallback), playing the role of \"the app inside the VM\".\n */\nfunction startStandInServer(\n spec: VmSpec,\n workspaceDir: string,\n): Promise<{ server: http.Server; port: number }> {\n const server = http.createServer((req: IncomingMessage, res: ServerResponse) => {\n void (async () => {\n const requestPath = decodeURIComponent((req.url ?? '/').split('?')[0])\n const relative = requestPath === '/' ? 'index.html' : requestPath\n try {\n const filePath = resolveWorkspacePath(workspaceDir, relative)\n const content = await fs.readFile(filePath)\n res.writeHead(200, {\n 'content-type':\n CONTENT_TYPES[path.extname(filePath).toLowerCase()] ?? 'application/octet-stream',\n })\n res.end(content)\n } catch {\n res.writeHead(200, { 'content-type': 'text/plain' })\n res.end(\n `mock vm ${spec.vmId} (${spec.stack}) \u2014 session ${spec.sessionId} \u2014 ${req.method} ${req.url}\\n`,\n )\n }\n })()\n })\n\n return new Promise((resolve, reject) => {\n server.once('error', reject)\n server.listen(0, '127.0.0.1', () => {\n resolve({ server, port: (server.address() as AddressInfo).port })\n })\n })\n}\n\nexport class MockExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), `mock-vm-${spec.vmId}-`))\n const { server, port } = await startStandInServer(spec, workspaceDir)\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n // No real process to configure \u2014 just echoed back for introspection/tests.\n ...(spec.env ? { metadata: { env: spec.env } } : {}),\n }\n\n const runMode = spec.runMode ?? 'service'\n this.vms.set(spec.vmId, { handle, server, port, workspaceDir, runMode, startedAt: Date.now() })\n logger.info({ vmId: spec.vmId, port, workspaceDir, runMode }, 'mock vm created')\n return handle\n }\n\n /** No real process to watch \u2014 just synthesize a successful run shortly after create(). */\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const startedAt = this.vms.get(vmId)?.startedAt ?? Date.now()\n this.exitHandlers.set(vmId, handler)\n setTimeout(() => {\n void (async () => {\n const registered = this.exitHandlers.get(vmId)\n this.exitHandlers.delete(vmId)\n if (!registered) return\n\n const result: VmRunResult = {\n exitCode: 0,\n stdout: `mock job ${vmId} completed\\n`,\n stderr: '',\n truncated: false,\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n }\n await this.destroy(vmId)\n registered(result)\n })()\n }, MOCK_JOB_DURATION_MS)\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n return this.setRunning(vmId, true)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n await new Promise<void>((resolve) => vm.server.close(() => resolve()))\n await fs.rm(vm.workspaceDir, { recursive: true, force: true })\n this.vms.delete(vmId)\n logger.info({ vmId }, 'mock vm destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((vm) => vm.handle)\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.requireRunningVm(vmId)\n\n return new Promise((resolve, reject) => {\n const proxyReq = http.request(\n {\n host: '127.0.0.1',\n port: vm.port,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (proxyRes) => {\n const chunks: Buffer[] = []\n proxyRes.on('data', (chunk) => chunks.push(chunk))\n proxyRes.on('end', () => {\n resolve({\n statusCode: proxyRes.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(proxyRes.headers).map(([key, value]) => [\n key,\n Array.isArray(value) ? value.join(', ') : value ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n })\n })\n },\n )\n\n proxyReq.on('error', reject)\n if (request.body) proxyReq.write(request.body)\n proxyReq.end()\n })\n }\n\n async writeFiles(vmId: string, files: VmFileWrite[]): Promise<VmWriteFilesResult> {\n const vm = this.requireRunningVm(vmId)\n const written: Array<{ path: string; bytes: number }> = []\n\n for (const file of files) {\n const buffer = Buffer.from(file.content, file.encoding === 'base64' ? 'base64' : 'utf8')\n if (buffer.byteLength > MAX_FILE_BYTES) {\n throw new Error(\n `File too large (${buffer.byteLength} bytes, max ${MAX_FILE_BYTES}): ${file.path}`,\n )\n }\n const filePath = resolveWorkspacePath(vm.workspaceDir, file.path)\n await fs.mkdir(path.dirname(filePath), { recursive: true })\n await fs.writeFile(filePath, buffer)\n written.push({ path: path.relative(vm.workspaceDir, filePath), bytes: buffer.byteLength })\n }\n\n logger.info({ vmId, files: written.length }, 'mock vm files written')\n return { written }\n }\n\n async exec(vmId: string, request: VmExecRequest): Promise<VmExecResult> {\n const vm = this.requireRunningVm(vmId)\n const cwd = request.cwd ? resolveWorkspacePath(vm.workspaceDir, request.cwd) : vm.workspaceDir\n const timeoutMs = Math.min(request.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS, MAX_EXEC_TIMEOUT_MS)\n const startedAt = Date.now()\n\n return new Promise((resolve) => {\n execFile(\n '/bin/sh',\n ['-c', request.command],\n {\n cwd,\n timeout: timeoutMs,\n maxBuffer: MAX_OUTPUT_BYTES,\n env: { ...process.env, HOME: vm.workspaceDir },\n },\n (error, stdout, stderr) => {\n const failed = error as\n | (NodeJS.ErrnoException & { code?: number | string; killed?: boolean })\n | null\n const timedOut = Boolean(failed?.killed)\n const truncated = failed?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'\n resolve({\n exitCode: typeof failed?.code === 'number' ? failed.code : failed ? 1 : 0,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n durationMs: Date.now() - startedAt,\n truncated: Boolean(truncated),\n timedOut,\n })\n },\n )\n })\n }\n\n private requireRunningVm(vmId: string): ManagedVm {\n const vm = this.vms.get(vmId)\n if (!vm || !vm.handle.running) {\n throw new Error(`vm ${vmId} is not running`)\n }\n return vm\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n}\n", "import { spawn, type ChildProcess } from 'child_process'\nimport net from 'net'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport os from 'os'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmRunMode,\n VmRunResult,\n} from '@multiplayer-app/builder-types'\nimport { resolveStackImages } from '../images'\nimport type { Executor, VmHandle, VmSpec } from './types'\nimport { withTimeout } from './reattach-utils'\nimport { encodeEnvB64 } from './env-encoding'\n\nconst MAX_OUTPUT_BYTES = 1024 * 1024\n/** Printed by the guest init script (see scripts/setup-vm-images.sh) right before it powers off in job mode. */\nconst JOB_EXIT_SENTINEL = '__JOB_EXIT_CODE__:'\n\nexport interface QemuConfig {\n bin?: string\n /** Root of per-stack base images: <imagesDir>/<stack>/{vmlinuz,initramfs.img}. */\n imagesDir?: string\n /** Explicit single-image override; used for every stack when both are set. */\n kernelPath?: string\n initrdPath?: string\n vmDataPath?: string\n httpPortRangeStart?: number\n httpPortRangeEnd?: number\n vncBasePort?: number // base port for VNC displays (default 5900); display N \u2192 port vncBasePort+N\n serialBasePort?: number // base port for serial TCP (default 8000)\n accel?: string // 'hvf' (macOS), 'kvm' (Linux + /dev/kvm), 'tcg' (software, any host)\n cpu?: string // 'host' (hvf/kvm), 'max' (tcg aarch64), 'qemu64' (tcg x86_64)\n machine?: string // 'virt' (aarch64), 'q35' (x86_64)\n}\n\ninterface ManagedVm {\n handle: VmHandle\n // Absent after a reattach \u2014 the original ChildProcess object doesn't survive a worker\n // restart. Lifecycle control still works via QMP; destroy() falls back to killing `pid`.\n process?: ChildProcess\n pid?: number\n hostPort: number\n qmpSocketPath: string\n vncDisplay: number // QEMU display index (port = vncBasePort + vncDisplay)\n serialPort: number\n runMode: VmRunMode\n startedAt: number\n /** Job mode only: bounded capture of the serial console, scraped for JOB_EXIT_SENTINEL on exit. */\n serialBuffer?: { chunks: Buffer[]; bytes: number; socket: net.Socket }\n}\n\nexport class QemuExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n private readonly usedHttpPorts = new Set<number>()\n private readonly usedDisplays = new Set<number>() // VNC display indices\n private readonly usedSerialPorts = new Set<number>()\n private readonly bin: string\n private readonly vmDataPath: string\n private readonly httpPortStart: number\n private readonly httpPortEnd: number\n private readonly vncBasePort: number\n private readonly serialBasePort: number\n private readonly accel: string\n private readonly cpu: string\n private readonly machine: string\n\n constructor(private readonly config: QemuConfig) {\n this.bin = config.bin ?? 'qemu-system-aarch64'\n this.vmDataPath = config.vmDataPath ?? path.join(os.tmpdir(), 'qemu-vms')\n this.httpPortStart = config.httpPortRangeStart ?? 9000\n this.httpPortEnd = config.httpPortRangeEnd ?? 9099\n this.vncBasePort = config.vncBasePort ?? 5900\n this.serialBasePort = config.serialBasePort ?? 8000\n this.accel = config.accel ?? 'hvf'\n this.cpu = config.cpu ?? 'host'\n this.machine = config.machine ?? 'virt'\n }\n\n private allocateHttpPort(): number {\n for (let p = this.httpPortStart; p <= this.httpPortEnd; p++) {\n if (!this.usedHttpPorts.has(p)) {\n this.usedHttpPorts.add(p)\n return p\n }\n }\n throw new Error('no free HTTP ports in QEMU port range')\n }\n\n private allocateVncDisplay(): number {\n for (let d = 1; d <= 99; d++) {\n if (!this.usedDisplays.has(d)) {\n this.usedDisplays.add(d)\n return d\n }\n }\n throw new Error('no free VNC displays')\n }\n\n private allocateSerialPort(): number {\n for (let p = this.serialBasePort; p <= this.serialBasePort + 99; p++) {\n if (!this.usedSerialPorts.has(p)) {\n this.usedSerialPorts.add(p)\n return p\n }\n }\n throw new Error('no free serial ports')\n }\n\n /** Explicit kernel/initrd override wins; otherwise the stack's base image, falling back to generic. */\n private resolveImages(stack: string): { kernelPath: string; initrdPath: string } {\n if (this.config.kernelPath && this.config.initrdPath) {\n return { kernelPath: this.config.kernelPath, initrdPath: this.config.initrdPath }\n }\n const resolved = this.config.imagesDir\n ? resolveStackImages(this.config.imagesDir, stack) ??\n resolveStackImages(this.config.imagesDir, 'generic')\n : undefined\n if (!resolved) {\n throw new Error(\n `no base image for stack \"${stack}\" under ${this.config.imagesDir} \u2014 run \"worker-cli images pull\"`,\n )\n }\n return resolved\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const { kernelPath, initrdPath } = this.resolveImages(spec.stack)\n const envB64 = encodeEnvB64(spec.env)\n const hostPort = this.allocateHttpPort()\n const vncDisplay = this.allocateVncDisplay()\n const serialPort = this.allocateSerialPort()\n const vncPort = this.vncBasePort + vncDisplay\n\n const vmDir = path.join(this.vmDataPath, spec.vmId)\n await fs.mkdir(vmDir, { recursive: true })\n const qmpSocketPath = path.join(vmDir, 'qmp.sock')\n\n const args = [\n '-machine',\n this.machine,\n '-cpu',\n this.cpu,\n '-accel',\n this.accel,\n '-smp',\n String(spec.resources.vcpuCount),\n '-m',\n String(spec.resources.memMib),\n '-kernel',\n kernelPath,\n '-initrd',\n initrdPath,\n // console=tty0 sends output to VGA framebuffer (VNC); ttyAMA0 to serial.\n // APP_URL_B64: base64-encoded presigned artifact URL \u2014 kernel cmdline params are\n // space-separated, so the raw URL (query string, &) can't be passed directly.\n '-append',\n [\n `console=tty0 console=ttyAMA0 net.ifnames=0 init=/init VM_ID=${spec.vmId} STACK=${spec.stack}`,\n spec.sessionId ? `SESSION_ID=${spec.sessionId}` : '',\n spec.appUrl ? `APP_URL_B64=${Buffer.from(spec.appUrl).toString('base64')}` : '',\n spec.runMode === 'job' ? 'RUN_MODE=job' : '',\n envB64 ? `ENV_B64=${envB64}` : '',\n ]\n .filter(Boolean)\n .join(' '),\n // Networking\n '-netdev',\n `user,id=net0,hostfwd=tcp::${hostPort}-:8080`,\n '-device',\n 'virtio-net-pci,netdev=net0',\n // Display: virtio-gpu-pci works on both aarch64 and x86_64; virtio-vga is x86-only\n '-device',\n 'virtio-gpu-pci',\n '-display',\n 'none',\n '-vnc',\n `127.0.0.1:${vncDisplay}`,\n // Serial console via TCP (xterm.js connects here)\n '-serial',\n `tcp:127.0.0.1:${serialPort},server,nowait`,\n // Control\n '-no-reboot',\n '-qmp',\n `unix:${qmpSocketPath},server,nowait`,\n ]\n\n logger.info({ vmId: spec.vmId, bin: this.bin, args }, 'spawning qemu')\n const proc = spawn(this.bin, args, { stdio: ['ignore', 'pipe', 'pipe'] })\n proc.stdout?.on('data', (d: Buffer) => logger.info({ vmId: spec.vmId }, d.toString().trimEnd()))\n proc.stderr?.on('data', (d: Buffer) =>\n logger.error({ vmId: spec.vmId }, d.toString().trimEnd()),\n )\n const runMode = spec.runMode ?? 'service'\n const startedAt = Date.now()\n proc.on('exit', (code, signal) => {\n const log = code === 0 || code === null ? logger.info.bind(logger) : logger.error.bind(logger)\n log({ vmId: spec.vmId, code, signal }, 'qemu process exited')\n const vm = this.vms.get(spec.vmId)\n if (!vm) return\n\n this.usedHttpPorts.delete(vm.hostPort)\n this.usedDisplays.delete(vm.vncDisplay)\n this.usedSerialPorts.delete(vm.serialPort)\n\n if (vm.runMode === 'job') {\n // Keep the map entry (marked not-running) until onExit() claims the result \u2014 see\n // docker-executor's deliverJobResult comment for why route() needs get() to still work.\n vm.handle = { ...vm.handle, running: false }\n this.reportJobResult(spec.vmId, vm)\n } else {\n this.vms.delete(spec.vmId)\n }\n })\n\n const metadata = { hostPort, qmpSocketPath, vncDisplay, serialPort, pid: proc.pid }\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n vncPort,\n serialPort,\n metadata,\n }\n\n const vm: ManagedVm = {\n handle,\n process: proc,\n pid: proc.pid,\n hostPort,\n qmpSocketPath,\n vncDisplay,\n serialPort,\n runMode,\n startedAt,\n }\n this.vms.set(spec.vmId, vm)\n if (runMode === 'job') vm.serialBuffer = connectSerialBuffer(serialPort)\n\n await waitForQmp(qmpSocketPath)\n logger.info({ vmId: spec.vmId, hostPort, vncPort, serialPort, runMode }, 'qemu vm ready')\n return handle\n }\n\n /** Scrapes JOB_EXIT_SENTINEL out of the buffered serial console and reports the result. */\n private reportJobResult(vmId: string, vm: ManagedVm): void {\n vm.serialBuffer?.socket.destroy()\n const output = Buffer.concat(vm.serialBuffer?.chunks ?? []).toString('utf8')\n const sentinelIndex = output.lastIndexOf(JOB_EXIT_SENTINEL)\n const exitCode =\n sentinelIndex === -1\n ? 1\n : Number.parseInt(output.slice(sentinelIndex + JOB_EXIT_SENTINEL.length), 10) || 0\n const stdout = sentinelIndex === -1 ? output : output.slice(0, sentinelIndex)\n\n const result: VmRunResult = {\n exitCode,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: '',\n truncated: (vm.serialBuffer?.bytes ?? 0) > MAX_OUTPUT_BYTES,\n durationMs: Date.now() - vm.startedAt,\n finishedAt: new Date().toISOString(),\n }\n logger.info({ vmId, exitCode }, 'qemu job vm exited')\n this.deliverJobResult(vmId, result)\n }\n\n private deliverJobResult(vmId: string, result: VmRunResult): void {\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n await this.qmp(vmId, 'stop')\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n await this.qmp(vmId, 'cont')\n return this.setRunning(vmId, true)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n await this.qmp(vmId, 'stop')\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n await this.qmp(vmId, 'cont')\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n try {\n await this.qmp(vmId, 'quit')\n } catch {\n this.killVm(vm)\n }\n\n if (vm.process) {\n const proc = vm.process\n await new Promise<void>((resolve) => {\n if (proc.exitCode !== null) return resolve()\n proc.once('exit', resolve)\n setTimeout(() => {\n this.killVm(vm)\n resolve()\n }, 3_000)\n })\n } else {\n // Reattached VM \u2014 no live ChildProcess to wait on. QMP quit was already requested\n // above; give it a moment, then fall back to killing by pid.\n await new Promise((resolve) => setTimeout(resolve, 1_000))\n this.killVm(vm)\n }\n\n this.usedHttpPorts.delete(vm.hostPort)\n this.usedDisplays.delete(vm.vncDisplay)\n this.usedSerialPorts.delete(vm.serialPort)\n this.vms.delete(vmId)\n await fs.rm(path.join(this.vmDataPath, vmId), { recursive: true, force: true })\n logger.info({ vmId }, 'qemu vm destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n /**\n * Recover a QEMU VM after a worker restart: the process may well have survived (it's not\n * killed just because its Node parent exited), so probe its QMP socket \u2014 if it answers,\n * lifecycle control and HTTP proxying resume normally. There's no live ChildProcess to\n * reattach to, so destroy() falls back to killing the stored pid.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as\n | {\n hostPort?: number\n qmpSocketPath?: string\n vncDisplay?: number\n serialPort?: number\n pid?: number\n }\n | undefined\n if (\n !meta?.qmpSocketPath ||\n meta.hostPort === undefined ||\n meta.vncDisplay === undefined ||\n meta.serialPort === undefined\n ) {\n return undefined\n }\n\n try {\n await withTimeout(sendQmpCommand(meta.qmpSocketPath, 'query-status'), 5_000)\n } catch {\n return undefined\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running: record.state === 'running',\n vncPort: this.vncBasePort + meta.vncDisplay,\n serialPort: meta.serialPort,\n metadata: meta,\n }\n\n this.usedHttpPorts.add(meta.hostPort)\n this.usedDisplays.add(meta.vncDisplay)\n this.usedSerialPorts.add(meta.serialPort)\n this.vms.set(record.vmId, {\n handle,\n pid: meta.pid,\n hostPort: meta.hostPort,\n qmpSocketPath: meta.qmpSocketPath,\n vncDisplay: meta.vncDisplay,\n serialPort: meta.serialPort,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n\n // Note: a job VM that finished (or is still running) while this worker was offline has\n // no recoverable path here \u2014 the serial buffer only ever lived in the dead worker's\n // memory, and if the guest already powered off the QMP probe above would have failed and\n // returned undefined before reaching this point (reported as \"resource no longer exists\"\n // by MultiEngineExecutor.reattachAll). A still-running job just resumes being watched\n // normally below via the QMP-confirmed process.\n\n logger.info({ vmId: record.vmId }, 'qemu vm reattached')\n return handle\n }\n\n private killVm(vm: ManagedVm): void {\n if (vm.process) {\n vm.process.kill('SIGKILL')\n return\n }\n if (vm.pid) {\n try {\n process.kill(vm.pid, 'SIGKILL')\n } catch {\n /* already gone */\n }\n }\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.vms.get(vmId)\n if (!vm?.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n const { default: http } = await import('http')\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: '127.0.0.1',\n port: vm.hostPort,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n\n private async qmp(vmId: string, execute: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n await sendQmpCommand(vm.qmpSocketPath, execute)\n }\n}\n\n/**\n * Opens our own client connection to the serial TCP port (QEMU holds it open as a server,\n * `nowait`) purely to capture a job's output \u2014 independent of whether a browser is also\n * watching live via SerialRelay/getSerialSource.\n */\nfunction connectSerialBuffer(port: number): {\n chunks: Buffer[]\n bytes: number\n socket: net.Socket\n} {\n const buffer = {\n chunks: [] as Buffer[],\n bytes: 0,\n socket: net.connect({ host: '127.0.0.1', port }),\n }\n buffer.socket.on('data', (chunk: Buffer) => {\n if (buffer.bytes >= MAX_OUTPUT_BYTES) return\n buffer.chunks.push(chunk)\n buffer.bytes += chunk.byteLength\n })\n buffer.socket.on('error', () => {\n /* best-effort capture \u2014 a dropped connection just means a shorter log, not a failure */\n })\n return buffer\n}\n\nfunction waitForQmp(socketPath: string, timeoutMs = 30_000): Promise<void> {\n return new Promise((resolve, reject) => {\n const deadline = Date.now() + timeoutMs\n const attempt = () => {\n if (Date.now() > deadline)\n return reject(new Error(`timed out waiting for QMP socket at ${socketPath}`))\n const sock = net.createConnection(socketPath)\n sock.once('connect', () => {\n sock.destroy()\n resolve()\n })\n sock.once('error', () => setTimeout(attempt, 500))\n }\n attempt()\n })\n}\n\nasync function sendQmpCommand(socketPath: string, execute: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const sock = net.createConnection(socketPath)\n let buf = ''\n let ready = false\n const send = (obj: object) => sock.write(JSON.stringify(obj) + '\\r\\n')\n\n sock.on('data', (data: Buffer) => {\n buf += data.toString()\n let idx: number\n while ((idx = buf.indexOf('\\n')) !== -1) {\n const line = buf.slice(0, idx).trim()\n buf = buf.slice(idx + 1)\n if (!line) continue\n let msg: Record<string, unknown>\n try {\n msg = JSON.parse(line)\n } catch {\n continue\n }\n\n if (msg['QMP']) {\n send({ execute: 'qmp_capabilities' })\n } else if (!ready && 'return' in msg) {\n ready = true\n send({ execute })\n } else if (ready && 'return' in msg) {\n sock.destroy()\n resolve()\n } else if (msg['error']) {\n sock.destroy()\n reject(new Error(`QMP error for \"${execute}\": ${JSON.stringify(msg['error'])}`))\n }\n }\n })\n\n sock.on('error', (e) => {\n if (execute === 'quit') resolve()\n else reject(e)\n })\n sock.on('close', () => resolve())\n })\n}\n", "/** Bounds a reattach probe so one unresponsive socket can't hang the whole `reattachAll` batch. */\nexport function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms)),\n ])\n}\n", "/**\n * Encodes a custom env var map into the single kernel-cmdline param QEMU/Firecracker guests\n * decode at boot (see the `ENV_B64=*` case in scripts/setup-vm-images.sh's init script).\n * The cmdline is space-delimited with no quoting, so raw `KEY=value with spaces` pairs can't\n * go directly on it (same reason APP_URL is base64-encoded as APP_URL_B64) \u2014 instead the\n * whole map is newline-joined and base64'd into one opaque param.\n */\nexport function encodeEnvB64(env: Record<string, string> | undefined): string | undefined {\n if (!env || Object.keys(env).length === 0) return undefined\n const lines = Object.entries(env)\n .map(([key, value]) => `${key}=${value}`)\n .join('\\n')\n return Buffer.from(lines).toString('base64')\n}\n", "import { spawn, type ChildProcess } from 'child_process'\nimport { exec } from 'child_process'\nimport { promisify } from 'util'\nimport http from 'http'\nimport net from 'net'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport os from 'os'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmRunMode,\n VmRunResult,\n} from '@multiplayer-app/builder-types'\nimport { resolveStackImages } from '../images'\nimport type { Executor, SerialSource, VmHandle, VmSpec } from './types'\nimport { withTimeout } from './reattach-utils'\nimport { encodeEnvB64 } from './env-encoding'\n\nconst execAsync = promisify(exec)\n\nconst MAX_OUTPUT_BYTES = 1024 * 1024\n/** Printed by the guest init script (see scripts/setup-vm-images.sh) right before it powers off in job mode. */\nconst JOB_EXIT_SENTINEL = '__JOB_EXIT_CODE__:'\n\nexport interface FirecrackerConfig {\n bin?: string // default: 'firecracker'\n /** Root of per-stack base images: <imagesDir>/<stack>/{vmlinuz,initramfs.img}. */\n imagesDir?: string\n /** Explicit single-image override (vmlinux/bzImage + cpio.gz); used for every stack when both are set. */\n kernelPath?: string\n initrdPath?: string\n vmDataPath?: string // default: /tmp/firecracker-vms\n}\n\ninterface ManagedVm {\n handle: VmHandle\n // Absent after a reattach \u2014 the original ChildProcess object doesn't survive a worker\n // restart. Lifecycle control and HTTP proxying still work via the API socket; the serial\n // console (piped over this process's inherited stdio) does not \u2014 see getSerialSource().\n process?: ChildProcess\n pid?: number\n apiSocketPath: string\n tapName: string\n subnet: number\n guestIp: string\n runMode: VmRunMode\n startedAt: number\n /** Job mode only: bounded capture of the guest's serial stdout, scraped for JOB_EXIT_SENTINEL on exit. */\n serialBuffer?: { chunks: Buffer[]; bytes: number }\n}\n\nexport class FirecrackerExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly usedSubnets = new Set<number>()\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n private tapCounter = 0\n private readonly bin: string\n private readonly vmDataPath: string\n private networkReady = false\n\n constructor(private readonly config: FirecrackerConfig) {\n this.bin = config.bin ?? 'firecracker'\n this.vmDataPath = config.vmDataPath ?? path.join(os.tmpdir(), 'firecracker-vms')\n }\n\n private allocateSubnet(): number {\n for (let s = 1; s <= 254; s++) {\n if (!this.usedSubnets.has(s)) {\n this.usedSubnets.add(s)\n return s\n }\n }\n throw new Error('no free TAP subnets (max 254 concurrent VMs)')\n }\n\n // Called once before the first VM; sets up host-level IP forwarding + masquerade.\n private async ensureNetworking(): Promise<void> {\n if (this.networkReady) return\n await execAsync('sysctl -w net.ipv4.ip_forward=1')\n const alreadySet = await execAsync(\n 'iptables -t nat -C POSTROUTING -s 172.16.0.0/12 ! -d 172.16.0.0/12 -j MASQUERADE',\n ).catch(() => null)\n if (!alreadySet) {\n await execAsync(\n 'iptables -t nat -A POSTROUTING -s 172.16.0.0/12 ! -d 172.16.0.0/12 -j MASQUERADE',\n )\n }\n this.networkReady = true\n }\n\n /** Explicit kernel/initrd override wins; otherwise the stack's base image, falling back to generic. */\n private resolveImages(stack: string): { kernelPath: string; initrdPath: string } {\n if (this.config.kernelPath && this.config.initrdPath) {\n return { kernelPath: this.config.kernelPath, initrdPath: this.config.initrdPath }\n }\n const resolved = this.config.imagesDir\n ? resolveStackImages(this.config.imagesDir, stack) ??\n resolveStackImages(this.config.imagesDir, 'generic')\n : undefined\n if (!resolved) {\n throw new Error(\n `no base image for stack \"${stack}\" under ${this.config.imagesDir} \u2014 run \"worker-cli images pull\"`,\n )\n }\n return resolved\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const { kernelPath, initrdPath } = this.resolveImages(spec.stack)\n await this.ensureNetworking()\n\n const subnet = this.allocateSubnet()\n const tapName = `fctap${++this.tapCounter}`\n const hostIp = `172.16.${subnet}.1`\n const guestIp = `172.16.${subnet}.2`\n\n const vmDir = path.join(this.vmDataPath, spec.vmId)\n await fs.mkdir(vmDir, { recursive: true })\n const apiSocketPath = path.join(vmDir, 'api.sock')\n await fs.rm(apiSocketPath, { force: true })\n\n // TAP device wired to this VM's Firecracker process\n await execAsync(`ip tuntap add dev ${tapName} mode tap`)\n await execAsync(`ip addr add ${hostIp}/30 dev ${tapName}`)\n await execAsync(`ip link set ${tapName} up`)\n\n const runMode = spec.runMode ?? 'service'\n const envB64 = encodeEnvB64(spec.env)\n const startedAt = Date.now()\n const serialBuffer = runMode === 'job' ? { chunks: [] as Buffer[], bytes: 0 } : undefined\n\n // stdin is piped so terminal input can be written to the guest's ttyS0 console\n const proc = spawn(this.bin, ['--api-sock', apiSocketPath], {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n proc.stdout?.on('data', (d: Buffer) => {\n logger.debug({ vmId: spec.vmId }, d.toString().trimEnd())\n if (serialBuffer && serialBuffer.bytes < MAX_OUTPUT_BYTES) {\n serialBuffer.chunks.push(d)\n serialBuffer.bytes += d.byteLength\n }\n })\n proc.stderr?.on('data', (d: Buffer) =>\n logger.debug({ vmId: spec.vmId }, d.toString().trimEnd()),\n )\n proc.on('exit', (code, signal) => {\n logger.info({ vmId: spec.vmId, code, signal }, 'firecracker process exited')\n const vm = this.vms.get(spec.vmId)\n if (vm) {\n this.usedSubnets.delete(vm.subnet)\n if (vm.runMode === 'job') {\n // Keep the map entry (marked not-running) until onExit() claims the result \u2014 see\n // docker-executor's deliverJobResult comment for why route() needs get() to work.\n vm.handle = { ...vm.handle, running: false }\n this.reportJobResult(spec.vmId, vm)\n } else {\n this.vms.delete(spec.vmId)\n }\n }\n execAsync(`ip link del ${tapName}`).catch(() => {})\n })\n\n await waitForSocket(apiSocketPath)\n\n const macHex = (n: number) => n.toString(16).padStart(2, '0')\n await fcRequest(apiSocketPath, 'PUT', '/machine-config', {\n vcpu_count: spec.resources.vcpuCount,\n mem_size_mib: spec.resources.memMib,\n })\n await fcRequest(apiSocketPath, 'PUT', '/boot-source', {\n kernel_image_path: kernelPath,\n initrd_path: initrdPath,\n boot_args: [\n 'console=ttyS0',\n 'reboot=k',\n 'panic=1',\n 'pci=off',\n 'net.ifnames=0',\n 'init=/init',\n `VM_ID=${spec.vmId}`,\n ...(spec.sessionId ? [`SESSION_ID=${spec.sessionId}`] : []),\n `STACK=${spec.stack}`,\n // base64: kernel cmdline is space-separated, raw presigned URLs are not safe\n ...(spec.appUrl ? [`APP_URL_B64=${Buffer.from(spec.appUrl).toString('base64')}`] : []),\n `GUEST_IP=${guestIp}`,\n `HOST_IP=${hostIp}`,\n ...(runMode === 'job' ? ['RUN_MODE=job'] : []),\n ...(envB64 ? [`ENV_B64=${envB64}`] : []),\n ].join(' '),\n })\n await fcRequest(apiSocketPath, 'PUT', '/network-interfaces/eth0', {\n iface_id: 'eth0',\n // AA = locally-administered unicast; encode subnet as last two bytes\n guest_mac: `AA:FC:00:00:${macHex(subnet >> 8)}:${macHex(subnet & 0xff)}`,\n host_dev_name: tapName,\n })\n await fcRequest(apiSocketPath, 'PUT', '/actions', { action_type: 'InstanceStart' })\n\n // A job's entrypoint may finish before it ever answers HTTP \u2014 the readiness gate below\n // only applies to persistent services.\n if (runMode !== 'job') await waitForHttp(guestIp, 8080)\n\n const metadata = { apiSocketPath, tapName, subnet, guestIp, pid: proc.pid }\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n metadata,\n }\n this.vms.set(spec.vmId, {\n handle,\n process: proc,\n pid: proc.pid,\n apiSocketPath,\n tapName,\n subnet,\n guestIp,\n runMode,\n startedAt,\n serialBuffer,\n })\n logger.info({ vmId: spec.vmId, guestIp, tapName, runMode }, 'firecracker vm ready')\n return handle\n }\n\n /** Scrapes JOB_EXIT_SENTINEL out of the buffered serial stdout and reports the result. */\n private reportJobResult(vmId: string, vm: ManagedVm): void {\n const output = Buffer.concat(vm.serialBuffer?.chunks ?? []).toString('utf8')\n const sentinelIndex = output.lastIndexOf(JOB_EXIT_SENTINEL)\n const exitCode =\n sentinelIndex === -1\n ? 1\n : Number.parseInt(output.slice(sentinelIndex + JOB_EXIT_SENTINEL.length), 10) || 0\n const stdout = sentinelIndex === -1 ? output : output.slice(0, sentinelIndex)\n\n const result: VmRunResult = {\n exitCode,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: '',\n truncated: (vm.serialBuffer?.bytes ?? 0) > MAX_OUTPUT_BYTES,\n durationMs: Date.now() - vm.startedAt,\n finishedAt: new Date().toISOString(),\n }\n logger.info({ vmId, exitCode }, 'firecracker job vm exited')\n this.deliverJobResult(vmId, result)\n }\n\n private deliverJobResult(vmId: string, result: VmRunResult): void {\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n await this.patchVmState(vmId, 'Paused')\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n await this.patchVmState(vmId, 'Resumed')\n return this.setRunning(vmId, true)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n await this.patchVmState(vmId, 'Paused')\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n await this.patchVmState(vmId, 'Resumed')\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n if (vm.process) {\n const proc = vm.process\n proc.kill('SIGKILL')\n await new Promise<void>((resolve) => {\n if (proc.exitCode !== null) return resolve()\n proc.once('exit', resolve)\n setTimeout(() => {\n proc.kill('SIGKILL')\n resolve()\n }, 3_000)\n })\n } else if (vm.pid) {\n // Reattached VM \u2014 no live ChildProcess to wait on; kill by the stored pid.\n try {\n process.kill(vm.pid, 'SIGKILL')\n } catch {\n /* already gone */\n }\n }\n\n this.usedSubnets.delete(vm.subnet)\n this.vms.delete(vmId)\n await execAsync(`ip link del ${vm.tapName}`).catch(() => {})\n await fs.rm(path.join(this.vmDataPath, vmId), { recursive: true, force: true })\n logger.info({ vmId }, 'firecracker vm destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n getSerialSource(vmId: string): SerialSource | undefined {\n const vm = this.vms.get(vmId)\n // Serial is piped over the child's inherited stdio \u2014 a reattached VM has no live\n // ChildProcess to read that from, so its serial console is unavailable until it's\n // recreated. Lifecycle control and HTTP proxying are unaffected.\n if (!vm?.process) return undefined\n return { type: 'pipe', process: vm.process }\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n /**\n * Recover a Firecracker VM after a worker restart: the process may well have survived, so\n * probe its API socket \u2014 if it answers, lifecycle control and HTTP proxying resume\n * normally. There's no live ChildProcess to reattach to, so destroy() falls back to\n * killing the stored pid, and the serial console is unavailable (see getSerialSource).\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as\n | {\n apiSocketPath?: string\n tapName?: string\n subnet?: number\n guestIp?: string\n pid?: number\n }\n | undefined\n if (!meta?.apiSocketPath || !meta.tapName || meta.subnet === undefined || !meta.guestIp) {\n return undefined\n }\n\n try {\n await withTimeout(fcRequest(meta.apiSocketPath, 'GET', '/', {}), 5_000)\n } catch {\n return undefined\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running: record.state === 'running',\n metadata: meta,\n }\n\n this.usedSubnets.add(meta.subnet)\n // Keep future tap names from colliding with this reattached one.\n const tapNumber = Number(meta.tapName.replace(/^fctap/, ''))\n if (Number.isFinite(tapNumber)) this.tapCounter = Math.max(this.tapCounter, tapNumber)\n\n this.vms.set(record.vmId, {\n handle,\n pid: meta.pid,\n apiSocketPath: meta.apiSocketPath,\n tapName: meta.tapName,\n subnet: meta.subnet,\n guestIp: meta.guestIp,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n\n // Note: same limitation as QemuExecutor.reattach \u2014 a job VM's serial buffer only ever\n // lived in the dead worker's memory, and a still-running one has no ChildProcess here to\n // detect its eventual exit (getSerialSource already documents the equivalent gap for the\n // live console). Not solved in v1.\n\n logger.info(\n { vmId: record.vmId, guestIp: meta.guestIp, tapName: meta.tapName },\n 'firecracker vm reattached',\n )\n return handle\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.vms.get(vmId)\n if (!vm?.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: vm.guestIp,\n port: 8080,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n private async patchVmState(vmId: string, state: 'Paused' | 'Resumed'): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n await fcRequest(vm.apiSocketPath, 'PATCH', '/vm', { state })\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n}\n\n// Send a request to the Firecracker REST API via Unix socket.\nfunction fcRequest(\n socketPath: string,\n method: string,\n urlPath: string,\n body: object,\n): Promise<object> {\n return new Promise((resolve, reject) => {\n const payload = JSON.stringify(body)\n const req = http.request(\n {\n socketPath,\n method,\n path: urlPath,\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(payload),\n Accept: 'application/json',\n },\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () => {\n const text = Buffer.concat(chunks).toString()\n if (res.statusCode && res.statusCode >= 400) {\n reject(new Error(`Firecracker ${method} ${urlPath} \u2192 ${res.statusCode}: ${text}`))\n } else {\n try {\n resolve(JSON.parse(text))\n } catch {\n resolve({})\n }\n }\n })\n },\n )\n req.on('error', reject)\n req.write(payload)\n req.end()\n })\n}\n\nfunction waitForSocket(socketPath: string, timeoutMs = 10_000): Promise<void> {\n return new Promise((resolve, reject) => {\n const deadline = Date.now() + timeoutMs\n const attempt = () => {\n if (Date.now() > deadline)\n return reject(new Error(`timed out waiting for Firecracker socket ${socketPath}`))\n const sock = net.createConnection(socketPath)\n sock.once('connect', () => {\n sock.destroy()\n resolve()\n })\n sock.once('error', () => setTimeout(attempt, 100))\n }\n attempt()\n })\n}\n\nfunction waitForHttp(host: string, port: number, timeoutMs = 60_000): Promise<void> {\n return new Promise((resolve, reject) => {\n const deadline = Date.now() + timeoutMs\n const attempt = () => {\n if (Date.now() > deadline)\n return reject(new Error(`timed out waiting for HTTP at ${host}:${port}`))\n const req = http.get(`http://${host}:${port}/health`, (res) => {\n if (res.statusCode && res.statusCode < 500) return resolve()\n res.resume()\n setTimeout(attempt, 1_000)\n })\n req.on('error', () => setTimeout(attempt, 1_000))\n req.setTimeout(2_000, () => {\n req.destroy()\n setTimeout(attempt, 1_000)\n })\n }\n attempt()\n })\n}\n", "import { execFile, spawn } from 'child_process'\nimport { promisify } from 'util'\nimport http from 'http'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmExecRequest,\n VmExecResult,\n VmFileWrite,\n VmRecord,\n VmRunMode,\n VmRunResult,\n VmWriteFilesResult,\n} from '@multiplayer-app/builder-types'\nimport type { DockerWorkerConfig } from '../config'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nconst DEFAULT_EXEC_TIMEOUT_MS = 60_000\nconst MAX_EXEC_TIMEOUT_MS = 300_000\nconst MAX_OUTPUT_BYTES = 1024 * 1024\nconst MAX_FILE_BYTES = 5 * 1024 * 1024\nconst WORKSPACE_DIR = '/workspace'\n\nconst execFileAsync = promisify(execFile)\n\ninterface ManagedVm {\n handle: VmHandle\n containerId: string\n containerName: string\n hostPort: number\n runMode: VmRunMode\n startedAt: number\n}\n\n/** Reject \"../\" and absolute paths, same rule MockExecutor applies to its own workspace. */\nfunction assertSafeWorkspacePath(relativePath: string): string {\n const normalized = relativePath.replace(/^([/\\\\])+/, '')\n if (normalized.split(/[/\\\\]/).includes('..')) {\n throw new Error(`Path escapes the VM workspace: ${relativePath}`)\n }\n return normalized\n}\n\n/**\n * Runs VMs as local Docker containers (one container per VM), via the `docker` CLI \u2014\n * same shell-out style QemuExecutor uses for qemu-system-*. No kernel/HVF/KVM needed,\n * so it's the lowest-friction local engine: just Docker Desktop/OrbStack.\n *\n * Unlike the other local engines, the container's process is directly reachable from\n * the host, so exec/writeFiles are real (`docker exec` / `docker cp`) rather than\n * MockExecutor-only stand-ins. pause/resume map to `docker pause`/`unpause` (a real\n * cgroup freeze); stop/restore map to `docker stop`/`start`, so every VmAction does\n * something meaningful \u2014 unlike QEMU (stop/restore alias pause/resume) or Fargate\n * (only stop works).\n */\nexport class DockerExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly usedPorts = new Set<number>()\n private readonly bin: string\n /** Job VMs that exited before onExit() was called to claim the result (create() \u2192 onExit() isn't atomic). */\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n\n constructor(private readonly config: DockerWorkerConfig) {\n this.bin = config.bin\n }\n\n private allocatePort(): number {\n for (let p = this.config.portRangeStart; p <= this.config.portRangeEnd; p++) {\n if (!this.usedPorts.has(p)) {\n this.usedPorts.add(p)\n return p\n }\n }\n throw new Error('no free ports in docker port range')\n }\n\n private async resolveImage(stack: string): Promise<string> {\n const explicit = this.config.stackImages[stack]\n if (explicit) return explicit\n\n const { imagePrefix, imageTag } = this.config\n const stackImage = `${imagePrefix}-${stack}:${imageTag}`\n if (await this.imageExists(stackImage)) return stackImage\n\n const genericImage = `${imagePrefix}-generic:${imageTag}`\n if (await this.imageExists(genericImage)) return genericImage\n\n throw new Error(\n `no local docker image for stack \"${stack}\" (${stackImage}) \u2014 run scripts/setup-docker-images.sh`,\n )\n }\n\n private async imageExists(image: string): Promise<boolean> {\n try {\n await execFileAsync(this.bin, ['image', 'inspect', image])\n return true\n } catch {\n return false\n }\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const image = await this.resolveImage(spec.stack)\n const hostPort = this.allocatePort()\n const containerName = `multiplayer-vm-${spec.vmId}`\n\n const args = [\n 'run',\n '-d',\n '--name',\n containerName,\n '-p',\n `127.0.0.1:${hostPort}:${this.config.guestPort}`,\n '--memory',\n `${spec.resources.memMib}m`,\n '--cpus',\n String(spec.resources.vcpuCount),\n '-e',\n `VM_ID=${spec.vmId}`,\n '-e',\n `STACK=${spec.stack}`,\n ...(spec.sessionId ? ['-e', `SESSION_ID=${spec.sessionId}`] : []),\n ...(spec.appUrl ? ['-e', `APP_URL=${spec.appUrl}`] : []),\n ...Object.entries(spec.env ?? {}).flatMap(([key, value]) => ['-e', `${key}=${value}`]),\n ...(this.config.network ? ['--network', this.config.network] : []),\n image,\n ]\n\n logger.info({ vmId: spec.vmId, bin: this.bin, args }, 'starting docker container')\n let containerId: string\n try {\n const { stdout } = await execFileAsync(this.bin, args)\n containerId = stdout.trim()\n } catch (error) {\n this.usedPorts.delete(hostPort)\n throw error\n }\n\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n metadata: { containerId, containerName, hostPort },\n }\n const runMode = spec.runMode ?? 'service'\n this.vms.set(spec.vmId, {\n handle,\n containerId,\n containerName,\n hostPort,\n runMode,\n startedAt: Date.now(),\n })\n this.watchExit(spec.vmId, containerId)\n\n // A job's entrypoint may run to completion before the agent ever comes up (e.g. it never\n // listens on a port) \u2014 waitForAgent would hang forever, so job VMs skip that readiness gate.\n if (runMode !== 'job') await this.waitForAgent(hostPort)\n logger.info({ vmId: spec.vmId, containerId, hostPort, runMode }, 'docker vm ready')\n return handle\n }\n\n /**\n * For 'service' VMs: frees the allocated port once the container exits on its own (crash,\n * OOM kill, `docker stop` from outside us) \u2014 same as before.\n * For 'job' VMs: captures the exit code + logs, tears the container down, and reports the\n * result to whoever calls onExit() (immediately if they already have, otherwise once they do).\n */\n private watchExit(vmId: string, containerId: string): void {\n execFileAsync(this.bin, ['wait', containerId])\n .catch(() => ({ stdout: '' }))\n .then(async ({ stdout }) => {\n const vm = this.vms.get(vmId)\n if (!vm || vm.containerId !== containerId) return\n\n if (vm.runMode !== 'job') {\n vm.handle = { ...vm.handle, running: false }\n return\n }\n\n const exitCode = Number.parseInt(stdout.trim(), 10) || 0\n const logs = await this.captureLogs(containerId)\n await execFileAsync(this.bin, ['rm', '-f', containerId]).catch((error: Error) =>\n logger.warn({ vmId, err: error }, 'docker rm after job exit failed'),\n )\n this.usedPorts.delete(vm.hostPort)\n // Resources are already freed above, but the map entry stays (marked not-running)\n // until onExit() claims the result \u2014 MultiEngineExecutor.route() needs get(vmId) to\n // keep finding it in the window between exit and onExit() being called (e.g. right\n // after a reattach discovers the job already finished).\n vm.handle = { ...vm.handle, running: false }\n\n const result: VmRunResult = {\n exitCode,\n ...logs,\n durationMs: Date.now() - vm.startedAt,\n finishedAt: new Date().toISOString(),\n }\n logger.info({ vmId, exitCode }, 'docker job vm exited')\n this.deliverJobResult(vmId, result)\n })\n }\n\n private deliverJobResult(vmId: string, result: VmRunResult): void {\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n /** `docker logs` mirrors the container's stdout/stderr onto its own, so the CLI's streams stay separate. */\n private async captureLogs(\n containerId: string,\n ): Promise<{ stdout: string; stderr: string; truncated: boolean }> {\n try {\n const { stdout, stderr } = await execFileAsync(this.bin, ['logs', containerId], {\n maxBuffer: MAX_OUTPUT_BYTES,\n })\n return {\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n truncated: stdout.length > MAX_OUTPUT_BYTES || stderr.length > MAX_OUTPUT_BYTES,\n }\n } catch (error) {\n const failed = error as NodeJS.ErrnoException & { stdout?: string; stderr?: string }\n return {\n stdout: (failed.stdout ?? '').slice(0, MAX_OUTPUT_BYTES),\n stderr: (failed.stderr ?? '').slice(0, MAX_OUTPUT_BYTES),\n truncated: true,\n }\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['pause', vm.containerId])\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['unpause', vm.containerId])\n return this.setRunning(vmId, true)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['stop', vm.containerId])\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['start', vm.containerId])\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n await execFileAsync(this.bin, ['rm', '-f', vm.containerId]).catch((error: Error) =>\n logger.warn({ vmId, err: error }, 'docker rm on destroy failed'),\n )\n this.usedPorts.delete(vm.hostPort)\n this.vms.delete(vmId)\n logger.info({ vmId }, 'docker vm destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n /**\n * Recover a container after a worker restart: it's an independent process the\n * Docker daemon owns, so just re-inspect it by ID and rebuild the local handle.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as\n | { containerId?: string; containerName?: string; hostPort?: number }\n | undefined\n if (!meta?.containerId || meta.hostPort === undefined) return undefined\n\n let running: boolean\n try {\n const { stdout } = await execFileAsync(this.bin, [\n 'inspect',\n '-f',\n '{{.State.Running}}',\n meta.containerId,\n ])\n running = stdout.trim() === 'true'\n } catch {\n return undefined\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running,\n metadata: meta,\n }\n this.usedPorts.add(meta.hostPort)\n this.vms.set(record.vmId, {\n handle,\n containerId: meta.containerId,\n containerName: meta.containerName ?? `multiplayer-vm-${record.vmId}`,\n hostPort: meta.hostPort,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n\n if (running) {\n this.watchExit(record.vmId, meta.containerId)\n } else if (record.runMode === 'job') {\n // The job already finished while this worker was offline (or restarting) \u2014 capture\n // whatever's left of it now instead of waiting on watchExit for a container that's\n // already dead, since `docker wait` never resolves for a container in a terminal state.\n void this.finishExitedJob(record.vmId, meta.containerId)\n }\n\n logger.info({ vmId: record.vmId, containerId: meta.containerId }, 'docker vm reattached')\n return handle\n }\n\n /** Same capture-and-report sequence as watchExit's job branch, for a container found already stopped. */\n private async finishExitedJob(vmId: string, containerId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n let exitCode = 0\n try {\n const { stdout } = await execFileAsync(this.bin, [\n 'inspect',\n '-f',\n '{{.State.ExitCode}}',\n containerId,\n ])\n exitCode = Number.parseInt(stdout.trim(), 10) || 0\n } catch {\n // container gone entirely \u2014 best effort, report a generic failure below\n }\n\n const logs = await this.captureLogs(containerId)\n await execFileAsync(this.bin, ['rm', '-f', containerId]).catch(() => {})\n this.usedPorts.delete(vm.hostPort)\n vm.handle = { ...vm.handle, running: false }\n\n const result: VmRunResult = {\n exitCode,\n ...logs,\n durationMs: Date.now() - vm.startedAt,\n finishedAt: new Date().toISOString(),\n }\n this.deliverJobResult(vmId, result)\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.mustGet(vmId)\n if (!vm.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: '127.0.0.1',\n port: vm.hostPort,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n async exec(vmId: string, request: VmExecRequest): Promise<VmExecResult> {\n const vm = this.mustGet(vmId)\n const cwd = request.cwd\n ? `${WORKSPACE_DIR}/${assertSafeWorkspacePath(request.cwd)}`\n : WORKSPACE_DIR\n const timeoutMs = Math.min(request.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS, MAX_EXEC_TIMEOUT_MS)\n const startedAt = Date.now()\n\n return new Promise((resolve) => {\n execFile(\n this.bin,\n ['exec', '-w', cwd, vm.containerId, '/bin/sh', '-c', request.command],\n { timeout: timeoutMs, maxBuffer: MAX_OUTPUT_BYTES },\n (error, stdout, stderr) => {\n const failed = error as\n | (NodeJS.ErrnoException & { code?: number | string; killed?: boolean })\n | null\n const timedOut = Boolean(failed?.killed)\n const truncated = failed?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'\n resolve({\n exitCode: typeof failed?.code === 'number' ? failed.code : failed ? 1 : 0,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n durationMs: Date.now() - startedAt,\n truncated: Boolean(truncated),\n timedOut,\n })\n },\n )\n })\n }\n\n async writeFiles(vmId: string, files: VmFileWrite[]): Promise<VmWriteFilesResult> {\n const vm = this.mustGet(vmId)\n const written: Array<{ path: string; bytes: number }> = []\n\n for (const file of files) {\n const relativePath = assertSafeWorkspacePath(file.path)\n const buffer = Buffer.from(file.content, file.encoding === 'base64' ? 'base64' : 'utf8')\n if (buffer.byteLength > MAX_FILE_BYTES) {\n throw new Error(\n `File too large (${buffer.byteLength} bytes, max ${MAX_FILE_BYTES}): ${file.path}`,\n )\n }\n\n const dir = relativePath.includes('/')\n ? relativePath.slice(0, relativePath.lastIndexOf('/'))\n : ''\n if (dir) {\n await execFileAsync(this.bin, [\n 'exec',\n vm.containerId,\n 'mkdir',\n '-p',\n `${WORKSPACE_DIR}/${dir}`,\n ])\n }\n await this.copyIntoContainer(vm.containerId, `${WORKSPACE_DIR}/${relativePath}`, buffer)\n written.push({ path: relativePath, bytes: buffer.byteLength })\n }\n\n logger.info({ vmId, files: written.length }, 'docker vm files written')\n return { written }\n }\n\n /** `docker cp` needs a tar stream on stdin; build the smallest valid ustar archive for one file. */\n private copyIntoContainer(containerId: string, destPath: string, content: Buffer): Promise<void> {\n const entryName = destPath.replace(/^\\//, '')\n const tarStream = buildSingleFileTar(entryName, content)\n\n return new Promise((resolve, reject) => {\n const proc = spawn(this.bin, ['cp', '-', `${containerId}:/`], {\n stdio: ['pipe', 'ignore', 'pipe'],\n })\n let stderr = ''\n proc.stderr?.on('data', (d: Buffer) => {\n stderr += d.toString()\n })\n proc.on('error', reject)\n proc.on('exit', (code) =>\n code === 0 ? resolve() : reject(new Error(`docker cp exited ${code}: ${stderr}`)),\n )\n proc.stdin.end(tarStream)\n })\n }\n\n private mustGet(vmId: string): ManagedVm {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n return vm\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.mustGet(vmId)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n\n private async waitForAgent(port: number, timeoutMs = 30_000): Promise<void> {\n const deadline = Date.now() + timeoutMs\n for (;;) {\n const ok = await new Promise<boolean>((resolve) => {\n const req = http.get({ host: '127.0.0.1', port, path: '/', timeout: 2_000 }, (res) => {\n res.resume()\n resolve(true)\n })\n req.on('error', () => resolve(false))\n req.on('timeout', () => {\n req.destroy()\n resolve(false)\n })\n })\n if (ok) return\n if (Date.now() > deadline)\n throw new Error(`timed out waiting for docker vm agent on port ${port}`)\n await new Promise((resolve) => setTimeout(resolve, 500))\n }\n }\n}\n\n/** POSIX ustar archive containing exactly one regular file \u2014 enough for `docker cp -`. */\nfunction buildSingleFileTar(name: string, content: Buffer): Buffer {\n const header = Buffer.alloc(512)\n header.write(name, 0, 'utf8')\n header.write('0000644\\0', 100, 'utf8') // mode\n header.write('0000000\\0', 108, 'utf8') // uid\n header.write('0000000\\0', 116, 'utf8') // gid\n header.write(content.byteLength.toString(8).padStart(11, '0') + '\\0', 124, 'utf8') // size (octal)\n header.write(\n Math.floor(Date.now() / 1000)\n .toString(8)\n .padStart(11, '0') + '\\0',\n 136,\n 'utf8',\n ) // mtime\n header.write(' ', 148, 'utf8') // checksum placeholder (spaces while computing)\n header.write('0', 156, 'utf8') // typeflag: regular file\n header.write('ustar\\0', 257, 'utf8')\n header.write('00', 263, 'utf8')\n\n let checksum = 0\n for (const byte of header) checksum += byte\n header.write(checksum.toString(8).padStart(6, '0') + '\\0 ', 148, 'utf8')\n\n const paddedContentLength = Math.ceil(content.byteLength / 512) * 512\n const paddedContent = Buffer.alloc(paddedContentLength)\n content.copy(paddedContent)\n\n return Buffer.concat([header, paddedContent, Buffer.alloc(1024)]) // two 512-byte zero blocks terminate the archive\n}\n", "import { execFile, spawn } from 'child_process'\nimport { promisify } from 'util'\nimport fs from 'fs/promises'\nimport os from 'os'\nimport path from 'path'\nimport http from 'http'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmExecRequest,\n VmExecResult,\n VmFileWrite,\n VmRecord,\n VmRunMode,\n VmRunResult,\n VmWriteFilesResult,\n} from '@multiplayer-app/builder-types'\nimport type { DockerSandboxWorkerConfig } from '../config'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nconst DEFAULT_EXEC_TIMEOUT_MS = 60_000\nconst MAX_EXEC_TIMEOUT_MS = 300_000\nconst MAX_OUTPUT_BYTES = 1024 * 1024\nconst MAX_FILE_BYTES = 5 * 1024 * 1024\nconst WORKSPACE_DIR = '/workspace'\nconst AGENT_DIR = '/app'\n\nconst execFileAsync = promisify(execFile)\n\ninterface ManagedVm {\n handle: VmHandle\n sandboxName: string\n vmDir: string\n hostPort: number\n agentCommand: string\n runMode: VmRunMode\n startedAt: number\n}\n\n/** Reject \"../\" and absolute paths, same rule MockExecutor/DockerExecutor apply to their workspace. */\nfunction assertSafeWorkspacePath(relativePath: string): string {\n const normalized = relativePath.replace(/^([/\\\\])+/, '')\n if (normalized.split(/[/\\\\]/).includes('..')) {\n throw new Error(`Path escapes the VM workspace: ${relativePath}`)\n }\n return normalized\n}\n\n/** sbx sandbox names: letters/digits/hyphens/periods only, starting with a letter or digit. */\nfunction sandboxNameFor(vmId: string): string {\n return `mp-${vmId.replace(/[^a-zA-Z0-9.-]/g, '-')}`\n}\n\n/**\n * Runs VMs as Docker Sandboxes (`sbx`, docker.com/products/docker-sandboxes) \u2014 Docker's own\n * microVM-per-sandbox product, originally built for safely running AI coding agents. Reuses\n * the exact same per-stack images `docker` (DockerExecutor) already builds via\n * scripts/setup-docker-images.sh, bridged into sbx's own image store with `docker save` +\n * `sbx template load`.\n *\n * Two things `sbx` does differently from plain `docker run`, driven by its \"isolated agent\n * sandbox\" design rather than \"run this image\" design:\n * - `sbx create` doesn't execute the image's own Dockerfile CMD (confirmed via `ps aux`:\n * PID 1 is a `sleep infinity` placeholder) \u2014 the guest agent is launched explicitly via\n * `sbx exec -d` right after creation.\n * - `sbx create`/`run` require a real host directory to mount as the sandbox's workspace;\n * unrelated to the image's own internal /workspace (used by the guest agent for release\n * deploys) \u2014 just a disposable per-VM directory to satisfy the CLI.\n *\n * No `docker pause`-equivalent primitive exists here, so pause/resume alias stop/restore,\n * same precedent QemuExecutor already sets for engines without a distinct freeze primitive.\n */\nexport class DockerSandboxExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly usedPorts = new Set<number>()\n private readonly loadedTemplates = new Set<string>()\n private readonly bin: string\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n\n constructor(private readonly config: DockerSandboxWorkerConfig) {\n this.bin = config.bin\n }\n\n private allocatePort(): number {\n for (let p = this.config.portRangeStart; p <= this.config.portRangeEnd; p++) {\n if (!this.usedPorts.has(p)) {\n this.usedPorts.add(p)\n return p\n }\n }\n throw new Error('no free ports in docker-sandbox port range')\n }\n\n private resolveAgentCommand(stack: string): string {\n return (\n this.config.stackAgentCommands[stack] ??\n this.config.stackAgentCommands.generic ??\n 'node app.js'\n )\n }\n\n /** Local `docker` image tag for a stack, same resolution order as DockerExecutor.resolveImage. */\n private localImageFor(stack: string): string {\n const { imagePrefix, imageTag } = this.config\n return `${imagePrefix}-${stack}:${imageTag}`\n }\n\n /** Bridges the local docker image into sbx's own image store once per process; returns its ref. */\n private async ensureTemplateLoaded(stack: string): Promise<string> {\n const explicit = this.config.stackTemplates[stack]\n if (explicit) return explicit\n\n const localImage = this.localImageFor(stack)\n const templateRef = `docker.io/library/${localImage}`\n if (this.loadedTemplates.has(templateRef)) return templateRef\n\n const tmpFile = path.join(os.tmpdir(), `sbx-template-${stack}-${Date.now()}.tar`)\n try {\n await execFileAsync('docker', ['save', localImage, '-o', tmpFile])\n await execFileAsync(this.bin, ['template', 'load', tmpFile])\n } catch (error) {\n throw new Error(\n `failed to bridge local image \"${localImage}\" into sbx \u2014 run scripts/setup-docker-images.sh: ${error}`,\n )\n } finally {\n await fs.rm(tmpFile, { force: true })\n }\n\n this.loadedTemplates.add(templateRef)\n return templateRef\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const templateRef = await this.ensureTemplateLoaded(spec.stack)\n const agentCommand = this.resolveAgentCommand(spec.stack)\n const sandboxName = sandboxNameFor(spec.vmId)\n const hostPort = this.allocatePort()\n const vmDir = path.join(this.config.workspaceRoot, spec.vmId)\n await fs.mkdir(vmDir, { recursive: true })\n const memMib = Math.max(spec.resources.memMib, this.config.minMemoryMib)\n\n const createArgs = [\n 'create',\n 'shell',\n vmDir,\n '--template',\n templateRef,\n '--name',\n sandboxName,\n '-p',\n `127.0.0.1:${hostPort}:${this.config.guestPort}`,\n '-m',\n `${memMib}m`,\n '--cpus',\n String(spec.resources.vcpuCount),\n '-e',\n `VM_ID=${spec.vmId}`,\n '-e',\n `STACK=${spec.stack}`,\n ...(spec.sessionId ? ['-e', `SESSION_ID=${spec.sessionId}`] : []),\n ...(spec.appUrl ? ['-e', `APP_URL=${spec.appUrl}`] : []),\n ...Object.entries(spec.env ?? {}).flatMap(([key, value]) => ['-e', `${key}=${value}`]),\n ]\n\n const runMode = spec.runMode ?? 'service'\n\n logger.info({ vmId: spec.vmId, bin: this.bin, args: createArgs }, 'creating docker sandbox')\n try {\n await execFileAsync(this.bin, createArgs)\n if (runMode !== 'job') this.launchAgent(sandboxName, agentCommand)\n } catch (error) {\n this.usedPorts.delete(hostPort)\n await fs.rm(vmDir, { recursive: true, force: true }).catch(() => {})\n throw error\n }\n\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: { ...spec.resources, memMib },\n running: true,\n metadata: { sandboxName, hostPort, vmDir, agentCommand },\n }\n this.vms.set(spec.vmId, {\n handle,\n sandboxName,\n vmDir,\n hostPort,\n agentCommand,\n runMode,\n startedAt: Date.now(),\n })\n\n if (runMode === 'job') {\n this.runJob(spec.vmId, sandboxName, agentCommand)\n } else {\n await this.waitForAgent(hostPort)\n }\n logger.info({ vmId: spec.vmId, sandboxName, hostPort, runMode }, 'docker sandbox ready')\n return handle\n }\n\n /**\n * Job mode: unlike `launchAgent` (fire-and-forget `sbx exec -d`, used for persistent\n * services), run the entrypoint in the *foreground* \u2014 the CLI call itself blocks until the\n * command exits and hands back its exit code + captured stdout/stderr directly, so there's\n * no separate wait/logs step needed the way DockerExecutor needs for a backgrounded container.\n */\n private runJob(vmId: string, sandboxName: string, agentCommand: string): void {\n const startedAt = this.vms.get(vmId)?.startedAt ?? Date.now()\n execFile(\n this.bin,\n ['exec', '-w', AGENT_DIR, sandboxName, '/bin/sh', '-c', agentCommand],\n { maxBuffer: MAX_OUTPUT_BYTES },\n (error, stdout, stderr) => {\n const failed = error as (NodeJS.ErrnoException & { code?: number | string }) | null\n const truncated = failed?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'\n const result: VmRunResult = {\n exitCode: typeof failed?.code === 'number' ? failed.code : failed ? 1 : 0,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n truncated: Boolean(truncated),\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n }\n void this.finishJob(vmId, sandboxName, result)\n },\n )\n }\n\n private async finishJob(vmId: string, sandboxName: string, result: VmRunResult): Promise<void> {\n logger.info({ vmId, exitCode: result.exitCode }, 'docker sandbox job exited')\n await execFileAsync(this.bin, ['rm', '-f', sandboxName]).catch((error: Error) =>\n logger.warn({ vmId, err: error }, 'sbx rm after job exit failed'),\n )\n const vm = this.vms.get(vmId)\n if (vm) {\n await fs.rm(vm.vmDir, { recursive: true, force: true }).catch(() => {})\n this.usedPorts.delete(vm.hostPort)\n // Resources are already freed above, but the map entry stays (marked not-running)\n // until onExit() claims the result \u2014 see docker-executor's deliverJobResult for why.\n vm.handle = { ...vm.handle, running: false }\n }\n\n this.deliverJobResult(vmId, result)\n }\n\n private deliverJobResult(vmId: string, result: VmRunResult): void {\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n /**\n * `sbx create shell` doesn't run the image's own CMD \u2014 launch the guest agent explicitly.\n *\n * Fire-and-forget: `sbx exec -d` (detach) launches the background command correctly but its\n * own CLI process then hangs indefinitely instead of returning \u2014 confirmed live (the agent\n * was already answering on its port while the CLI call itself sat stuck for 14+ minutes,\n * needing a kill -9). `waitForAgent`'s port poll is the real readiness signal here, not this\n * process exiting, so it's spawned detached and never awaited.\n */\n private launchAgent(sandboxName: string, agentCommand: string): void {\n const proc = spawn(\n this.bin,\n ['exec', '-d', '-w', AGENT_DIR, sandboxName, '/bin/sh', '-c', agentCommand],\n {\n stdio: 'ignore',\n },\n )\n proc.on('error', (error) =>\n logger.warn({ sandboxName, err: error }, 'sbx exec -d failed to spawn'),\n )\n proc.unref()\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n return this.stop(vmId)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n return this.restore(vmId)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['stop', vm.sandboxName])\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['run', '--name', vm.sandboxName, '--detached'])\n const alreadyUp = await this.probeAgent(vm.hostPort)\n if (!alreadyUp) this.launchAgent(vm.sandboxName, vm.agentCommand)\n await this.waitForAgent(vm.hostPort)\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n await execFileAsync(this.bin, ['rm', '-f', vm.sandboxName]).catch((error: Error) =>\n logger.warn({ vmId, err: error }, 'sbx rm on destroy failed'),\n )\n await fs.rm(vm.vmDir, { recursive: true, force: true }).catch(() => {})\n this.usedPorts.delete(vm.hostPort)\n this.vms.delete(vmId)\n logger.info({ vmId }, 'docker sandbox destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n /**\n * Recover a sandbox after a worker restart: it's owned by the independent `sandboxd`\n * daemon, so a liveness probe against its name is enough to confirm it's still there.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as\n | { sandboxName?: string; hostPort?: number; vmDir?: string; agentCommand?: string }\n | undefined\n if (!meta?.sandboxName || meta.hostPort === undefined || !meta.vmDir || !meta.agentCommand)\n return undefined\n\n let running: boolean\n try {\n await execFileAsync(this.bin, ['exec', meta.sandboxName, 'true'])\n running = true\n } catch {\n try {\n await execFileAsync(this.bin, ['ls', '--json'])\n running = false // ran but the sandbox isn't reachable \u2014 treat as stopped, not gone\n } catch {\n return undefined\n }\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running,\n metadata: meta,\n }\n this.usedPorts.add(meta.hostPort)\n this.vms.set(record.vmId, {\n handle,\n sandboxName: meta.sandboxName,\n vmDir: meta.vmDir,\n hostPort: meta.hostPort,\n agentCommand: meta.agentCommand,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n\n if (record.runMode === 'job') {\n // The job's entrypoint ran as this worker's own foreground child process (see runJob) \u2014\n // it died with the worker, so there's nothing left to resume watching. Report it as\n // failed rather than leaving the record stuck in 'running' forever.\n void this.finishJob(record.vmId, meta.sandboxName, {\n exitCode: -1,\n stdout: '',\n stderr: 'worker restarted while this job was still running',\n truncated: false,\n durationMs: Date.now() - (Date.parse(record.createdAt) || Date.now()),\n finishedAt: new Date().toISOString(),\n })\n }\n\n logger.info({ vmId: record.vmId, sandboxName: meta.sandboxName }, 'docker sandbox reattached')\n return handle\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.mustGet(vmId)\n if (!vm.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: '127.0.0.1',\n port: vm.hostPort,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n async exec(vmId: string, request: VmExecRequest): Promise<VmExecResult> {\n const vm = this.mustGet(vmId)\n const cwd = request.cwd\n ? `${WORKSPACE_DIR}/${assertSafeWorkspacePath(request.cwd)}`\n : WORKSPACE_DIR\n const timeoutMs = Math.min(request.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS, MAX_EXEC_TIMEOUT_MS)\n const startedAt = Date.now()\n\n return new Promise((resolve) => {\n execFile(\n this.bin,\n ['exec', '-w', cwd, vm.sandboxName, '/bin/sh', '-c', request.command],\n { timeout: timeoutMs, maxBuffer: MAX_OUTPUT_BYTES },\n (error, stdout, stderr) => {\n const failed = error as\n | (NodeJS.ErrnoException & { code?: number | string; killed?: boolean })\n | null\n const timedOut = Boolean(failed?.killed)\n const truncated = failed?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'\n resolve({\n exitCode: typeof failed?.code === 'number' ? failed.code : failed ? 1 : 0,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n durationMs: Date.now() - startedAt,\n truncated: Boolean(truncated),\n timedOut,\n })\n },\n )\n })\n }\n\n async writeFiles(vmId: string, files: VmFileWrite[]): Promise<VmWriteFilesResult> {\n const vm = this.mustGet(vmId)\n const written: Array<{ path: string; bytes: number }> = []\n\n for (const file of files) {\n const relativePath = assertSafeWorkspacePath(file.path)\n const buffer = Buffer.from(file.content, file.encoding === 'base64' ? 'base64' : 'utf8')\n if (buffer.byteLength > MAX_FILE_BYTES) {\n throw new Error(\n `File too large (${buffer.byteLength} bytes, max ${MAX_FILE_BYTES}): ${file.path}`,\n )\n }\n\n const dir = relativePath.includes('/')\n ? relativePath.slice(0, relativePath.lastIndexOf('/'))\n : ''\n if (dir) {\n await execFileAsync(this.bin, [\n 'exec',\n vm.sandboxName,\n 'mkdir',\n '-p',\n `${WORKSPACE_DIR}/${dir}`,\n ])\n }\n\n // sbx cp takes a real host path on one side \u2014 simpler than DockerExecutor's tar-over-stdin hack.\n const tmpFile = path.join(\n os.tmpdir(),\n `sbx-write-${vmId}-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n )\n await fs.writeFile(tmpFile, buffer)\n try {\n await execFileAsync(this.bin, [\n 'cp',\n tmpFile,\n `${vm.sandboxName}:${WORKSPACE_DIR}/${relativePath}`,\n ])\n } finally {\n await fs.rm(tmpFile, { force: true })\n }\n written.push({ path: relativePath, bytes: buffer.byteLength })\n }\n\n logger.info({ vmId, files: written.length }, 'docker sandbox files written')\n return { written }\n }\n\n private mustGet(vmId: string): ManagedVm {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n return vm\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.mustGet(vmId)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n\n private async probeAgent(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const req = http.get({ host: '127.0.0.1', port, path: '/', timeout: 2_000 }, (res) => {\n res.resume()\n resolve(true)\n })\n req.on('error', () => resolve(false))\n req.on('timeout', () => {\n req.destroy()\n resolve(false)\n })\n })\n }\n\n private async waitForAgent(port: number, timeoutMs = 30_000): Promise<void> {\n const deadline = Date.now() + timeoutMs\n for (;;) {\n if (await this.probeAgent(port)) return\n if (Date.now() > deadline)\n throw new Error(`timed out waiting for docker sandbox agent on port ${port}`)\n await new Promise((resolve) => setTimeout(resolve, 500))\n }\n }\n}\n", "import http from 'http'\nimport https from 'https'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmRunResult,\n} from '@multiplayer-app/builder-types'\nimport type { Executor, VmHandle, VmSpec } from './types'\nimport { withTimeout } from './reattach-utils'\n\nconst JOB_POLL_INTERVAL_MS = 3_000\n\nexport interface RemoteExecutorConfig {\n agentUrl: string // e.g. http://192.168.1.10:4040\n authToken?: string\n}\n\nexport class RemoteExecutor implements Executor {\n private readonly base: string\n private readonly headers: Record<string, string>\n // The remote agent is the actual source of truth, but MultiEngineExecutor.route() (used by\n // pause/resume/stop/restore/destroy/proxyHttp/exec/writeFiles) needs get() to find the\n // right executor for a vmId \u2014 cache the handle each call returns so it does.\n private readonly vms = new Map<string, VmHandle>()\n private readonly jobStartedAt = new Map<string, number>()\n\n constructor(config: RemoteExecutorConfig) {\n this.base = config.agentUrl.replace(/\\/$/, '')\n this.headers = {\n 'Content-Type': 'application/json',\n ...(config.authToken ? { Authorization: `Bearer ${config.authToken}` } : {}),\n }\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const handle = await this.request<VmHandle>('POST', '/vms', spec)\n this.vms.set(spec.vmId, handle)\n if (spec.runMode === 'job') this.jobStartedAt.set(spec.vmId, Date.now())\n return handle\n }\n\n /**\n * The remote agent's own wire protocol (VmHandle) has no exit-code/output field \u2014 extending\n * it is out of this repo's control, so this only detects completion (poll GET /vms/:vmId\n * until running flips false) without a real exit code or captured output. Good enough to\n * unblock the record from being stuck in 'running' forever; a real RemoteExecutor deployment\n * wanting full job support needs its agent protocol extended first.\n */\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const startedAt = this.jobStartedAt.get(vmId) ?? Date.now()\n const poll = async () => {\n const handle = await this.request<VmHandle>('GET', `/vms/${vmId}`).catch(() => undefined)\n if (handle) this.vms.set(vmId, handle)\n\n if (!handle || !handle.running) {\n this.jobStartedAt.delete(vmId)\n this.vms.delete(vmId)\n handler({\n exitCode: 0,\n stdout: '',\n stderr:\n 'remote engine does not report job exit codes/output \u2014 completion detected via polling only',\n truncated: false,\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n })\n return\n }\n setTimeout(() => void poll(), JOB_POLL_INTERVAL_MS)\n }\n void poll()\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n return this.updateCached(vmId, await this.request('POST', `/vms/${vmId}/pause`))\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n return this.updateCached(vmId, await this.request('POST', `/vms/${vmId}/resume`))\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n return this.updateCached(vmId, await this.request('POST', `/vms/${vmId}/stop`))\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n return this.updateCached(vmId, await this.request('POST', `/vms/${vmId}/restore`))\n }\n\n async destroy(vmId: string): Promise<void> {\n await this.request('DELETE', `/vms/${vmId}`)\n this.vms.delete(vmId)\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()]\n }\n\n /**\n * Recover a remote-agent VM after a worker restart. The agent owns the actual VM state\n * independently of this process, so reattaching is just confirming it still knows about\n * this vmId and re-populating the local get()/list() cache above.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n try {\n const handle = await withTimeout(this.request<VmHandle>('GET', `/vms/${record.vmId}`), 5_000)\n this.vms.set(record.vmId, handle)\n return handle\n } catch {\n return undefined\n }\n }\n\n private updateCached(vmId: string, handle: VmHandle): VmHandle {\n this.vms.set(vmId, handle)\n return handle\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const result = await this.request<{\n statusCode: number\n headers: Record<string, string>\n body?: string\n }>('POST', `/vms/${vmId}/proxy`, {\n method: request.method,\n path: request.path,\n headers: request.headers,\n body: request.body?.toString('base64'),\n })\n\n return {\n statusCode: result.statusCode,\n headers: result.headers,\n body: result.body ? Buffer.from(result.body, 'base64') : Buffer.alloc(0),\n }\n }\n\n private request<T = unknown>(method: string, path: string, body?: unknown): Promise<T> {\n const url = new URL(this.base + path)\n const lib = url.protocol === 'https:' ? https : http\n const payload = body !== undefined ? JSON.stringify(body) : undefined\n\n return new Promise((resolve, reject) => {\n const req = lib.request(\n {\n hostname: url.hostname,\n port: url.port || (url.protocol === 'https:' ? 443 : 80),\n path: url.pathname,\n method,\n headers: {\n ...this.headers,\n ...(payload ? { 'Content-Length': Buffer.byteLength(payload) } : {}),\n },\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () => {\n const text = Buffer.concat(chunks).toString()\n if (res.statusCode && res.statusCode >= 400) {\n reject(new Error(`vm-agent ${method} ${path} \u2192 ${res.statusCode}: ${text}`))\n return\n }\n if (res.statusCode === 204 || !text) {\n resolve(undefined as T)\n return\n }\n try {\n resolve(JSON.parse(text) as T)\n } catch {\n resolve(text as unknown as T)\n }\n })\n },\n )\n req.on('error', reject)\n if (payload) req.write(payload)\n req.end()\n })\n }\n}\n", "import https from 'https'\nimport {\n LambdaMicrovmsClient,\n RunMicrovmCommand,\n SuspendMicrovmCommand,\n ResumeMicrovmCommand,\n TerminateMicrovmCommand,\n GetMicrovmCommand,\n CreateMicrovmAuthTokenCommand,\n} from '@aws-sdk/client-lambda-microvms'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmStack,\n} from '@multiplayer-app/builder-types'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nexport interface LambdaMicrovmConfig {\n region?: string\n /** Default MicroVM image ARN, used for any stack without a specific image. */\n imageArn: string\n /** Per-stack image ARN overrides, e.g. { node: 'arn:...', python: 'arn:...' }. */\n stackImageArns?: Partial<Record<VmStack, string>>\n ingressConnectorArns?: string[]\n egressConnectorArns?: string[]\n executionRoleArn?: string\n /** Suspend automatically after this many seconds without endpoint traffic (0 disables the idle policy). */\n maxIdleSeconds?: number\n /** Terminate automatically after this many seconds in the suspended state. */\n suspendedDurationSeconds?: number\n /** Hard lifetime cap for a MicroVM (running + suspended), max 28800. */\n maximumDurationInSeconds?: number\n /** How long to wait for the RUNNING state after run-microvm. */\n createTimeoutMs?: number\n}\n\ninterface ManagedMicrovm {\n handle: VmHandle\n microvmId: string\n endpoint: string\n authToken?: { headers: Record<string, string>; expiresAt: number }\n}\n\nconst AUTH_TOKEN_TTL_MINUTES = 60\nconst AUTH_TOKEN_REFRESH_MARGIN_MS = 2 * 60_000\n\n/**\n * Runs VMs as AWS Lambda MicroVMs (Firecracker snapshots managed by Lambda).\n * No VNC framebuffer or serial console \u2014 HTTP(S) into the guest only, via the\n * MicroVM's dedicated endpoint with JWE auth. Suspend/resume preserve full\n * memory + disk state, so pause/resume here is a true checkpoint, unlike QEMU's.\n *\n * Intentionally has no onExit(): unlike Fargate (whose ECS task actually stops when the\n * container's process exits) or QEMU/Firecracker (a guest poweroff kills the local hypervisor\n * process we spawned), a MicroVM's AWS-managed lifecycle has no state that reflects \"the\n * guest's own entrypoint finished\" \u2014 it only transitions via explicit suspend/resume/terminate\n * calls or the idle/duration policies above. 'job' run mode isn't supported on this engine\n * until the guest image itself can signal completion back out (e.g. call TerminateMicrovm on\n * itself, or a callback through the existing HTTP proxy path) \u2014 MultiEngineExecutor.onExit()\n * already surfaces a clear \"does not support job run mode\" error for this engine as-is.\n */\nexport class LambdaMicrovmExecutor implements Executor {\n private readonly client: LambdaMicrovmsClient\n private readonly vms = new Map<string, ManagedMicrovm>()\n\n constructor(private readonly config: LambdaMicrovmConfig) {\n this.client = new LambdaMicrovmsClient(config.region ? { region: config.region } : {})\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const imageIdentifier = this.config.stackImageArns?.[spec.stack] ?? this.config.imageArn\n const maxIdle = this.config.maxIdleSeconds ?? 900\n\n const run = await this.client.send(\n new RunMicrovmCommand({\n imageIdentifier,\n ingressNetworkConnectors: this.config.ingressConnectorArns,\n egressNetworkConnectors: this.config.egressConnectorArns,\n executionRoleArn: this.config.executionRoleArn,\n maximumDurationInSeconds: this.config.maximumDurationInSeconds ?? 28_800,\n ...(maxIdle > 0\n ? {\n idlePolicy: {\n autoResumeEnabled: true,\n maxIdleDurationSeconds: maxIdle,\n suspendedDurationSeconds: this.config.suspendedDurationSeconds ?? 28_800,\n },\n }\n : {}),\n // The guest's /run lifecycle hook receives this payload \u2014 lets the image\n // identify which builder session/VM it serves.\n runHookPayload: JSON.stringify({\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n appUrl: spec.appUrl,\n env: spec.env,\n }),\n }),\n )\n\n if (!run.microvmId || !run.endpoint) {\n throw new Error('run-microvm returned no microvmId/endpoint')\n }\n\n logger.info(\n { vmId: spec.vmId, microvmId: run.microvmId, endpoint: run.endpoint, state: run.state },\n '[LambdaMicrovm] run-microvm accepted',\n )\n\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n // Resources are fixed at MicroVM image build time; echo the request back for bookkeeping.\n resources: spec.resources,\n running: true,\n metadata: { microvmId: run.microvmId, endpoint: run.endpoint },\n }\n\n const vm: ManagedMicrovm = { handle, microvmId: run.microvmId, endpoint: run.endpoint }\n this.vms.set(spec.vmId, vm)\n\n try {\n await this.waitForState(run.microvmId, 'RUNNING', this.config.createTimeoutMs ?? 25_000)\n } catch (error) {\n this.vms.delete(spec.vmId)\n await this.client\n .send(new TerminateMicrovmCommand({ microvmIdentifier: run.microvmId }))\n .catch(() => {})\n throw error\n }\n\n logger.info({ vmId: spec.vmId, microvmId: run.microvmId }, '[LambdaMicrovm] vm running')\n return handle\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await this.client.send(new SuspendMicrovmCommand({ microvmIdentifier: vm.microvmId }))\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await this.client.send(new ResumeMicrovmCommand({ microvmIdentifier: vm.microvmId }))\n return this.setRunning(vmId, true)\n }\n\n // Suspend preserves memory + disk, so stop/restore are the same checkpoint\n // operations as pause/resume \u2014 there is no separate \"powered off\" state.\n stop(vmId: string): Promise<VmHandle> {\n return this.pause(vmId)\n }\n\n restore(vmId: string): Promise<VmHandle> {\n return this.resume(vmId)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n await this.client.send(new TerminateMicrovmCommand({ microvmIdentifier: vm.microvmId }))\n this.vms.delete(vmId)\n logger.info({ vmId, microvmId: vm.microvmId }, '[LambdaMicrovm] vm terminated')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.mustGet(vmId)\n const auth = await this.getAuthHeaders(vm)\n\n return new Promise((resolve, reject) => {\n const req = https.request(\n {\n host: vm.endpoint,\n method: request.method,\n path: request.path,\n headers: {\n ...request.headers,\n ...auth,\n // Lambda routes to port 8080 by default; make the guest port explicit.\n 'X-aws-proxy-port': '8080',\n host: vm.endpoint,\n },\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n /**\n * Recover a Lambda MicroVM after a worker restart. It's an independent AWS-managed\n * resource that outlives this process \u2014 just re-describe it by ID and, unless it's been\n * terminated, rebuild the local handle (the auth token refetches lazily as usual).\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as { microvmId?: string; endpoint?: string } | undefined\n if (!meta?.microvmId || !meta.endpoint) return undefined\n\n const described = await this.client\n .send(new GetMicrovmCommand({ microvmIdentifier: meta.microvmId }))\n .catch(() => undefined)\n if (!described || described.state === 'TERMINATED' || described.state === 'TERMINATING') {\n return undefined\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running: described.state === 'RUNNING',\n metadata: meta,\n }\n this.vms.set(record.vmId, { handle, microvmId: meta.microvmId, endpoint: meta.endpoint })\n logger.info(\n { vmId: record.vmId, microvmId: meta.microvmId, state: described.state },\n '[LambdaMicrovm] vm reattached',\n )\n return handle\n }\n\n private mustGet(vmId: string): ManagedMicrovm {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n return vm\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.mustGet(vmId)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n\n private async getAuthHeaders(vm: ManagedMicrovm): Promise<Record<string, string>> {\n if (vm.authToken && vm.authToken.expiresAt - Date.now() > AUTH_TOKEN_REFRESH_MARGIN_MS) {\n return vm.authToken.headers\n }\n\n const resp = await this.client.send(\n new CreateMicrovmAuthTokenCommand({\n microvmIdentifier: vm.microvmId,\n expirationInMinutes: AUTH_TOKEN_TTL_MINUTES,\n allowedPorts: [{ allPorts: {} }],\n }),\n )\n if (!resp.authToken) throw new Error('create-microvm-auth-token returned no token')\n\n vm.authToken = {\n headers: resp.authToken,\n expiresAt: Date.now() + AUTH_TOKEN_TTL_MINUTES * 60_000,\n }\n return vm.authToken.headers\n }\n\n private async waitForState(microvmId: string, target: string, timeoutMs: number): Promise<void> {\n const deadline = Date.now() + timeoutMs\n for (;;) {\n const resp = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: microvmId }))\n if (resp.state === target) return\n if (resp.state === 'TERMINATED' || resp.state === 'TERMINATING') {\n throw new Error(`microvm ${microvmId} entered ${resp.state} while waiting for ${target}`)\n }\n if (Date.now() > deadline) {\n throw new Error(\n `timed out waiting for microvm ${microvmId} to reach ${target} (still ${resp.state})`,\n )\n }\n await new Promise((r) => setTimeout(r, 1_000))\n }\n }\n}\n", "import http from 'http'\nimport {\n ECSClient,\n RunTaskCommand,\n StopTaskCommand,\n DescribeTasksCommand,\n DescribeTaskDefinitionCommand,\n} from '@aws-sdk/client-ecs'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmRunMode,\n VmRunResult,\n VmStack,\n} from '@multiplayer-app/builder-types'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nconst JOB_POLL_INTERVAL_MS = 5_000\n\nexport interface FargateConfig {\n region?: string\n /** ECS cluster name or ARN. */\n cluster: string\n /** Default task definition (family[:revision] or ARN), used for stacks without an override. */\n taskDefinition?: string\n /** Per-stack task definition overrides, e.g. { node: 'builder-node:3' }. */\n stackTaskDefinitions?: Partial<Record<VmStack, string>>\n /** VPC subnets for awsvpc networking. */\n subnets: string[]\n securityGroups?: string[]\n /**\n * ENABLED: task gets a public IP and the worker proxies to it (worker outside the VPC).\n * DISABLED (default): the worker proxies to the task's private IP (worker inside the VPC).\n */\n assignPublicIp?: boolean\n /** Guest HTTP port the app/agent listens on. */\n guestPort?: number\n /** How long to wait for the task to reach RUNNING (image pulls can be slow). */\n startTimeoutMs?: number\n}\n\ninterface ManagedTask {\n handle: VmHandle\n taskArn: string\n ip: string\n runMode: VmRunMode\n startedAt: number\n}\n\n// Valid Fargate cpu (units) \u2192 [min, max] task memory (MiB).\nconst FARGATE_MEM_RANGES: Record<number, [number, number]> = {\n 256: [512, 2048],\n 512: [1024, 4096],\n 1024: [2048, 8192],\n 2048: [4096, 16384],\n 4096: [8192, 30720],\n}\n\n/** Snap requested VM resources to a valid Fargate cpu/memory combination. */\nexport function fargateResources(\n vcpuCount: number,\n memMib: number,\n): { cpu: string; memory: string } {\n const cpu = Math.min(4096, Math.max(256, vcpuCount * 1024))\n const [min, max] = FARGATE_MEM_RANGES[cpu]\n let memory = Math.min(max, Math.max(min, memMib))\n // Above 512 MiB, Fargate only accepts 1 GiB increments\n if (memory > 512) memory = Math.ceil(memory / 1024) * 1024\n return { cpu: String(cpu), memory: String(Math.min(max, memory)) }\n}\n\n/**\n * Runs VMs as AWS Fargate tasks (one task per VM). No VNC or serial console and no\n * pause/resume \u2014 HTTP(S) into the container only, via the task's IP on the guest port.\n * Slower to start than Lambda MicroVMs (image pull + task provisioning), but supports\n * arbitrary container images via standard ECS task definitions.\n */\nexport class FargateExecutor implements Executor {\n private readonly client: ECSClient\n private readonly vms = new Map<string, ManagedTask>()\n private readonly containerNames = new Map<string, string>()\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n\n constructor(private readonly config: FargateConfig) {\n this.client = new ECSClient(config.region ? { region: config.region } : {})\n }\n\n /** First container of the task definition \u2014 the target for env overrides. Cached per definition. */\n private async resolveContainerName(taskDefinition: string): Promise<string> {\n const cached = this.containerNames.get(taskDefinition)\n if (cached) return cached\n\n const described = await this.client.send(new DescribeTaskDefinitionCommand({ taskDefinition }))\n const name = described.taskDefinition?.containerDefinitions?.[0]?.name\n if (!name) throw new Error(`task definition ${taskDefinition} has no containers`)\n this.containerNames.set(taskDefinition, name)\n return name\n }\n\n private async waitForRunning(taskArn: string): Promise<string> {\n const timeoutMs = this.config.startTimeoutMs ?? 180_000\n const deadline = Date.now() + timeoutMs\n\n for (;;) {\n const described = await this.client.send(\n new DescribeTasksCommand({ cluster: this.config.cluster, tasks: [taskArn] }),\n )\n const task = described.tasks?.[0]\n if (!task) throw new Error(`task ${taskArn} not found`)\n\n if (task.lastStatus === 'STOPPED') {\n throw new Error(`fargate task stopped: ${task.stoppedReason ?? 'unknown reason'}`)\n }\n if (task.lastStatus === 'RUNNING') {\n const ip = this.config.assignPublicIp\n ? await this.resolvePublicIp(task.attachments)\n : task.containers?.[0]?.networkInterfaces?.[0]?.privateIpv4Address\n if (!ip)\n throw new Error(\n `fargate task ${taskArn} is RUNNING but has no ${this.config.assignPublicIp ? 'public' : 'private'} IP`,\n )\n return ip\n }\n if (Date.now() > deadline) {\n throw new Error(\n `fargate task did not reach RUNNING within ${timeoutMs}ms (last status: ${task.lastStatus})`,\n )\n }\n await new Promise((resolve) => setTimeout(resolve, 3000))\n }\n }\n\n private async resolvePublicIp(\n attachments: { type?: string; details?: { name?: string; value?: string }[] }[] | undefined,\n ): Promise<string | undefined> {\n const eniId = attachments\n ?.find((a) => a.type === 'ElasticNetworkInterface')\n ?.details?.find((d) => d.name === 'networkInterfaceId')?.value\n if (!eniId) return undefined\n\n const { EC2Client, DescribeNetworkInterfacesCommand } = await import('@aws-sdk/client-ec2')\n const ec2 = new EC2Client(this.config.region ? { region: this.config.region } : {})\n const described = await ec2.send(\n new DescribeNetworkInterfacesCommand({ NetworkInterfaceIds: [eniId] }),\n )\n return described.NetworkInterfaces?.[0]?.Association?.PublicIp\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const taskDefinition =\n this.config.stackTaskDefinitions?.[spec.stack] ?? this.config.taskDefinition\n if (!taskDefinition) {\n throw new Error(`no Fargate task definition configured for stack \"${spec.stack}\"`)\n }\n\n const containerName = await this.resolveContainerName(taskDefinition)\n const { cpu, memory } = fargateResources(spec.resources.vcpuCount, spec.resources.memMib)\n\n const run = await this.client.send(\n new RunTaskCommand({\n cluster: this.config.cluster,\n taskDefinition,\n launchType: 'FARGATE',\n count: 1,\n networkConfiguration: {\n awsvpcConfiguration: {\n subnets: this.config.subnets,\n securityGroups: this.config.securityGroups,\n assignPublicIp: this.config.assignPublicIp ? 'ENABLED' : 'DISABLED',\n },\n },\n overrides: {\n cpu,\n memory,\n containerOverrides: [\n {\n name: containerName,\n environment: [\n { name: 'VM_ID', value: spec.vmId },\n ...(spec.sessionId ? [{ name: 'SESSION_ID', value: spec.sessionId }] : []),\n { name: 'STACK', value: spec.stack },\n // Release artifact: the container agent pulls, unzips, and starts it\n ...(spec.appUrl ? [{ name: 'APP_URL', value: spec.appUrl }] : []),\n ...Object.entries(spec.env ?? {}).map(([name, value]) => ({ name, value })),\n ],\n },\n ],\n },\n tags: [\n { key: 'vmId', value: spec.vmId },\n ...(spec.sessionId ? [{ key: 'sessionId', value: spec.sessionId }] : []),\n ],\n }),\n )\n\n const taskArn = run.tasks?.[0]?.taskArn\n if (!taskArn) {\n throw new Error(`RunTask failed: ${run.failures?.[0]?.reason ?? 'no task returned'}`)\n }\n logger.info({ vmId: spec.vmId, taskArn, taskDefinition, cpu, memory }, 'fargate task started')\n\n const runMode = spec.runMode ?? 'service'\n try {\n const ip = await this.waitForRunning(taskArn)\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n metadata: { taskArn, ip },\n }\n this.vms.set(spec.vmId, { handle, taskArn, ip, runMode, startedAt: Date.now() })\n if (runMode === 'job') void this.watchJob(spec.vmId, taskArn)\n logger.info({ vmId: spec.vmId, ip, runMode }, 'fargate task running')\n return handle\n } catch (error) {\n await this.client\n .send(\n new StopTaskCommand({\n cluster: this.config.cluster,\n task: taskArn,\n reason: 'startup failed',\n }),\n )\n .catch(() => {})\n throw error\n }\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n throw new Error(`fargate tasks cannot be paused (vm ${vmId})`)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n throw new Error(`fargate tasks cannot be resumed (vm ${vmId})`)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n throw new Error(`fargate tasks cannot be restored (vm ${vmId})`)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await this.client.send(\n new StopTaskCommand({\n cluster: this.config.cluster,\n task: vm.taskArn,\n reason: 'stopped via API',\n }),\n )\n vm.handle.running = false\n return vm.handle\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n await this.client\n .send(\n new StopTaskCommand({\n cluster: this.config.cluster,\n task: vm.taskArn,\n reason: 'destroyed via API',\n }),\n )\n .catch((error: Error) => logger.warn({ vmId, err: error }, 'fargate stop on destroy failed'))\n this.vms.delete(vmId)\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((vm) => vm.handle)\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.mustGet(vmId)\n if (!vm.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: vm.ip,\n port: this.config.guestPort ?? 8080,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n /**\n * Recover a Fargate task after a worker restart. The task is an independent AWS resource\n * that outlives this process \u2014 just re-describe it by ARN and, if it's still RUNNING,\n * rebuild the local handle.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as { taskArn?: string } | undefined\n if (!meta?.taskArn) return undefined\n\n const described = await this.client\n .send(new DescribeTasksCommand({ cluster: this.config.cluster, tasks: [meta.taskArn] }))\n .catch(() => undefined)\n const task = described?.tasks?.[0]\n if (!task || task.lastStatus !== 'RUNNING') return undefined\n\n const ip = this.config.assignPublicIp\n ? await this.resolvePublicIp(task.attachments)\n : task.containers?.[0]?.networkInterfaces?.[0]?.privateIpv4Address\n if (!ip) return undefined\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running: true,\n metadata: { taskArn: meta.taskArn, ip },\n }\n this.vms.set(record.vmId, {\n handle,\n taskArn: meta.taskArn,\n ip,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n if (record.runMode === 'job') void this.watchJob(record.vmId, meta.taskArn)\n logger.info({ vmId: record.vmId, taskArn: meta.taskArn, ip }, 'fargate task reattached')\n return handle\n }\n\n /**\n * No push notification exists for \"task stopped\" without EventBridge wiring (v1 doesn't set\n * that up), so poll DescribeTasks. Exit code comes straight from the container's own\n * `exitCode` field \u2014 no CloudWatch Logs integration yet, so stdout/stderr capture isn't\n * implemented for this engine (the caller can still find full output in CloudWatch directly,\n * via the task's own log configuration).\n */\n private async watchJob(vmId: string, taskArn: string): Promise<void> {\n const startedAt = this.vms.get(vmId)?.startedAt ?? Date.now()\n for (;;) {\n await new Promise((resolve) => setTimeout(resolve, JOB_POLL_INTERVAL_MS))\n if (!this.vms.has(vmId)) return // destroyed out from under the poll\n\n const described = await this.client\n .send(new DescribeTasksCommand({ cluster: this.config.cluster, tasks: [taskArn] }))\n .catch(() => undefined)\n const task = described?.tasks?.[0]\n\n if (!task) {\n this.finishJob(vmId, {\n exitCode: -1,\n stdout: '',\n stderr: 'fargate task not found while polling for completion',\n truncated: false,\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n })\n return\n }\n if (task.lastStatus === 'STOPPED') {\n const exitCode = task.containers?.[0]?.exitCode\n this.finishJob(vmId, {\n exitCode: exitCode ?? 1,\n stdout: '',\n stderr: [\n task.stoppedReason ? `stoppedReason: ${task.stoppedReason}` : undefined,\n 'output capture not implemented for the fargate engine \u2014 see CloudWatch Logs for this task',\n ]\n .filter(Boolean)\n .join('; '),\n truncated: false,\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n })\n return\n }\n }\n }\n\n private finishJob(vmId: string, result: VmRunResult): void {\n logger.info({ vmId, exitCode: result.exitCode }, 'fargate job task exited')\n // Keep the map entry (marked not-running) until onExit() claims the result \u2014 see\n // docker-executor's deliverJobResult comment for why route() needs get() to still work.\n const vm = this.vms.get(vmId)\n if (vm) vm.handle = { ...vm.handle, running: false }\n\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n private mustGet(vmId: string): ManagedTask {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n return vm\n }\n}\n", "import fs from 'fs'\nimport { execFileSync } from 'child_process'\nimport logger from '@multiplayer-app/logger'\nimport { VM_STACKS, type VmEngine } from '@multiplayer-app/builder-types'\nimport { availableStacks } from '../images'\nimport type { WorkerConfig } from '../config'\n\n/** Auto-mode default preference when multiple engines are runnable on this host. */\nconst ENGINE_PRIORITY: VmEngine[] = [\n 'firecracker',\n 'qemu',\n 'docker-sandbox',\n 'docker',\n 'lambda-microvm',\n 'fargate',\n 'remote',\n 'mock',\n]\n\nexport interface EngineProbe {\n engine: VmEngine\n available: boolean\n /** Why the engine is unavailable (for startup logs). */\n reason?: string\n}\n\nfunction binaryOnPath(bin: string): boolean {\n if (bin.includes('/')) {\n try {\n fs.accessSync(bin, fs.constants.X_OK)\n return true\n } catch {\n return false\n }\n }\n try {\n execFileSync('which', [bin], { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nfunction kvmUsable(): boolean {\n try {\n fs.accessSync('/dev/kvm', fs.constants.R_OK | fs.constants.W_OK)\n return true\n } catch {\n return false\n }\n}\n\n/** Explicit kernel/initrd override present, or at least one stack dir with both image files. */\nfunction hasBaseImages(cfg: {\n imagesDir: string\n kernelPath?: string\n initrdPath?: string\n}): boolean {\n if (cfg.kernelPath && cfg.initrdPath)\n return fs.existsSync(cfg.kernelPath) && fs.existsSync(cfg.initrdPath)\n return availableStacks(cfg.imagesDir).length > 0\n}\n\nfunction probeQemu(config: WorkerConfig): EngineProbe {\n const { bin, accel } = config.qemu\n if (!hasBaseImages(config.qemu)) {\n return {\n engine: 'qemu',\n available: false,\n reason: `no base images under ${config.qemu.imagesDir} \u2014 run \"worker-cli images pull\" or scripts/setup-vm-images.sh`,\n }\n }\n if (!binaryOnPath(bin)) {\n return { engine: 'qemu', available: false, reason: `${bin} not found on PATH` }\n }\n if (accel === 'hvf' && process.platform !== 'darwin') {\n return {\n engine: 'qemu',\n available: false,\n reason: 'QEMU_ACCEL=hvf requires macOS (use kvm or tcg)',\n }\n }\n if (accel === 'kvm' && !kvmUsable()) {\n return {\n engine: 'qemu',\n available: false,\n reason: 'QEMU_ACCEL=kvm but /dev/kvm is not accessible',\n }\n }\n return { engine: 'qemu', available: true }\n}\n\nfunction probeFirecracker(config: WorkerConfig): EngineProbe {\n const { bin } = config.firecracker\n if (process.platform !== 'linux') {\n return { engine: 'firecracker', available: false, reason: 'requires a Linux host' }\n }\n if (!kvmUsable()) {\n return { engine: 'firecracker', available: false, reason: '/dev/kvm is not accessible' }\n }\n if (!hasBaseImages(config.firecracker)) {\n return {\n engine: 'firecracker',\n available: false,\n reason: `no base images under ${config.firecracker.imagesDir} \u2014 run \"worker-cli images pull\" or scripts/setup-vm-images.sh`,\n }\n }\n if (!binaryOnPath(bin)) {\n return { engine: 'firecracker', available: false, reason: `${bin} not found on PATH` }\n }\n return { engine: 'firecracker', available: true }\n}\n\n/** Whether at least one <imagePrefix>-<stack>:<imageTag> image exists in the local `docker` daemon. */\nfunction hasLocalDockerImage(\n bin: string,\n imagePrefix: string,\n imageTag: string,\n stackImages: Record<string, string> = {},\n): boolean {\n return VM_STACKS.some((stack) => {\n try {\n const image = stackImages[stack] ?? `${imagePrefix}-${stack}:${imageTag}`\n execFileSync(bin, ['image', 'inspect', image], { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n })\n}\n\nfunction probeDocker(config: WorkerConfig): EngineProbe {\n const { bin, imagePrefix, imageTag, stackImages } = config.docker\n if (!binaryOnPath(bin)) {\n return { engine: 'docker', available: false, reason: `${bin} not found on PATH` }\n }\n try {\n execFileSync(bin, ['info'], { stdio: 'ignore' })\n } catch {\n return { engine: 'docker', available: false, reason: 'docker daemon not reachable' }\n }\n if (!hasLocalDockerImage(bin, imagePrefix, imageTag, stackImages)) {\n return {\n engine: 'docker',\n available: false,\n reason: 'no local docker images \u2014 run scripts/setup-docker-images.sh',\n }\n }\n return { engine: 'docker', available: true }\n}\n\n/**\n * `docker-sandbox` (Docker's own Sandboxes product, the `sbx` CLI) bridges the same local\n * `docker` images in on demand (see DockerSandboxExecutor.ensureTemplateLoaded), so it needs\n * both `sbx` itself and those local images to exist. A not-yet-initialized global network\n * policy (`sbx policy init balanced|allow-all|deny-all`, required once before any sandbox can\n * be created) isn't checked here \u2014 same as Fargate detect not validating IAM permissions\n * upfront \u2014 it'll surface as a clear error the first time `create()` is called instead.\n */\nfunction probeDockerSandbox(config: WorkerConfig): EngineProbe {\n const { bin, imagePrefix, imageTag } = config.dockerSandbox\n if (!binaryOnPath(bin)) {\n return { engine: 'docker-sandbox', available: false, reason: `${bin} not found on PATH` }\n }\n try {\n execFileSync(bin, ['ls'], { stdio: 'ignore' })\n } catch {\n return {\n engine: 'docker-sandbox',\n available: false,\n reason: 'sbx daemon not reachable \u2014 run \"sbx daemon start\" and \"sbx login\"',\n }\n }\n if (!hasLocalDockerImage(config.docker.bin, imagePrefix, imageTag)) {\n return {\n engine: 'docker-sandbox',\n available: false,\n reason: 'no local docker images \u2014 run scripts/setup-docker-images.sh',\n }\n }\n return { engine: 'docker-sandbox', available: true }\n}\n\nfunction probeRemote(config: WorkerConfig): EngineProbe {\n return config.remote.agentUrl\n ? { engine: 'remote', available: true }\n : { engine: 'remote', available: false, reason: 'AGENT_URL not set' }\n}\n\nfunction probeLambdaMicrovm(config: WorkerConfig): EngineProbe {\n const { imageArn, stackImageArns } = config.lambdaMicrovm\n return imageArn || Object.keys(stackImageArns).length\n ? { engine: 'lambda-microvm', available: true }\n : {\n engine: 'lambda-microvm',\n available: false,\n reason: 'MICROVM_IMAGE_ARN / MICROVM_STACK_IMAGE_ARNS not set',\n }\n}\n\nfunction probeFargate(config: WorkerConfig): EngineProbe {\n const { cluster, taskDefinition, stackTaskDefinitions, subnets } = config.fargate\n if (!cluster) {\n return { engine: 'fargate', available: false, reason: 'FARGATE_CLUSTER not set' }\n }\n if (!taskDefinition && !Object.keys(stackTaskDefinitions).length) {\n return {\n engine: 'fargate',\n available: false,\n reason: 'FARGATE_TASK_DEFINITION / FARGATE_STACK_TASK_DEFS not set',\n }\n }\n if (!subnets.length) {\n return { engine: 'fargate', available: false, reason: 'FARGATE_SUBNETS not set' }\n }\n return { engine: 'fargate', available: true }\n}\n\n/** Probe every engine against this host + config. Mock is always runnable. */\nexport function probeEngines(config: WorkerConfig): EngineProbe[] {\n return [\n { engine: 'mock', available: true },\n probeQemu(config),\n probeFirecracker(config),\n probeDocker(config),\n probeDockerSandbox(config),\n probeRemote(config),\n probeLambdaMicrovm(config),\n probeFargate(config),\n ]\n}\n\nexport function detectEngines(config: WorkerConfig): {\n engines: VmEngine[]\n defaultEngine: VmEngine\n} {\n const probes = probeEngines(config)\n\n for (const probe of probes) {\n if (probe.available) {\n logger.info({ engine: probe.engine }, 'micro-VM engine available')\n } else {\n logger.debug({ engine: probe.engine, reason: probe.reason }, 'micro-VM engine unavailable')\n }\n }\n\n const engines = probes.filter((p) => p.available).map((p) => p.engine)\n const defaultEngine = ENGINE_PRIORITY.find((engine) => engines.includes(engine)) ?? 'mock'\n return { engines, defaultEngine }\n}\n", "import logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmEngine,\n VmExecRequest,\n VmExecResult,\n VmFileWrite,\n VmRecord,\n VmRunResult,\n VmWriteFilesResult,\n} from '@multiplayer-app/builder-types'\nimport { MockExecutor } from './mock-executor'\nimport { QemuExecutor } from './qemu-executor'\nimport { FirecrackerExecutor } from './firecracker-executor'\nimport { DockerExecutor } from './docker-executor'\nimport { DockerSandboxExecutor } from './docker-sandbox-executor'\nimport { RemoteExecutor } from './remote-executor'\nimport { LambdaMicrovmExecutor } from './lambda-microvm-executor'\nimport { FargateExecutor } from './fargate-executor'\nimport { detectEngines } from './detect'\nimport type { Executor, SerialSource, VmHandle, VmSpec } from './types'\nimport type { WorkerConfig } from '../config'\n\nexport type { Executor, SerialSource, VmHandle, VmSpec } from './types'\n\n/**\n * Of the VM records sandbox says this workerId owns, the ones this executor isn't already\n * tracking in memory \u2014 i.e. the ones actually worth attempting to reattach. A plain reconnect\n * (network blip, not a real process restart) never loses in-memory state, so this naturally\n * comes back empty in that case.\n */\nexport function findNotAttachedVms(\n executor: Pick<Executor, 'get'>,\n records: VmRecord[],\n): VmRecord[] {\n return records.filter((record) => !executor.get(record.vmId))\n}\n\n/** Only called for engines `detectEngines` reported runnable, so prerequisites are already verified. */\nfunction createEngineExecutor(engine: VmEngine, config: WorkerConfig): Executor {\n switch (engine) {\n case 'mock':\n return new MockExecutor()\n case 'qemu':\n return new QemuExecutor(config.qemu)\n case 'firecracker':\n return new FirecrackerExecutor(config.firecracker)\n case 'docker':\n return new DockerExecutor(config.docker)\n case 'docker-sandbox':\n return new DockerSandboxExecutor(config.dockerSandbox)\n case 'remote':\n return new RemoteExecutor(config.remote)\n case 'lambda-microvm':\n return new LambdaMicrovmExecutor(config.lambdaMicrovm)\n case 'fargate':\n return new FargateExecutor(config.fargate)\n default:\n throw new Error(`unknown engine \"${engine as string}\"`)\n }\n}\n\n/**\n * Routes VM operations to per-engine executors. `create` picks the executor from\n * `spec.engine` (falling back to the worker default); every other operation is\n * routed to whichever executor owns the vmId.\n */\nexport class MultiEngineExecutor implements Executor {\n constructor(\n private readonly executors: Map<VmEngine, Executor>,\n readonly defaultEngine: VmEngine,\n ) {}\n\n get engines(): VmEngine[] {\n return [...this.executors.keys()]\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const engine = spec.engine ?? this.defaultEngine\n const executor = this.executors.get(engine)\n if (!executor) {\n throw new Error(\n `engine \"${engine}\" is not available on this worker (available: ${this.engines.join(', ')})`,\n )\n }\n const handle = await executor.create(spec)\n return { ...handle, engine }\n }\n\n pause(vmId: string): Promise<VmHandle> {\n return this.route(vmId).pause(vmId)\n }\n resume(vmId: string): Promise<VmHandle> {\n return this.route(vmId).resume(vmId)\n }\n stop(vmId: string): Promise<VmHandle> {\n return this.route(vmId).stop(vmId)\n }\n restore(vmId: string): Promise<VmHandle> {\n return this.route(vmId).restore(vmId)\n }\n destroy(vmId: string): Promise<void> {\n return this.route(vmId).destroy(vmId)\n }\n\n proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n return this.route(vmId).proxyHttp(vmId, request)\n }\n\n get(vmId: string): VmHandle | undefined {\n for (const executor of this.executors.values()) {\n const handle = executor.get(vmId)\n if (handle) return handle\n }\n return undefined\n }\n\n list(): VmHandle[] {\n return [...this.executors.values()].flatMap((executor) => executor.list())\n }\n\n getSerialSource(vmId: string): SerialSource | undefined {\n for (const executor of this.executors.values()) {\n if (executor.get(vmId)) return executor.getSerialSource?.(vmId)\n }\n return undefined\n }\n\n exec(vmId: string, request: VmExecRequest): Promise<VmExecResult> {\n const executor = this.route(vmId)\n if (!executor.exec) return Promise.reject(new Error('executor does not support guest exec'))\n return executor.exec(vmId, request)\n }\n\n writeFiles(vmId: string, files: VmFileWrite[]): Promise<VmWriteFilesResult> {\n const executor = this.route(vmId)\n if (!executor.writeFiles)\n return Promise.reject(new Error('executor does not support guest file writes'))\n return executor.writeFiles(vmId, files)\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const executor = this.route(vmId)\n if (!executor.onExit) throw new Error('executor does not support job run mode')\n executor.onExit(vmId, handler)\n }\n\n /**\n * Recover VMs sandbox says this workerId owns but that aren't currently tracked (a worker\n * restart, most likely). Runs in parallel \u2014 probing many VMs serially would needlessly\n * delay the first heartbeat, which reports capacity from `list()` and must reflect\n * reattached VMs to avoid sandbox overbooking this worker. Best-effort: failures are logged,\n * never thrown \u2014 a VM that can't be reattached just stays unavailable until something\n * touches it again (create/proxy/lifecycle), which already errors gracefully today.\n */\n async reattachAll(records: VmRecord[]): Promise<void> {\n const pending = findNotAttachedVms(this, records)\n if (!pending.length) return\n\n const results = await Promise.allSettled(\n pending.map(async (record) => {\n const executor = record.engine ? this.executors.get(record.engine) : undefined\n if (!executor)\n throw new Error(`engine \"${record.engine ?? 'unknown'}\" not available on this worker`)\n if (!executor.reattach)\n throw new Error(`engine \"${record.engine}\" does not support reattach`)\n const handle = await executor.reattach(record)\n if (!handle) throw new Error('resource no longer exists')\n }),\n )\n\n results.forEach((result, i) => {\n const vmId = pending[i].vmId\n if (result.status === 'fulfilled') logger.info({ vmId }, 'vm reattached')\n else\n logger.warn(\n { vmId, err: result.reason },\n 'vm reattach failed \u2014 staying unavailable until next touch',\n )\n })\n }\n\n private route(vmId: string): Executor {\n for (const executor of this.executors.values()) {\n if (executor.get(vmId)) return executor\n }\n throw new Error(`vm ${vmId} not found on this worker`)\n }\n}\n\n/**\n * Probes the host (KVM, HVF, binaries, images, ARNs) and registers every runnable engine,\n * defaulting to the most capable one. Per-VM engine selection comes from the create request.\n */\nexport function createExecutor(config: WorkerConfig): MultiEngineExecutor {\n const { engines, defaultEngine } = detectEngines(config)\n\n const executors = new Map<VmEngine, Executor>()\n for (const engine of engines) {\n executors.set(engine, createEngineExecutor(engine, config))\n }\n\n logger.info({ engines, defaultEngine }, 'micro-VM engines initialized')\n return new MultiEngineExecutor(executors, defaultEngine)\n}\n", "import os from 'os'\nimport { io, type Socket } from 'socket.io-client'\nimport logger from '@multiplayer-app/logger'\nimport type {\n CommandAck,\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmExecRequest,\n VmFileWrite,\n VmRecord,\n WorkerHeartbeat,\n} from '@multiplayer-app/builder-types'\nimport { WorkerEvent } from '@multiplayer-app/builder-types'\nimport type { WorkerConfig } from './config'\nimport { WORKER_VERSION } from './config'\nimport type { MultiEngineExecutor, VmSpec } from './executor'\n\nconst HEARTBEAT_INTERVAL_MS = 10_000\n// If sandbox never sends the reattach handshake (older version, edge case), start\n// heartbeating anyway rather than hanging the connection forever.\nconst REATTACH_FALLBACK_MS = 5_000\n\nfunction primaryIp(): string | undefined {\n for (const ifaces of Object.values(os.networkInterfaces())) {\n for (const iface of ifaces ?? []) {\n if (!iface.internal && iface.family === 'IPv4') return iface.address\n }\n }\n return undefined\n}\n\nfunction buildHeartbeat(config: WorkerConfig, executor: MultiEngineExecutor): WorkerHeartbeat {\n return {\n hostname: os.hostname(),\n ip: primaryIp(),\n region: config.region,\n version: WORKER_VERSION,\n engines: executor.engines,\n defaultEngine: executor.defaultEngine,\n capacity: {\n maxVms: config.maxVms,\n usedVms: executor.list().length,\n cpuCores: os.cpus().length,\n memMib: Math.round(os.totalmem() / (1024 * 1024)),\n },\n }\n}\n\nfunction wrap<TPayload, TResult>(\n handler: (payload: TPayload) => Promise<TResult>,\n): (payload: TPayload, callback: (ack: CommandAck<TResult>) => void) => void {\n return (payload, callback) => {\n handler(payload)\n .then((result) => callback({ ok: true, result }))\n .catch((error: Error) => {\n logger.error({ err: error }, 'command failed')\n callback({ ok: false, error: error.message })\n })\n }\n}\n\nfunction registerCommandHandlers(socket: Socket, executor: MultiEngineExecutor): void {\n socket.on(\n WorkerEvent.VM_CREATE,\n wrap(async (spec: VmSpec) => {\n const handle = await executor.create(spec)\n if (spec.runMode === 'job') {\n try {\n executor.onExit(spec.vmId, (result) =>\n socket.emit(WorkerEvent.VM_RUN_EXITED, { vmId: spec.vmId, ...result }),\n )\n } catch (error) {\n // The engine doesn't support job mode \u2014 don't leave an orphaned resource behind.\n await executor.destroy(spec.vmId).catch(() => { })\n throw error\n }\n }\n return handle\n }),\n )\n socket.on(\n WorkerEvent.VM_PAUSE,\n wrap(({ vmId }: { vmId: string }) => executor.pause(vmId)),\n )\n socket.on(\n WorkerEvent.VM_RESUME,\n wrap(({ vmId }: { vmId: string }) => executor.resume(vmId)),\n )\n socket.on(\n WorkerEvent.VM_STOP,\n wrap(({ vmId }: { vmId: string }) => executor.stop(vmId)),\n )\n socket.on(\n WorkerEvent.VM_RESTORE,\n wrap(({ vmId }: { vmId: string }) => executor.restore(vmId)),\n )\n socket.on(\n WorkerEvent.VM_DESTROY,\n wrap(({ vmId }: { vmId: string }) => executor.destroy(vmId)),\n )\n\n socket.on(\n WorkerEvent.PROXY_HTTP,\n wrap(\n ({\n vmId,\n ...request\n }: ProxyRequestDescriptor & { vmId: string }): Promise<ProxyResponseDescriptor> =>\n executor.proxyHttp(vmId, request),\n ),\n )\n\n socket.on(\n WorkerEvent.VM_EXEC,\n wrap(({ vmId, ...request }: VmExecRequest & { vmId: string }) => {\n if (!executor.exec) {\n return Promise.reject(new Error('executor does not support guest exec'))\n }\n return executor.exec(vmId, request)\n }),\n )\n\n socket.on(\n WorkerEvent.VM_WRITE_FILES,\n wrap(({ vmId, files }: { vmId: string; files: VmFileWrite[] }) => {\n if (!executor.writeFiles) {\n return Promise.reject(new Error('executor does not support guest file writes'))\n }\n return executor.writeFiles(vmId, files)\n }),\n )\n}\n\nexport function connectToSandbox(config: WorkerConfig, executor: MultiEngineExecutor): Socket {\n let assignedWorkerId: string | undefined\n const socket = io(config.sandboxUrl, {\n path: config.workerSocketPath,\n auth: (callback) =>\n callback({\n workerId: config.workerId,\n ...(assignedWorkerId ? { assignedWorkerId } : {}),\n ...(config.token ? { token: config.token } : {}),\n }),\n transports: ['websocket'],\n reconnection: true,\n })\n\n let heartbeatTimer: NodeJS.Timeout | undefined\n let reattachFallbackTimer: NodeJS.Timeout | undefined\n\n socket.on(WorkerEvent.ASSIGNED_ID, ({ workerId }: { workerId: string }) => {\n assignedWorkerId = workerId\n logger.info({ workerId: config.workerId, assignedWorkerId }, 'worker runtime ID assigned')\n })\n\n const sendHeartbeat = () => socket.emit(WorkerEvent.HEARTBEAT, buildHeartbeat(config, executor))\n\n function startHeartbeat(): void {\n if (heartbeatTimer) return // already running for this connection\n sendHeartbeat()\n heartbeatTimer = setInterval(sendHeartbeat, HEARTBEAT_INTERVAL_MS)\n }\n\n socket.on('connect', () => {\n logger.info(\n { workerId: config.workerId, assignedWorkerId, url: config.sandboxUrl },\n 'connected to sandbox',\n )\n\n // Sandbox emits REATTACH once, right after auth, listing any VMs it thinks this worker\n // still owns. Reattach them before the first heartbeat so capacity.usedVms is accurate \u2014\n // otherwise sandbox could schedule new VMs onto capacity that's actually already in use.\n socket.off(WorkerEvent.REATTACH)\n reattachFallbackTimer = setTimeout(() => {\n logger.warn(\n { workerId: config.workerId },\n 'no reattach handshake from sandbox \u2014 starting heartbeat anyway',\n )\n startHeartbeat()\n }, REATTACH_FALLBACK_MS)\n\n socket.once(WorkerEvent.REATTACH, (records: VmRecord[]) => {\n clearTimeout(reattachFallbackTimer)\n executor\n .reattachAll(records)\n .catch((error: Error) => logger.error({ err: error }, 'reattach batch failed'))\n .finally(() => {\n // Reattached job VMs may already have a result waiting (finished while this worker\n // was offline) or may still be running \u2014 either way, re-register so its eventual\n // VM_RUN_EXITED gets (re-)sent now that we're connected again.\n for (const record of records) {\n if (record.runMode !== 'job' || !executor.get(record.vmId)) continue\n try {\n executor.onExit(record.vmId, (result) =>\n socket.emit(WorkerEvent.VM_RUN_EXITED, { vmId: record.vmId, ...result }),\n )\n } catch (error) {\n logger.warn(\n { vmId: record.vmId, err: error },\n 'reattached job vm has no onExit support',\n )\n }\n }\n startHeartbeat()\n })\n })\n })\n\n socket.on('disconnect', (reason) => {\n logger.warn({ workerId: config.workerId, reason }, 'disconnected from sandbox')\n clearInterval(heartbeatTimer)\n clearTimeout(reattachFallbackTimer)\n heartbeatTimer = undefined\n socket.off(WorkerEvent.REATTACH)\n })\n\n socket.on('connect_error', (error) => {\n logger.error({\n err: error,\n sandboxUrl: config.sandboxUrl\n }, 'sandbox connection error')\n })\n\n registerCommandHandlers(socket, executor)\n\n return socket\n}\n", "import rfb from 'rfb2'\nimport type { Socket } from 'socket.io-client'\nimport logger from '@multiplayer-app/logger'\nimport {\n WorkerEvent,\n type VncFramePayload,\n type VncCopyFramePayload,\n type VncMousePayload,\n type VncKeyboardPayload,\n} from '@multiplayer-app/builder-types'\n\nfunction bgraToRgba(src: Buffer): Buffer {\n const dst = Buffer.allocUnsafe(src.length)\n for (let i = 0; i < src.length; i += 4) {\n dst[i] = src[i + 2]\n dst[i + 1] = src[i + 1]\n dst[i + 2] = src[i]\n dst[i + 3] = 0xff\n }\n return dst\n}\n\n/** Connects to a QEMU VNC server and relays frames upstream to the sandbox socket. */\nexport class VncRelay {\n private rfbc: ReturnType<typeof rfb.createConnection> & any = null\n private interval: ReturnType<typeof setInterval> | null = null\n private mouseHandler: ((e: VncMousePayload) => void) | null = null\n private keyHandler: ((e: VncKeyboardPayload) => void) | null = null\n\n constructor(\n private readonly vmId: string,\n private readonly host: string,\n private readonly port: number,\n private readonly socket: Socket,\n ) {}\n\n start(): void {\n this.rfbc = rfb.createConnection({ host: this.host, port: this.port, password: '' })\n const rfbc = this.rfbc\n\n rfbc.on('connect', () => {\n rfbc.autoUpdate = true\n this.socket.emit(WorkerEvent.VNC_INIT, {\n vmId: this.vmId,\n width: rfbc.width,\n height: rfbc.height,\n })\n this.interval = setInterval(() => {\n rfbc.requestUpdate(false, 0, 0, rfbc.width, rfbc.height)\n }, 300)\n })\n\n rfbc.on('rect', (rect: any) => {\n switch (rect.encoding) {\n case rfb.encodings.raw: {\n const frame: VncFramePayload = {\n vmId: this.vmId,\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n encoding: 'raw',\n data: bgraToRgba(rect.data),\n }\n this.socket.emit(WorkerEvent.VNC_FRAME, frame)\n break\n }\n case rfb.encodings.copyRect: {\n const frame: VncCopyFramePayload = {\n vmId: this.vmId,\n x: rect.x,\n y: rect.y,\n src: rect.src,\n width: rect.width,\n height: rect.height,\n }\n this.socket.emit(WorkerEvent.VNC_COPY_FRAME, frame)\n break\n }\n }\n })\n\n // Guest display init/resize (e.g. QEMU placeholder 640x480 \u2192 guest fb 1280x800).\n // rfb2 updates rfbc.width/height itself; re-announce dimensions and pull a\n // full frame so browsers aren't stuck on the pre-boot placeholder.\n rfbc.on('resize', (rect: { width: number; height: number }) => {\n logger.info(\n { vmId: this.vmId, width: rect.width, height: rect.height },\n '[VNC] desktop resized',\n )\n this.socket.emit(WorkerEvent.VNC_INIT, {\n vmId: this.vmId,\n width: rect.width,\n height: rect.height,\n })\n rfbc.requestUpdate(false, 0, 0, rect.width, rect.height)\n })\n\n rfbc.on('error', (err: Error) => logger.error({ vmId: this.vmId, err }, '[VNC] RFB error'))\n\n this.mouseHandler = (e: VncMousePayload) => {\n if (e.vmId === this.vmId) rfbc.pointerEvent(e.x, e.y, e.button)\n }\n this.keyHandler = (e: VncKeyboardPayload) => {\n if (e.vmId === this.vmId) rfbc.keyEvent(e.keyCode, e.isDown)\n }\n this.socket.on(WorkerEvent.VNC_MOUSE, this.mouseHandler)\n this.socket.on(WorkerEvent.VNC_KEYBOARD, this.keyHandler)\n logger.info({ vmId: this.vmId, port: this.port }, '[VNC] relay started')\n }\n\n destroy(): void {\n if (this.interval) clearInterval(this.interval)\n if (this.mouseHandler) this.socket.off(WorkerEvent.VNC_MOUSE, this.mouseHandler)\n if (this.keyHandler) this.socket.off(WorkerEvent.VNC_KEYBOARD, this.keyHandler)\n try {\n this.rfbc?.end()\n } catch {}\n this.rfbc = null\n logger.info({ vmId: this.vmId }, '[VNC] relay destroyed')\n }\n}\n", "import net from 'net'\nimport type { ChildProcess } from 'child_process'\nimport type { Socket } from 'socket.io-client'\nimport logger from '@multiplayer-app/logger'\nimport { WorkerEvent, type TerminalInputPayload } from '@multiplayer-app/builder-types'\nimport type { SerialSource } from '../executor/types'\n\n/** Relays VM serial console data upstream to the sandbox socket. */\nexport class SerialRelay {\n private conn: net.Socket | null = null\n private inputHandler: ((e: TerminalInputPayload) => void) | null = null\n\n constructor(\n private readonly vmId: string,\n private readonly source: SerialSource,\n private readonly socket: Socket,\n ) {}\n\n connect(): void {\n if (this.source.type === 'tcp') {\n this.connectTcp()\n } else {\n this.connectPipe()\n }\n\n this.inputHandler = (e: TerminalInputPayload) => {\n if (e.vmId !== this.vmId) return\n if (this.source.type === 'tcp' && this.conn) {\n this.conn.write(e.data)\n } else if (this.source.type === 'pipe') {\n const proc = (this.source as { type: 'pipe'; process: ChildProcess }).process\n proc.stdin?.write(e.data)\n }\n }\n this.socket.on(WorkerEvent.TERMINAL_INPUT, this.inputHandler)\n }\n\n private connectTcp(): void {\n const { host, port } = this.source as { type: 'tcp'; host: string; port: number }\n const attempt = () => {\n const sock = net.createConnection(port, host)\n sock.once('connect', () => {\n this.conn = sock\n logger.info({ vmId: this.vmId, port }, '[Serial] TCP connected')\n sock.on('data', (d: Buffer) =>\n this.socket.emit(WorkerEvent.TERMINAL_DATA, { vmId: this.vmId, data: d }),\n )\n sock.on('end', () => logger.info({ vmId: this.vmId }, '[Serial] TCP ended'))\n sock.on('error', (err) => logger.error({ vmId: this.vmId, err }, '[Serial] TCP error'))\n })\n sock.once('error', () => setTimeout(attempt, 1_000))\n }\n attempt()\n }\n\n private connectPipe(): void {\n const { process: proc } = this.source as { type: 'pipe'; process: ChildProcess }\n proc.stdout?.on('data', (d: Buffer) =>\n this.socket.emit(WorkerEvent.TERMINAL_DATA, { vmId: this.vmId, data: d }),\n )\n proc.stderr?.on('data', (d: Buffer) =>\n this.socket.emit(WorkerEvent.TERMINAL_DATA, { vmId: this.vmId, data: d }),\n )\n }\n\n destroy(): void {\n if (this.inputHandler) this.socket.off(WorkerEvent.TERMINAL_INPUT, this.inputHandler)\n try {\n this.conn?.destroy()\n } catch {}\n this.conn = null\n logger.info({ vmId: this.vmId }, '[Serial] relay destroyed')\n }\n}\n", "import type { Socket } from 'socket.io-client'\nimport type { MultiEngineExecutor } from './executor'\nimport { VncRelay } from './services/vnc-relay'\nimport { SerialRelay } from './services/serial-relay'\n\n/**\n * Wires up VNC and serial relays for any executor that exposes console endpoints (QEMU: VNC +\n * serial TCP ports; Firecracker: serial via process stdio pipe). All media (frames, terminal\n * data) flows through the sandbox socket to browsers \u2014 the worker never accepts inbound\n * connections from the internet. Wraps `executor.create`/`destroy` in place.\n */\nexport function attachConsoleRelays(executor: MultiEngineExecutor, sandboxSocket: Socket): void {\n const relays = new Map<string, { vnc?: VncRelay; serial?: SerialRelay }>()\n\n const originalCreate = executor.create.bind(executor)\n executor.create = async (spec) => {\n const handle = await originalCreate(spec)\n const entry: { vnc?: VncRelay; serial?: SerialRelay } = {}\n\n if (handle.vncPort) {\n const vnc = new VncRelay(handle.vmId, '127.0.0.1', handle.vncPort, sandboxSocket)\n vnc.start()\n entry.vnc = vnc\n }\n\n const serialSource = handle.serialPort\n ? { type: 'tcp' as const, host: '127.0.0.1', port: handle.serialPort }\n : executor.getSerialSource?.(handle.vmId)\n if (serialSource) {\n const serial = new SerialRelay(handle.vmId, serialSource, sandboxSocket)\n serial.connect()\n entry.serial = serial\n }\n\n if (entry.vnc || entry.serial) relays.set(handle.vmId, entry)\n return handle\n }\n\n const originalDestroy = executor.destroy.bind(executor)\n executor.destroy = async (vmId) => {\n const entry = relays.get(vmId)\n entry?.vnc?.destroy()\n entry?.serial?.destroy()\n relays.delete(vmId)\n return originalDestroy(vmId)\n }\n}\n", "import { execFile } from 'child_process'\nimport { promisify } from 'util'\nimport type { WorkerConfig } from './config'\nimport { availableStacks, hostArch, PUBLISHED_IMAGE_STACKS, pullImages } from './images'\nimport { version as WORKER_VERSION } from '../package.json'\n\nconst execFileAsync = promisify(execFile)\n\nexport function artifactImageLocation(env: NodeJS.ProcessEnv = process.env): string | undefined {\n const bucket = env.S3_BUCKET_ARTIFACTS?.trim()\n if (!bucket) return undefined\n if (bucket.includes('/') || bucket.includes('://')) {\n throw new Error('S3_BUCKET_ARTIFACTS must contain only the bucket name (no scheme or path)')\n }\n const version = env.NODE_ENV === 'development' || env.BUILDER_ENV === 'local'\n ? 'local'\n : WORKER_VERSION\n return `s3://${bucket}/${version}/qemu`\n}\n\nfunction allStacksAvailable(imagesDir: string): boolean {\n const available = new Set(availableStacks(imagesDir))\n return PUBLISHED_IMAGE_STACKS.every((stack) => available.has(stack))\n}\n\nasync function dockerAvailable(bin: string): Promise<boolean> {\n try {\n await execFileAsync(bin, ['info'])\n return true\n } catch {\n return false\n }\n}\n\nasync function dockerImageExists(bin: string, image: string): Promise<boolean> {\n try {\n await execFileAsync(bin, ['image', 'inspect', image])\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Materialize remotely published images before engine detection.\n *\n * S3_BUCKET_ARTIFACTS is the artifact bucket name. The worker derives the\n * environment/version and runner prefix; pullImages appends\n * <arch>/<stack>/<file>.\n * Registry-backed Docker images are pulled whenever the configured prefix is\n * a qualified repository (contains a slash), while local development prefixes\n * continue to require locally built images.\n */\nexport async function prepareWorkerImages(\n config: WorkerConfig,\n env: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n const vmImagesUrl = artifactImageLocation(env)\n const refreshVmImages = env.VM_IMAGES_REFRESH === 'true'\n if (vmImagesUrl) {\n const destinations = new Set([config.qemu.imagesDir, config.firecracker.imagesDir])\n for (const imagesDir of destinations) {\n if (!refreshVmImages && allStacksAvailable(imagesDir)) continue\n await pullImages({\n location: vmImagesUrl,\n arch: hostArch(),\n endpoint: env.S3_ARTIFACTS_ENDPOINT,\n }, imagesDir)\n }\n }\n\n const shouldPullDocker = env.DOCKER_PULL_IMAGES === 'true'\n || (env.DOCKER_PULL_IMAGES !== 'false' && config.docker.imagePrefix.includes('/'))\n if (!shouldPullDocker || !await dockerAvailable(config.docker.bin)) return\n\n for (const stack of PUBLISHED_IMAGE_STACKS) {\n const image = config.docker.stackImages[stack]\n ?? `${config.docker.imagePrefix}-${stack}:${config.docker.imageTag}`\n if (!await dockerImageExists(config.docker.bin, image)) {\n await execFileAsync(config.docker.bin, ['pull', image])\n }\n }\n}\n", "import http, { type IncomingMessage, type Server, type ServerResponse } from 'http'\n\nexport interface SandboxHealthServerOptions {\n host: string\n port: number\n pathPrefix: string\n isReady: () => boolean\n}\n\n/** Local probe server under API_PREFIX: /healthz is liveness; /health is readiness. */\nexport async function startSandboxHealthServer(\n options: SandboxHealthServerOptions,\n): Promise<Server> {\n const server = http.createServer((req: IncomingMessage, res: ServerResponse) => {\n const pathname = new URL(req.url ?? '/', 'http://localhost').pathname\n if (pathname === `${options.pathPrefix}/healthz`) {\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ ok: true, status: 'alive' }))\n return\n }\n if (pathname === `${options.pathPrefix}/health`) {\n const ready = options.isReady()\n res.writeHead(ready ? 200 : 503, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ ok: ready, status: ready ? 'ready' : 'not-ready' }))\n return\n }\n res.writeHead(404, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ ok: false, error: 'not found' }))\n })\n\n await new Promise<void>((resolve, reject) => {\n server.listen(options.port, options.host, resolve)\n server.once('error', reject)\n })\n return server\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n/* eslint-disable no-console -- console output is the CLI's user interface */\n// Worker CLI. Published as the global `sandbox` executable and also available locally via\n// `pnpm --filter @multiplayer-app/sandbox run cli -- <args>`.\nimport 'dotenv/config'\nimport { Command } from 'commander'\nimport { version as WORKER_VERSION } from '../package.json'\nimport { loadWorkerConfigFromEnv } from './config'\nimport { createExecutor } from './executor'\nimport { probeEngines } from './executor/detect'\nimport { defaultImagesDir, hostArch, pullImages, pushImages } from './images'\nimport { connectToSandbox } from './socket-client'\nimport { attachConsoleRelays } from './console-relays'\nimport { artifactImageLocation, prepareWorkerImages } from './prepare-images'\nimport { startSandboxHealthServer } from './health-server'\nimport logger from '@multiplayer-app/logger'\n\nconst program = new Command()\n\nprogram\n .name('sandbox')\n .description('Run and manage a Multiplayer sandbox worker')\n .version(WORKER_VERSION)\n\nprogram\n .command('start')\n .description('start a worker and connect it to the sandbox control plane')\n .option('--token <token>', 'worker authentication token (env: WORKER_TOKEN)')\n .option('--worker-id <id>', 'worker pool/authentication ID (env: WORKER_ID; default: hostname)')\n .option('--sandbox-url <url>', 'control-plane base URL (env: SANDBOX_URL; default: https://api.sandbox.filingramp.com/v0)')\n .option('--max-vms <count>', 'maximum concurrent VMs (env: MAX_VMS)')\n .action(async (opts: { token?: string; workerId?: string; sandboxUrl?: string; maxVms?: string }) => {\n const config = loadWorkerConfigFromEnv({\n ...process.env,\n ...(opts.token ? { WORKER_TOKEN: opts.token } : {}),\n ...(opts.workerId ? { WORKER_ID: opts.workerId } : {}),\n ...(opts.sandboxUrl ? { SANDBOX_URL: opts.sandboxUrl } : {}),\n ...(opts.maxVms ? { MAX_VMS: opts.maxVms } : {}),\n })\n const socketRef: { current?: ReturnType<typeof connectToSandbox> } = {}\n const healthServer = await startSandboxHealthServer({\n host: config.healthHost,\n port: config.healthPort,\n pathPrefix: config.healthPathPrefix,\n isReady: () => socketRef.current?.connected === true,\n })\n await prepareWorkerImages(config)\n const executor = createExecutor(config)\n const socket = connectToSandbox(config, executor)\n socketRef.current = socket\n attachConsoleRelays(executor, socket)\n\n let stopping = false\n const stop = async (signal: string): Promise<void> => {\n if (stopping) return\n stopping = true\n console.log(`\\n${signal} received; shutting down sandbox worker...`)\n socket.disconnect()\n healthServer.close()\n const results = await Promise.allSettled(executor.list().map((vm) => executor.destroy(vm.vmId)))\n const failed = results.filter((result) => result.status === 'rejected')\n if (failed.length) console.error(`Failed to destroy ${failed.length} VM(s) during shutdown`)\n process.exit(failed.length ? 1 : 0)\n }\n\n process.once('SIGINT', () => { void stop('SIGINT') })\n process.once('SIGTERM', () => { void stop('SIGTERM') })\n\n logger.info(`Starting sandbox worker ${config.workerId} \u2192 ${config.sandboxUrl}`)\n // Socket.IO's reconnect timers keep the process alive until a termination signal arrives.\n })\n\nprogram\n .command('detect')\n .description('probe this host and report which micro-VM engines it can run')\n .action(() => {\n const probes = probeEngines(loadWorkerConfigFromEnv({ ...process.env, WORKER_ID: '-', WORKER_TOKEN: '-' }))\n for (const probe of probes) {\n const status = probe.available ? 'available' : `unavailable \u2014 ${probe.reason}`\n console.log(`${probe.engine.padEnd(15)} ${status}`)\n }\n })\n\nconst images = program\n .command('images')\n .description('manage engine base images (kernel + initramfs for QEMU/Firecracker)')\n\nimages\n .command('pull')\n .description('download per-stack base images from S3 or an HTTPS mirror into the standard location')\n .requiredOption('--from <location>', 's3://bucket[/prefix] or https:// base URL (default derived from S3_BUCKET_ARTIFACTS)', artifactImageLocation())\n .option('--arch <arch>', 'image architecture', hostArch())\n .option('--stack <stack...>', 'stacks to pull (default: all)')\n .option('--dest <dir>', 'destination directory (default: ~/.multiplayer/vm-images/<arch>)')\n .option('--endpoint <url>', 'custom S3 endpoint, e.g. a MinIO URL (env: S3_ARTIFACTS_ENDPOINT)', process.env.S3_ARTIFACTS_ENDPOINT)\n .action(async (opts: { from: string; arch: string; stack?: string[]; dest?: string; endpoint?: string }) => {\n const dest = opts.dest ?? defaultImagesDir(opts.arch)\n const files = await pullImages({ location: opts.from, arch: opts.arch, stacks: opts.stack, endpoint: opts.endpoint }, dest)\n for (const file of files) console.log(`pulled ${file}`)\n console.log('\\nbase images ready \u2014 \"sandbox detect\" shows which engines they enable')\n })\n\nimages\n .command('push')\n .description('upload locally built per-stack base images (scripts/setup-vm-images.sh) to S3')\n .requiredOption('--to <location>', 's3://bucket[/prefix] (default derived from S3_BUCKET_ARTIFACTS)', artifactImageLocation())\n .option('--arch <arch>', 'image architecture', hostArch())\n .option('--stack <stack...>', 'stacks to push (default: all found locally)')\n .option('--src <dir>', 'source directory (default: ~/.multiplayer/vm-images/<arch>)')\n .option('--endpoint <url>', 'custom S3 endpoint, e.g. a MinIO URL (env: S3_ARTIFACTS_ENDPOINT)', process.env.S3_ARTIFACTS_ENDPOINT)\n .action(async (opts: { to: string; arch: string; stack?: string[]; src?: string; endpoint?: string }) => {\n const src = opts.src ?? defaultImagesDir(opts.arch)\n const uploaded = await pushImages({ location: opts.to, arch: opts.arch, stacks: opts.stack, endpoint: opts.endpoint }, src)\n for (const uri of uploaded) console.log(`pushed ${uri}`)\n })\n\nprogram.parseAsync().catch((error: Error) => {\n console.error(`Error: ${error.message}`)\n process.exit(1)\n})\n", "{\n \"name\": \"@multiplayer-app/sandbox\",\n \"version\": \"7.0.1\",\n \"description\": \"Sandbox worker library and CLI (Docker, QEMU, Firecracker, AWS Lambda MicroVM, Fargate)\",\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"require\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n }\n },\n \"bin\": {\n \"sandbox\": \"dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\",\n \"registry\": \"https://registry.npmjs.org/\"\n },\n \"scripts\": {\n \"build\": \"tsc --build --force && node scripts/bundle.mjs\",\n \"dev\": \"nodemon --watch src --watch scripts/bundle.mjs --watch package.json --ext ts,mjs,json --exec \\\"pnpm run build && pnpm run worker:start\\\"\",\n \"clean\": \"rm -rf ./dist tsconfig.tsbuildinfo\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"eslint src/**/*.ts --config ../../eslint.config.js\",\n \"images:build\": \"bash scripts/build-base-images.sh\",\n \"images:publish:local\": \"bash scripts/publish-base-images-local.sh\",\n \"images:upload:local\": \"SKIP_BUILD=1 bash scripts/publish-base-images-local.sh\",\n \"docker:build\": \"docker build -f Dockerfile -t multiplayer-sandbox-worker:local ../..\",\n \"start\": \"node dist/cli.js\",\n \"worker:start\": \"node dist/cli.js start\",\n \"test\": \"tsc --build --force && node --test 'dist/**/*.test.js'\",\n \"prepublishOnly\": \"pnpm run build\",\n \"postversion\": \"git commit -m \\\"sandbox v$npm_package_version\\\" -- package.json && git tag \\\"sandbox-v$npm_package_version\\\" && git push && git push --tags\"\n },\n \"dependencies\": {\n \"@aws-sdk/client-ec2\": \"^3.1087.0\",\n \"@aws-sdk/client-ecs\": \"^3.1087.0\",\n \"@aws-sdk/client-lambda-microvms\": \"^3.1079.0\",\n \"@aws-sdk/client-s3\": \"^3.1079.0\",\n \"bunyan\": \"1.8.15\",\n \"commander\": \"^14.0.0\",\n \"dotenv\": \"^17.2.3\",\n \"rfb2\": \"^0.2.2\",\n \"socket.io-client\": \"4.8.3\"\n },\n \"devDependencies\": {\n \"@multiplayer-app/builder-types\": \"workspace:*\",\n \"@multiplayer-app/logger\": \"workspace:*\",\n \"@types/node\": \"^25.8.0\",\n \"esbuild\": \"^0.25.12\",\n \"nodemon\": \"3.1.14\",\n \"typescript\": \"^6.0.3\"\n }\n}\n", "import os from 'os'\nimport path from 'path'\nimport { version as WORKER_VERSION } from '../package.json'\nimport { defaultImagesDir } from './images'\n\nexport { WORKER_VERSION }\n\nexport interface RemoteWorkerConfig {\n agentUrl: string\n authToken?: string\n}\n\nexport interface FirecrackerWorkerConfig {\n bin: string\n imagesDir: string\n kernelPath?: string\n initrdPath?: string\n vmDataPath: string\n}\n\nexport interface QemuWorkerConfig {\n bin: string\n imagesDir: string\n kernelPath?: string\n initrdPath?: string\n vmDataPath: string\n portRangeStart: number\n portRangeEnd: number\n accel: string\n cpu: string\n machine: string\n}\n\nexport interface LambdaMicrovmWorkerConfig {\n region?: string\n imageArn: string\n stackImageArns: Record<string, string>\n ingressConnectorArns?: string[]\n egressConnectorArns?: string[]\n executionRoleArn?: string\n maxIdleSeconds: number\n suspendedDurationSeconds: number\n maximumDurationInSeconds: number\n}\n\nexport interface DockerWorkerConfig {\n bin: string\n imagePrefix: string\n imageTag: string\n stackImages: Record<string, string>\n network?: string\n portRangeStart: number\n portRangeEnd: number\n guestPort: number\n}\n\nexport interface DockerSandboxWorkerConfig {\n bin: string\n imagePrefix: string\n imageTag: string\n /** Fully-qualified `sbx template load`ed ref overrides, keyed by stack. */\n stackTemplates: Record<string, string>\n /** In-sandbox start command per stack \u2014 `sbx create shell` doesn't run the image's own CMD. */\n stackAgentCommands: Record<string, string>\n workspaceRoot: string\n portRangeStart: number\n portRangeEnd: number\n guestPort: number\n minMemoryMib: number\n}\n\nexport interface FargateWorkerConfig {\n region?: string\n cluster: string\n taskDefinition?: string\n stackTaskDefinitions: Record<string, string>\n subnets: string[]\n securityGroups?: string[]\n assignPublicIp: boolean\n guestPort: number\n startTimeoutMs: number\n}\n\nexport interface WorkerConfig {\n /** Credential/pool identity. Multiple instances may intentionally share it. */\n workerId: string\n token?: string\n sandboxUrl: string\n workerSocketPath: string\n maxVms: number\n healthHost: string\n healthPort: number\n healthPathPrefix: string\n region?: string\n remote: RemoteWorkerConfig\n firecracker: FirecrackerWorkerConfig\n qemu: QemuWorkerConfig\n docker: DockerWorkerConfig\n dockerSandbox: DockerSandboxWorkerConfig\n lambdaMicrovm: LambdaMicrovmWorkerConfig\n fargate: FargateWorkerConfig\n}\n\n/** Format: \"node:<value>,python:<value>\" \u2014 per-stack overrides (MicroVM image ARNs, Fargate task defs). */\nfunction parseStackMap(raw: string | undefined): Record<string, string> {\n const map: Record<string, string> = {}\n if (!raw) return map\n for (const pair of raw.split(',')) {\n const idx = pair.indexOf(':')\n if (idx === -1) continue\n const stack = pair.slice(0, idx).trim()\n const arn = pair.slice(idx + 1).trim()\n if (stack && arn) map[stack] = arn\n }\n return map\n}\n\nfunction parseArnList(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined\n const arns = raw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n return arns.length ? arns : undefined\n}\n\nfunction resolveSandboxEndpoint(rawUrl: string): {\n sandboxUrl: string\n workerSocketPath: string\n} {\n const url = new URL(rawUrl)\n const basePath = url.pathname.replace(/\\/+$/, '')\n return {\n // Socket.IO treats a URL pathname as a namespace, so connect to the origin\n // and pass the derived HTTP transport path separately. SANDBOX_URL's pathname is the\n // sole source of truth for the socket path \u2014 it must include whatever base the control\n // plane expects (e.g. \"/v0/gapi\" or \"/internal/v0/gapi\"), and \"/workers/ws\" is appended.\n sandboxUrl: url.origin,\n workerSocketPath: `${basePath}/workers/ws`,\n }\n}\n\nexport function loadWorkerConfigFromEnv(env: NodeJS.ProcessEnv = process.env): WorkerConfig {\n const workerId = env.WORKER_ID?.trim() || os.hostname()\n const token = env.WORKER_TOKEN?.trim() || undefined\n const sandboxEndpoint = resolveSandboxEndpoint(\n env.SANDBOX_URL ?? 'https://api.sandbox.filingramp.com/v0/gapi',\n )\n\n return {\n workerId,\n token,\n sandboxUrl: sandboxEndpoint.sandboxUrl,\n workerSocketPath: sandboxEndpoint.workerSocketPath,\n maxVms: Number(env.MAX_VMS) || 10,\n healthHost: env.SANDBOX_HEALTH_HOST ?? '0.0.0.0',\n healthPort: Number(env.SANDBOX_HEALTH_PORT) || 3000,\n healthPathPrefix: (env.API_PREFIX ?? '/v0/api').replace(/\\/+$/, ''),\n region: env.WORKER_REGION,\n remote: {\n // No default: an unset AGENT_URL means the remote engine is not configured on this worker\n agentUrl: env.AGENT_URL ?? '',\n authToken: env.AGENT_TOKEN,\n },\n firecracker: {\n bin: env.FIRECRACKER_BIN ?? 'firecracker',\n // Per-stack base images (<imagesDir>/<stack>/vmlinuz + initramfs.img) from\n // `worker-cli images pull` / setup-vm-images.sh; engine detection checks\n // existence, so missing images just disable the engine.\n imagesDir: env.FIRECRACKER_IMAGES_DIR ?? env.VM_IMAGES_DIR ?? defaultImagesDir(),\n // Explicit single-image override, applied to every stack when both are set\n kernelPath: env.FIRECRACKER_KERNEL,\n initrdPath: env.FIRECRACKER_INITRD,\n vmDataPath: env.FIRECRACKER_VM_DATA ?? path.join(os.tmpdir(), 'firecracker-vms'),\n },\n lambdaMicrovm: {\n region: env.MICROVM_AWS_REGION ?? env.AWS_REGION,\n imageArn: env.MICROVM_IMAGE_ARN ?? '',\n stackImageArns: parseStackMap(env.MICROVM_STACK_IMAGE_ARNS),\n ingressConnectorArns: parseArnList(env.MICROVM_INGRESS_CONNECTORS),\n egressConnectorArns: parseArnList(env.MICROVM_EGRESS_CONNECTORS),\n executionRoleArn: env.MICROVM_EXECUTION_ROLE_ARN,\n // 0 disables auto-suspend; the sandbox drives pause/resume explicitly by default\n maxIdleSeconds: Number(env.MICROVM_MAX_IDLE_SECONDS ?? 900),\n suspendedDurationSeconds: Number(env.MICROVM_SUSPENDED_DURATION_SECONDS ?? 28_800),\n maximumDurationInSeconds: Number(env.MICROVM_MAX_DURATION_SECONDS ?? 28_800),\n },\n fargate: {\n region: env.FARGATE_AWS_REGION ?? env.AWS_REGION,\n cluster: env.FARGATE_CLUSTER ?? '',\n taskDefinition: env.FARGATE_TASK_DEFINITION,\n // Per-stack task definitions: \"node:builder-node:3,python:builder-python:1\"\n stackTaskDefinitions: parseStackMap(env.FARGATE_STACK_TASK_DEFS),\n subnets:\n env.FARGATE_SUBNETS?.split(',')\n .map((s) => s.trim())\n .filter(Boolean) ?? [],\n securityGroups: env.FARGATE_SECURITY_GROUPS?.split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n // ENABLED when the worker runs outside the task VPC (proxies to the task's public IP)\n assignPublicIp: env.FARGATE_ASSIGN_PUBLIC_IP === 'true',\n guestPort: Number(env.FARGATE_GUEST_PORT) || 8080,\n startTimeoutMs: Number(env.FARGATE_START_TIMEOUT_MS) || 180_000,\n },\n docker: {\n bin: env.DOCKER_BIN ?? 'docker',\n // Local images from `scripts/setup-docker-images.sh`: <imagePrefix>-<stack>:<imageTag>\n imagePrefix: env.DOCKER_IMAGE_PREFIX ?? 'multiplayer-builder-vm',\n imageTag: env.DOCKER_IMAGE_TAG ?? 'local',\n stackImages: parseStackMap(env.DOCKER_STACK_IMAGES),\n network: env.DOCKER_NETWORK,\n portRangeStart: Number(env.DOCKER_PORT_MIN) || 9100,\n portRangeEnd: Number(env.DOCKER_PORT_MAX) || 9199,\n guestPort: Number(env.DOCKER_GUEST_PORT) || 8080,\n },\n dockerSandbox: {\n bin: env.SBX_BIN ?? 'sbx',\n // Bridged from the same local images `docker` (imagePrefix-imageTag) already uses \u2014\n // `docker save` + `sbx template load`, see docker-sandbox-executor.ts.\n imagePrefix: env.SBX_IMAGE_PREFIX ?? env.DOCKER_IMAGE_PREFIX ?? 'multiplayer-builder-vm',\n imageTag: env.SBX_IMAGE_TAG ?? env.DOCKER_IMAGE_TAG ?? 'local',\n stackTemplates: parseStackMap(env.SBX_STACK_TEMPLATES),\n // `sbx create shell` doesn't run the image's own CMD, so the engine launches\n // it explicitly \u2014 defaults match each Dockerfile's own WORKDIR /app + CMD.\n stackAgentCommands: {\n node: 'node app.js',\n python: 'python app.py',\n static: 'node app.js',\n ...parseStackMap(env.SBX_STACK_AGENT_COMMANDS),\n },\n workspaceRoot: env.SBX_WORKSPACE_DIR ?? path.join(os.tmpdir(), 'sbx-vms'),\n portRangeStart: Number(env.SBX_PORT_MIN) || 9200,\n portRangeEnd: Number(env.SBX_PORT_MAX) || 9299,\n guestPort: Number(env.SBX_GUEST_PORT) || 8080,\n // sbx rejects sandboxes below 1 GiB memory.\n minMemoryMib: Number(env.SBX_MIN_MEMORY_MIB) || 1024,\n },\n qemu: {\n bin: env.QEMU_BIN ?? 'qemu-system-aarch64',\n // Per-stack base images (<imagesDir>/<stack>/vmlinuz + initramfs.img) from\n // `worker-cli images pull` / setup-vm-images.sh; engine detection checks\n // existence, so missing images just disable the engine.\n imagesDir: env.QEMU_IMAGES_DIR ?? env.VM_IMAGES_DIR ?? defaultImagesDir(),\n // Explicit single-image override, applied to every stack when both are set\n kernelPath: env.QEMU_KERNEL,\n initrdPath: env.QEMU_INITRD,\n vmDataPath: env.QEMU_VM_DATA ?? path.join(os.tmpdir(), 'qemu-vms'),\n portRangeStart: Number(env.QEMU_PORT_MIN) || 9000,\n portRangeEnd: Number(env.QEMU_PORT_MAX) || 9999,\n // Accelerator: hvf (macOS host), kvm (Linux + /dev/kvm), tcg (software, any host \u2014 slow)\n accel: env.QEMU_ACCEL ?? (process.platform === 'darwin' ? 'hvf' : 'kvm'),\n // CPU model: host requires hvf/kvm; max is best for tcg on aarch64; qemu64 for tcg x86_64\n cpu: env.QEMU_CPU ?? 'host',\n // Machine type: virt (aarch64), q35 (x86_64)\n machine: env.QEMU_MACHINE ?? 'virt',\n },\n }\n}\n", "import fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport { pipeline } from 'stream/promises'\nimport { Readable } from 'stream'\nimport { VM_STACKS, type VmStack } from '@multiplayer-app/builder-types'\n\n/** Files that make up one stack's base image (built by scripts/setup-vm-images.sh). */\nexport const IMAGE_FILES = ['vmlinuz', 'initramfs.img'] as const\n/** Stacks included in the published base-image catalog; `generic` remains a local fallback only. */\nexport const PUBLISHED_IMAGE_STACKS = VM_STACKS.filter((stack) => stack !== 'generic')\n\n/** Normalize Node's process.arch to the uname-style names used in image paths. */\nexport function hostArch(): string {\n switch (process.arch) {\n case 'arm64': return 'aarch64'\n case 'x64': return 'x86_64'\n default: return process.arch\n }\n}\n\n/** Default local image directory \u2014 the same location scripts/setup-vm-images.sh writes to. */\nexport function defaultImagesDir(arch: string = hostArch()): string {\n return path.join(os.homedir(), '.multiplayer', 'vm-images', arch)\n}\n\n/** Kernel + initrd for one stack under an images dir, or undefined if incomplete. */\nexport function resolveStackImages(imagesDir: string, stack: string): { kernelPath: string; initrdPath: string } | undefined {\n const kernelPath = path.join(imagesDir, stack, 'vmlinuz')\n const initrdPath = path.join(imagesDir, stack, 'initramfs.img')\n return fs.existsSync(kernelPath) && fs.existsSync(initrdPath) ? { kernelPath, initrdPath } : undefined\n}\n\n/** Stacks that have a complete base image under an images dir. */\nexport function availableStacks(imagesDir: string): VmStack[] {\n return VM_STACKS.filter((stack) => resolveStackImages(imagesDir, stack) !== undefined)\n}\n\nexport interface ImageSourceOptions {\n /** s3://bucket[/prefix] or http(s):// base URL holding <arch>/<stack>/vmlinuz + initramfs.img */\n location: string\n arch: string\n /** Stacks to transfer (default: all known stacks). */\n stacks?: readonly string[]\n /** Custom S3 endpoint (MinIO, etc.); implies path-style addressing. */\n endpoint?: string\n}\n\nfunction parseS3Uri(uri: string): { bucket: string; prefix: string } {\n const match = /^s3:\\/\\/([^/]+)\\/?(.*)$/.exec(uri)\n if (!match) throw new Error(`invalid S3 URI \"${uri}\" \u2014 expected s3://bucket[/prefix]`)\n return { bucket: match[1], prefix: match[2].replace(/\\/+$/, '') }\n}\n\nfunction s3Key(prefix: string, arch: string, stack: string, file: string): string {\n return [prefix, arch, stack, file].filter(Boolean).join('/')\n}\n\nasync function makeS3Client(endpoint?: string) {\n const { S3Client } = await import('@aws-sdk/client-s3')\n return new S3Client({\n ...(endpoint ? { endpoint, forcePathStyle: true } : {}),\n ...(process.env.AWS_REGION ? {} : { region: 'us-east-1' }),\n // aws-chunked checksum streaming breaks older S3-compatible stores (MinIO)\n requestChecksumCalculation: 'WHEN_REQUIRED',\n })\n}\n\nasync function downloadFromS3(opts: ImageSourceOptions, stack: string, file: string, dest: string): Promise<void> {\n const { GetObjectCommand } = await import('@aws-sdk/client-s3')\n const { bucket, prefix } = parseS3Uri(opts.location)\n const client = await makeS3Client(opts.endpoint)\n const key = s3Key(prefix, opts.arch, stack, file)\n const response = await client.send(new GetObjectCommand({ Bucket: bucket, Key: key }))\n if (!response.Body) throw new Error(`empty response for s3://${bucket}/${key}`)\n await pipeline(response.Body as Readable, fs.createWriteStream(dest))\n}\n\nasync function downloadFromHttp(opts: ImageSourceOptions, stack: string, file: string, dest: string): Promise<void> {\n const url = `${opts.location.replace(/\\/+$/, '')}/${opts.arch}/${stack}/${file}`\n const response = await fetch(url)\n if (!response.ok || !response.body) {\n throw new Error(`GET ${url} failed: ${response.status} ${response.statusText}`)\n }\n await pipeline(Readable.fromWeb(response.body as import('stream/web').ReadableStream), fs.createWriteStream(dest))\n}\n\n/** Download base images for the given stacks into destDir/<stack>/ (atomic per file via .partial rename). */\nexport async function pullImages(opts: ImageSourceOptions, destDir: string): Promise<string[]> {\n const isS3 = opts.location.startsWith('s3://')\n const downloaded: string[] = []\n\n for (const stack of opts.stacks ?? PUBLISHED_IMAGE_STACKS) {\n const stackDir = path.join(destDir, stack)\n fs.mkdirSync(stackDir, { recursive: true })\n for (const file of IMAGE_FILES) {\n const dest = path.join(stackDir, file)\n const partial = `${dest}.partial`\n if (isS3) await downloadFromS3(opts, stack, file, partial)\n else await downloadFromHttp(opts, stack, file, partial)\n fs.renameSync(partial, dest)\n downloaded.push(dest)\n }\n }\n return downloaded\n}\n\n/** Upload base images for the given stacks from srcDir/<stack>/ to s3://bucket[/prefix]/<arch>/<stack>/. */\nexport async function pushImages(opts: ImageSourceOptions, srcDir: string): Promise<string[]> {\n const { PutObjectCommand } = await import('@aws-sdk/client-s3')\n const { bucket, prefix } = parseS3Uri(opts.location)\n const client = await makeS3Client(opts.endpoint)\n const uploaded: string[] = []\n\n const stacks = opts.stacks ?? availableStacks(srcDir)\n if (!stacks.length) {\n throw new Error(`no stack images found under ${srcDir} \u2014 run scripts/setup-vm-images.sh first`)\n }\n\n for (const stack of stacks) {\n for (const file of IMAGE_FILES) {\n const src = path.join(srcDir, stack, file)\n if (!fs.existsSync(src)) {\n throw new Error(`${src} not found \u2014 run scripts/setup-vm-images.sh first`)\n }\n const key = s3Key(prefix, opts.arch, stack, file)\n // Buffer instead of stream: keeps Content-Length exact and avoids aws-chunked\n // encoding that older S3-compatible stores reject. Images are ~20-50 MB.\n await client.send(new PutObjectCommand({\n Bucket: bucket,\n Key: key,\n Body: fs.readFileSync(src),\n }))\n uploaded.push(`s3://${bucket}/${key}`)\n }\n }\n return uploaded\n}\n", "import type { GatewayAccessConfig } from './access'\n\nexport const VM_STACKS = ['generic', 'node', 'python', 'static'] as const\nexport type VmStack = (typeof VM_STACKS)[number]\n\nexport const VM_ENGINES = [\n 'mock',\n 'qemu',\n 'firecracker',\n 'docker',\n 'docker-sandbox',\n 'remote',\n 'lambda-microvm',\n 'fargate',\n] as const\nexport type VmEngine = (typeof VM_ENGINES)[number]\n\n/** 'service': a persistent process the gateway proxies to. 'job': runs its entrypoint once and exits. */\nexport const VM_RUN_MODES = ['service', 'job'] as const\nexport type VmRunMode = (typeof VM_RUN_MODES)[number]\n\nexport type VmState =\n | 'creating'\n | 'running'\n | 'pausing'\n | 'paused'\n | 'resuming'\n | 'stopping'\n | 'stopped'\n | 'restoring'\n | 'destroying'\n | 'error'\n /** Job VM whose entrypoint exited with code 0. See VmRecord.result. */\n | 'completed'\n /** User-initiated teardown that keeps the record around (e.g. as deployment history) instead of deleting it. */\n | 'destroyed'\n\nexport const VM_ACTIONS = ['pause', 'resume', 'stop', 'restore'] as const\nexport type VmAction = (typeof VM_ACTIONS)[number]\n\nexport interface VmResources {\n vcpuCount: number\n memMib: number\n}\n\nexport interface VmRecord {\n vmId: string\n /** Builder session this VM belongs to; optional for VMs not tied to a session. */\n sessionId?: string\n workerId: string\n stack: VmStack\n /** Micro-VM engine the VM runs on. Absent on records created before engines existed. */\n engine?: VmEngine\n /** Release whose artifact the VM pulled and started at boot. */\n releaseId?: string\n /** Gateway-level access protection (Cloudflare Access-style login gate). */\n access?: GatewayAccessConfig\n resources: VmResources\n state: VmState\n /** 'service' (default) for a persistent proxied process, 'job' for a run-once script. */\n runMode: VmRunMode\n /** Custom environment variables for the guest entrypoint. */\n env?: Record<string, string>\n /** Set once a 'job' VM's entrypoint exits (state becomes 'completed' or 'error'). */\n result?: VmRunResult\n /**\n * Opaque, engine-specific data an executor needs to reattach to this VM after a worker\n * restart (e.g. a QEMU QMP socket path, a Fargate task ARN). Sandbox stores it as-is and\n * never interprets it \u2014 only the executor that created it knows the shape.\n */\n runtimeMetadata?: Record<string, unknown>\n createdAt: string\n updatedAt: string\n}\n\nexport interface VmCreateRequest {\n /** Builder session to associate the VM with (not validated; informational for now). */\n sessionId?: string\n stack: VmStack\n /** Requested micro-VM engine. Omit to use the scheduled worker's default engine. */\n engine?: VmEngine\n /** Release to deploy into the VM: the guest pulls the artifact (presigned URL), unzips, and starts it. */\n releaseId?: string\n /** 'service' (default) keeps the entrypoint running and proxied; 'job' runs it once and exits. */\n runMode?: VmRunMode\n /** Custom environment variables for the guest entrypoint. */\n env?: Record<string, string>\n resources?: Partial<VmResources>\n}\n\nexport interface VmExecRequest {\n /** Shell command executed inside the VM workspace. */\n command: string\n /** Working directory relative to the VM workspace root. */\n cwd?: string\n /** Wall-clock limit for the command; capped by the executor. */\n timeoutMs?: number\n}\n\nexport interface VmExecResult {\n exitCode: number\n stdout: string\n stderr: string\n durationMs: number\n /** True when stdout/stderr were cut at the executor's output cap. */\n truncated: boolean\n /** True when the command was killed by the timeout. */\n timedOut: boolean\n}\n\n/** Outcome of a 'job' VM's entrypoint running to completion. */\nexport interface VmRunResult {\n exitCode: number\n stdout: string\n stderr: string\n /** True when stdout/stderr were cut at the executor's output cap. */\n truncated: boolean\n durationMs: number\n finishedAt: string\n}\n\nexport interface VmFileWrite {\n /** Path relative to the VM workspace root (no leading slash, no traversal). */\n path: string\n content: string\n /** How `content` is encoded; utf8 by default, base64 for binary files. */\n encoding?: 'utf8' | 'base64'\n}\n\nexport interface VmWriteFilesResult {\n written: Array<{ path: string; bytes: number }>\n}\n\nexport interface ProxyRequestDescriptor {\n method: string\n path: string\n headers: Record<string, string>\n body?: Buffer\n}\n\nexport interface ProxyResponseDescriptor {\n statusCode: number\n headers: Record<string, string>\n body?: Buffer\n}\n\nexport interface CommandResult {\n ok: boolean\n error?: string\n}\n\nexport interface CommandAck<T = unknown> extends CommandResult {\n result?: T\n}\n\nexport const VM_REDIS_KEY_PREFIX = 'vm:'\n\nexport interface VmRegistryEntry {\n workerId: string\n state: VmState\n access?: GatewayAccessConfig\n}\n", "import type { VmAction, VmRunResult } from './vm'\n\n// \u2500\u2500 Worker socket events (sandbox \u2194 worker) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Events exchanged on the worker socket (sandbox side listens, worker side emits \u2014 and vice versa). */\nexport const WorkerEvent = {\n // worker \u2192 sandbox\n HEARTBEAT: 'worker:heartbeat',\n\n // worker \u2192 sandbox, fire-and-forget like HEARTBEAT \u2014 sent once when a 'job' VM's\n // entrypoint exits on its own (the worker has already torn the resource down by then).\n VM_RUN_EXITED: 'vm:run-exited',\n\n // sandbox \u2192 worker, generated by the control plane and reused by this worker process\n // on Socket.IO reconnects. This keeps duplicate configured WORKER_ID values isolated.\n ASSIGNED_ID: 'worker:assigned-id',\n\n // sandbox \u2192 worker, once right after auth on every (re)connect \u2014 the VMs sandbox's\n // records say this workerId owns, so the worker can try to reattach before its first\n // heartbeat. Always sent, even with an empty array, as a handshake signal.\n REATTACH: 'worker:reattach',\n\n // sandbox \u2192 worker (VM lifecycle commands)\n VM_CREATE: 'vm:create',\n VM_PAUSE: 'vm:pause',\n VM_RESUME: 'vm:resume',\n VM_STOP: 'vm:stop',\n VM_RESTORE: 'vm:restore',\n VM_DESTROY: 'vm:destroy',\n\n // sandbox / gateway \u2192 worker (HTTP proxy)\n PROXY_HTTP: 'proxy:http',\n\n // sandbox \u2192 worker (guest workspace commands)\n VM_EXEC: 'vm:exec',\n VM_WRITE_FILES: 'vm:write-files',\n\n // worker \u2192 sandbox (VNC/terminal media relay)\n VNC_INIT: 'vnc:init',\n VNC_FRAME: 'vnc:frame',\n VNC_COPY_FRAME: 'vnc:copy-frame',\n TERMINAL_DATA: 'terminal:data',\n\n // sandbox \u2192 worker (browser input forwarded downstream)\n VNC_MOUSE: 'vnc:mouse',\n VNC_KEYBOARD: 'vnc:keyboard',\n TERMINAL_INPUT: 'terminal:input',\n} as const\n\nexport type WorkerEventName = (typeof WorkerEvent)[keyof typeof WorkerEvent]\n\n/** Maps a VmAction to its worker socket event name. */\nexport const VM_ACTION_EVENTS: Record<VmAction, string> = {\n pause: WorkerEvent.VM_PAUSE,\n resume: WorkerEvent.VM_RESUME,\n stop: WorkerEvent.VM_STOP,\n restore: WorkerEvent.VM_RESTORE,\n}\n\n// \u2500\u2500 Console socket events (browser \u2194 sandbox /vm-console/ws) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Events on the browser-facing console Socket.io namespaces (/vnc and /terminal). */\nexport const ConsoleEvent = {\n // /vnc namespace: sandbox \u2192 browser\n VNC_INIT: 'init',\n VNC_FRAME: 'frame',\n VNC_COPY_FRAME: 'copy-frame',\n\n // /vnc namespace: browser \u2192 sandbox\n VNC_MOUSE: 'mouse',\n VNC_KEYBOARD: 'keyboard',\n\n // /terminal namespace: sandbox \u2194 browser\n TERMINAL_DATA: 'data',\n TERMINAL_INPUT: 'data',\n} as const\n\n// \u2500\u2500 Payload types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface VncInitPayload {\n vmId: string\n width: number\n height: number\n}\n\nexport interface VncFramePayload {\n vmId: string\n x: number\n y: number\n width: number\n height: number\n encoding: 'raw'\n data: Buffer\n}\n\nexport interface VncCopyFramePayload {\n vmId: string\n x: number\n y: number\n src: { x: number; y: number }\n width: number\n height: number\n}\n\nexport interface TerminalDataPayload {\n vmId: string\n data: Buffer\n}\n\nexport interface VncMousePayload {\n vmId: string\n x: number\n y: number\n button: number\n}\n\nexport interface VncKeyboardPayload {\n vmId: string\n keyCode: number\n isDown: boolean\n}\n\nexport interface TerminalInputPayload {\n vmId: string\n data: string\n}\n\nexport interface VmRunExitedPayload extends VmRunResult {\n vmId: string\n}\n", "import bunyan, {\n type LoggerOptions,\n type LogLevelString,\n} from 'bunyan'\nimport { hostname } from 'os'\nimport {\n APP_NAME,\n LOG_LEVEL,\n} from './config'\n\nconst HOST_NAME = hostname()\n\nconst loggerOptions: LoggerOptions = {\n name: APP_NAME,\n level: LOG_LEVEL as LogLevelString,\n hostname: HOST_NAME,\n serializers: bunyan.stdSerializers,\n}\n\nexport const logger = bunyan.createLogger(loggerOptions)\n\n// const events = [\n// 'exit',\n// 'SIGINT',\n// 'SIGTERM',\n// 'uncaughtException',\n// ]\n\n// const exit = () => {\n// // logger.reopenFileStreams()\n// }\n\n// events.forEach(event => process.on(event, exit))\n", "export const NODE_ENV = process.env.NODE_ENV || 'development'\nexport const isProduction = NODE_ENV === 'production'\n// npm_package_name is only set when launched via `npm run`/`pnpm run` \u2014 production images start\n// services with a plain `node dist/index.js`, so APP_NAME must be set explicitly there.\nexport const APP_NAME =\n process.env.APP_NAME || process.env.npm_package_name?.split('/').pop() || 'unknown-app'\nexport const LOG_LEVEL = process.env.LOG_LEVEL || (isProduction ? 'info' : 'debug')\n", "import bunyan, { type LoggerOptions } from 'bunyan'\nimport { hostname } from 'os'\nimport { isProduction, APP_NAME } from './config'\n\nconst HOST_NAME = hostname()\n\nconst loggerOptions: LoggerOptions = {\n name: APP_NAME,\n level: isProduction ? 'info' : 'debug',\n hostname: HOST_NAME,\n}\n\nexport const KafkaJsLogCreator = (logLevelConverter: any) => (level: any) => {\n if (level) {\n loggerOptions.level = logLevelConverter(level)\n }\n const logger = bunyan.createLogger(loggerOptions)\n\n return ({ level, log }) => {\n const { message, ...extra } = log\n logger[logLevelConverter(level)]({\n extra,\n }, message)\n }\n}\n", "import { logger } from './logger'\n\nexport { middleware as loggerExpressMiddleware } from './middleware'\nexport { default as logError } from './log-error.decorator'\nexport { default as asyncLogError } from './log-error-async.decorator'\nexport * from './kafkajs-logger-creator'\nexport default logger\nexport * from './kafkajs-logger-creator'\n", "import { execFile } from 'child_process'\nimport fs from 'fs/promises'\nimport http from 'http'\nimport type { IncomingMessage, ServerResponse } from 'http'\nimport os from 'os'\nimport path from 'path'\nimport type { AddressInfo } from 'net'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmExecRequest,\n VmExecResult,\n VmFileWrite,\n VmRunMode,\n VmRunResult,\n VmWriteFilesResult,\n} from '@multiplayer-app/builder-types'\nimport logger from '@multiplayer-app/logger'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nconst DEFAULT_EXEC_TIMEOUT_MS = 60_000\nconst MAX_EXEC_TIMEOUT_MS = 300_000\nconst MAX_OUTPUT_BYTES = 1024 * 1024\nconst MAX_FILE_BYTES = 5 * 1024 * 1024\n\nconst CONTENT_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'text/javascript; charset=utf-8',\n '.mjs': 'text/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.txt': 'text/plain; charset=utf-8',\n '.md': 'text/plain; charset=utf-8',\n}\n\ninterface ManagedVm {\n handle: VmHandle\n server: http.Server\n port: number\n workspaceDir: string\n runMode: VmRunMode\n startedAt: number\n}\n\n/** ms until a mock 'job' VM synthesizes a completion result \u2014 short enough for tests to not stall. */\nconst MOCK_JOB_DURATION_MS = 250\n\n/** Resolve a workspace-relative path, rejecting escapes (\"../\", absolute paths). */\nfunction resolveWorkspacePath(workspaceDir: string, relativePath: string): string {\n const normalized = path.normalize(relativePath).replace(/^([/\\\\])+/, '')\n const resolved = path.resolve(workspaceDir, normalized)\n if (resolved !== workspaceDir && !resolved.startsWith(workspaceDir + path.sep)) {\n throw new Error(`Path escapes the VM workspace: ${relativePath}`)\n }\n return resolved\n}\n\n/**\n * Stand-in for a real microVM: serves the VM workspace directory over HTTP\n * (index.html fallback), playing the role of \"the app inside the VM\".\n */\nfunction startStandInServer(\n spec: VmSpec,\n workspaceDir: string,\n): Promise<{ server: http.Server; port: number }> {\n const server = http.createServer((req: IncomingMessage, res: ServerResponse) => {\n void (async () => {\n const requestPath = decodeURIComponent((req.url ?? '/').split('?')[0])\n const relative = requestPath === '/' ? 'index.html' : requestPath\n try {\n const filePath = resolveWorkspacePath(workspaceDir, relative)\n const content = await fs.readFile(filePath)\n res.writeHead(200, {\n 'content-type':\n CONTENT_TYPES[path.extname(filePath).toLowerCase()] ?? 'application/octet-stream',\n })\n res.end(content)\n } catch {\n res.writeHead(200, { 'content-type': 'text/plain' })\n res.end(\n `mock vm ${spec.vmId} (${spec.stack}) \u2014 session ${spec.sessionId} \u2014 ${req.method} ${req.url}\\n`,\n )\n }\n })()\n })\n\n return new Promise((resolve, reject) => {\n server.once('error', reject)\n server.listen(0, '127.0.0.1', () => {\n resolve({ server, port: (server.address() as AddressInfo).port })\n })\n })\n}\n\nexport class MockExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), `mock-vm-${spec.vmId}-`))\n const { server, port } = await startStandInServer(spec, workspaceDir)\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n // No real process to configure \u2014 just echoed back for introspection/tests.\n ...(spec.env ? { metadata: { env: spec.env } } : {}),\n }\n\n const runMode = spec.runMode ?? 'service'\n this.vms.set(spec.vmId, { handle, server, port, workspaceDir, runMode, startedAt: Date.now() })\n logger.info({ vmId: spec.vmId, port, workspaceDir, runMode }, 'mock vm created')\n return handle\n }\n\n /** No real process to watch \u2014 just synthesize a successful run shortly after create(). */\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const startedAt = this.vms.get(vmId)?.startedAt ?? Date.now()\n this.exitHandlers.set(vmId, handler)\n setTimeout(() => {\n void (async () => {\n const registered = this.exitHandlers.get(vmId)\n this.exitHandlers.delete(vmId)\n if (!registered) return\n\n const result: VmRunResult = {\n exitCode: 0,\n stdout: `mock job ${vmId} completed\\n`,\n stderr: '',\n truncated: false,\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n }\n await this.destroy(vmId)\n registered(result)\n })()\n }, MOCK_JOB_DURATION_MS)\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n return this.setRunning(vmId, true)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n await new Promise<void>((resolve) => vm.server.close(() => resolve()))\n await fs.rm(vm.workspaceDir, { recursive: true, force: true })\n this.vms.delete(vmId)\n logger.info({ vmId }, 'mock vm destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((vm) => vm.handle)\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.requireRunningVm(vmId)\n\n return new Promise((resolve, reject) => {\n const proxyReq = http.request(\n {\n host: '127.0.0.1',\n port: vm.port,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (proxyRes) => {\n const chunks: Buffer[] = []\n proxyRes.on('data', (chunk) => chunks.push(chunk))\n proxyRes.on('end', () => {\n resolve({\n statusCode: proxyRes.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(proxyRes.headers).map(([key, value]) => [\n key,\n Array.isArray(value) ? value.join(', ') : value ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n })\n })\n },\n )\n\n proxyReq.on('error', reject)\n if (request.body) proxyReq.write(request.body)\n proxyReq.end()\n })\n }\n\n async writeFiles(vmId: string, files: VmFileWrite[]): Promise<VmWriteFilesResult> {\n const vm = this.requireRunningVm(vmId)\n const written: Array<{ path: string; bytes: number }> = []\n\n for (const file of files) {\n const buffer = Buffer.from(file.content, file.encoding === 'base64' ? 'base64' : 'utf8')\n if (buffer.byteLength > MAX_FILE_BYTES) {\n throw new Error(\n `File too large (${buffer.byteLength} bytes, max ${MAX_FILE_BYTES}): ${file.path}`,\n )\n }\n const filePath = resolveWorkspacePath(vm.workspaceDir, file.path)\n await fs.mkdir(path.dirname(filePath), { recursive: true })\n await fs.writeFile(filePath, buffer)\n written.push({ path: path.relative(vm.workspaceDir, filePath), bytes: buffer.byteLength })\n }\n\n logger.info({ vmId, files: written.length }, 'mock vm files written')\n return { written }\n }\n\n async exec(vmId: string, request: VmExecRequest): Promise<VmExecResult> {\n const vm = this.requireRunningVm(vmId)\n const cwd = request.cwd ? resolveWorkspacePath(vm.workspaceDir, request.cwd) : vm.workspaceDir\n const timeoutMs = Math.min(request.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS, MAX_EXEC_TIMEOUT_MS)\n const startedAt = Date.now()\n\n return new Promise((resolve) => {\n execFile(\n '/bin/sh',\n ['-c', request.command],\n {\n cwd,\n timeout: timeoutMs,\n maxBuffer: MAX_OUTPUT_BYTES,\n env: { ...process.env, HOME: vm.workspaceDir },\n },\n (error, stdout, stderr) => {\n const failed = error as\n | (NodeJS.ErrnoException & { code?: number | string; killed?: boolean })\n | null\n const timedOut = Boolean(failed?.killed)\n const truncated = failed?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'\n resolve({\n exitCode: typeof failed?.code === 'number' ? failed.code : failed ? 1 : 0,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n durationMs: Date.now() - startedAt,\n truncated: Boolean(truncated),\n timedOut,\n })\n },\n )\n })\n }\n\n private requireRunningVm(vmId: string): ManagedVm {\n const vm = this.vms.get(vmId)\n if (!vm || !vm.handle.running) {\n throw new Error(`vm ${vmId} is not running`)\n }\n return vm\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n}\n", "import { spawn, type ChildProcess } from 'child_process'\nimport net from 'net'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport os from 'os'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmRunMode,\n VmRunResult,\n} from '@multiplayer-app/builder-types'\nimport { resolveStackImages } from '../images'\nimport type { Executor, VmHandle, VmSpec } from './types'\nimport { withTimeout } from './reattach-utils'\nimport { encodeEnvB64 } from './env-encoding'\n\nconst MAX_OUTPUT_BYTES = 1024 * 1024\n/** Printed by the guest init script (see scripts/setup-vm-images.sh) right before it powers off in job mode. */\nconst JOB_EXIT_SENTINEL = '__JOB_EXIT_CODE__:'\n\nexport interface QemuConfig {\n bin?: string\n /** Root of per-stack base images: <imagesDir>/<stack>/{vmlinuz,initramfs.img}. */\n imagesDir?: string\n /** Explicit single-image override; used for every stack when both are set. */\n kernelPath?: string\n initrdPath?: string\n vmDataPath?: string\n httpPortRangeStart?: number\n httpPortRangeEnd?: number\n vncBasePort?: number // base port for VNC displays (default 5900); display N \u2192 port vncBasePort+N\n serialBasePort?: number // base port for serial TCP (default 8000)\n accel?: string // 'hvf' (macOS), 'kvm' (Linux + /dev/kvm), 'tcg' (software, any host)\n cpu?: string // 'host' (hvf/kvm), 'max' (tcg aarch64), 'qemu64' (tcg x86_64)\n machine?: string // 'virt' (aarch64), 'q35' (x86_64)\n}\n\ninterface ManagedVm {\n handle: VmHandle\n // Absent after a reattach \u2014 the original ChildProcess object doesn't survive a worker\n // restart. Lifecycle control still works via QMP; destroy() falls back to killing `pid`.\n process?: ChildProcess\n pid?: number\n hostPort: number\n qmpSocketPath: string\n vncDisplay: number // QEMU display index (port = vncBasePort + vncDisplay)\n serialPort: number\n runMode: VmRunMode\n startedAt: number\n /** Job mode only: bounded capture of the serial console, scraped for JOB_EXIT_SENTINEL on exit. */\n serialBuffer?: { chunks: Buffer[]; bytes: number; socket: net.Socket }\n}\n\nexport class QemuExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n private readonly usedHttpPorts = new Set<number>()\n private readonly usedDisplays = new Set<number>() // VNC display indices\n private readonly usedSerialPorts = new Set<number>()\n private readonly bin: string\n private readonly vmDataPath: string\n private readonly httpPortStart: number\n private readonly httpPortEnd: number\n private readonly vncBasePort: number\n private readonly serialBasePort: number\n private readonly accel: string\n private readonly cpu: string\n private readonly machine: string\n\n constructor(private readonly config: QemuConfig) {\n this.bin = config.bin ?? 'qemu-system-aarch64'\n this.vmDataPath = config.vmDataPath ?? path.join(os.tmpdir(), 'qemu-vms')\n this.httpPortStart = config.httpPortRangeStart ?? 9000\n this.httpPortEnd = config.httpPortRangeEnd ?? 9099\n this.vncBasePort = config.vncBasePort ?? 5900\n this.serialBasePort = config.serialBasePort ?? 8000\n this.accel = config.accel ?? 'hvf'\n this.cpu = config.cpu ?? 'host'\n this.machine = config.machine ?? 'virt'\n }\n\n private allocateHttpPort(): number {\n for (let p = this.httpPortStart; p <= this.httpPortEnd; p++) {\n if (!this.usedHttpPorts.has(p)) {\n this.usedHttpPorts.add(p)\n return p\n }\n }\n throw new Error('no free HTTP ports in QEMU port range')\n }\n\n private allocateVncDisplay(): number {\n for (let d = 1; d <= 99; d++) {\n if (!this.usedDisplays.has(d)) {\n this.usedDisplays.add(d)\n return d\n }\n }\n throw new Error('no free VNC displays')\n }\n\n private allocateSerialPort(): number {\n for (let p = this.serialBasePort; p <= this.serialBasePort + 99; p++) {\n if (!this.usedSerialPorts.has(p)) {\n this.usedSerialPorts.add(p)\n return p\n }\n }\n throw new Error('no free serial ports')\n }\n\n /** Explicit kernel/initrd override wins; otherwise the stack's base image, falling back to generic. */\n private resolveImages(stack: string): { kernelPath: string; initrdPath: string } {\n if (this.config.kernelPath && this.config.initrdPath) {\n return { kernelPath: this.config.kernelPath, initrdPath: this.config.initrdPath }\n }\n const resolved = this.config.imagesDir\n ? resolveStackImages(this.config.imagesDir, stack) ??\n resolveStackImages(this.config.imagesDir, 'generic')\n : undefined\n if (!resolved) {\n throw new Error(\n `no base image for stack \"${stack}\" under ${this.config.imagesDir} \u2014 run \"worker-cli images pull\"`,\n )\n }\n return resolved\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const { kernelPath, initrdPath } = this.resolveImages(spec.stack)\n const envB64 = encodeEnvB64(spec.env)\n const hostPort = this.allocateHttpPort()\n const vncDisplay = this.allocateVncDisplay()\n const serialPort = this.allocateSerialPort()\n const vncPort = this.vncBasePort + vncDisplay\n\n const vmDir = path.join(this.vmDataPath, spec.vmId)\n await fs.mkdir(vmDir, { recursive: true })\n const qmpSocketPath = path.join(vmDir, 'qmp.sock')\n\n const args = [\n '-machine',\n this.machine,\n '-cpu',\n this.cpu,\n '-accel',\n this.accel,\n '-smp',\n String(spec.resources.vcpuCount),\n '-m',\n String(spec.resources.memMib),\n '-kernel',\n kernelPath,\n '-initrd',\n initrdPath,\n // console=tty0 sends output to VGA framebuffer (VNC); ttyAMA0 to serial.\n // APP_URL_B64: base64-encoded presigned artifact URL \u2014 kernel cmdline params are\n // space-separated, so the raw URL (query string, &) can't be passed directly.\n '-append',\n [\n `console=tty0 console=ttyAMA0 net.ifnames=0 init=/init VM_ID=${spec.vmId} STACK=${spec.stack}`,\n spec.sessionId ? `SESSION_ID=${spec.sessionId}` : '',\n spec.appUrl ? `APP_URL_B64=${Buffer.from(spec.appUrl).toString('base64')}` : '',\n spec.runMode === 'job' ? 'RUN_MODE=job' : '',\n envB64 ? `ENV_B64=${envB64}` : '',\n ]\n .filter(Boolean)\n .join(' '),\n // Networking\n '-netdev',\n `user,id=net0,hostfwd=tcp::${hostPort}-:8080`,\n '-device',\n 'virtio-net-pci,netdev=net0',\n // Display: virtio-gpu-pci works on both aarch64 and x86_64; virtio-vga is x86-only\n '-device',\n 'virtio-gpu-pci',\n '-display',\n 'none',\n '-vnc',\n `127.0.0.1:${vncDisplay}`,\n // Serial console via TCP (xterm.js connects here)\n '-serial',\n `tcp:127.0.0.1:${serialPort},server,nowait`,\n // Control\n '-no-reboot',\n '-qmp',\n `unix:${qmpSocketPath},server,nowait`,\n ]\n\n logger.info({ vmId: spec.vmId, bin: this.bin, args }, 'spawning qemu')\n const proc = spawn(this.bin, args, { stdio: ['ignore', 'pipe', 'pipe'] })\n proc.stdout?.on('data', (d: Buffer) => logger.info({ vmId: spec.vmId }, d.toString().trimEnd()))\n proc.stderr?.on('data', (d: Buffer) =>\n logger.error({ vmId: spec.vmId }, d.toString().trimEnd()),\n )\n const runMode = spec.runMode ?? 'service'\n const startedAt = Date.now()\n proc.on('exit', (code, signal) => {\n const log = code === 0 || code === null ? logger.info.bind(logger) : logger.error.bind(logger)\n log({ vmId: spec.vmId, code, signal }, 'qemu process exited')\n const vm = this.vms.get(spec.vmId)\n if (!vm) return\n\n this.usedHttpPorts.delete(vm.hostPort)\n this.usedDisplays.delete(vm.vncDisplay)\n this.usedSerialPorts.delete(vm.serialPort)\n\n if (vm.runMode === 'job') {\n // Keep the map entry (marked not-running) until onExit() claims the result \u2014 see\n // docker-executor's deliverJobResult comment for why route() needs get() to still work.\n vm.handle = { ...vm.handle, running: false }\n this.reportJobResult(spec.vmId, vm)\n } else {\n this.vms.delete(spec.vmId)\n }\n })\n\n const metadata = { hostPort, qmpSocketPath, vncDisplay, serialPort, pid: proc.pid }\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n vncPort,\n serialPort,\n metadata,\n }\n\n const vm: ManagedVm = {\n handle,\n process: proc,\n pid: proc.pid,\n hostPort,\n qmpSocketPath,\n vncDisplay,\n serialPort,\n runMode,\n startedAt,\n }\n this.vms.set(spec.vmId, vm)\n if (runMode === 'job') vm.serialBuffer = connectSerialBuffer(serialPort)\n\n await waitForQmp(qmpSocketPath)\n logger.info({ vmId: spec.vmId, hostPort, vncPort, serialPort, runMode }, 'qemu vm ready')\n return handle\n }\n\n /** Scrapes JOB_EXIT_SENTINEL out of the buffered serial console and reports the result. */\n private reportJobResult(vmId: string, vm: ManagedVm): void {\n vm.serialBuffer?.socket.destroy()\n const output = Buffer.concat(vm.serialBuffer?.chunks ?? []).toString('utf8')\n const sentinelIndex = output.lastIndexOf(JOB_EXIT_SENTINEL)\n const exitCode =\n sentinelIndex === -1\n ? 1\n : Number.parseInt(output.slice(sentinelIndex + JOB_EXIT_SENTINEL.length), 10) || 0\n const stdout = sentinelIndex === -1 ? output : output.slice(0, sentinelIndex)\n\n const result: VmRunResult = {\n exitCode,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: '',\n truncated: (vm.serialBuffer?.bytes ?? 0) > MAX_OUTPUT_BYTES,\n durationMs: Date.now() - vm.startedAt,\n finishedAt: new Date().toISOString(),\n }\n logger.info({ vmId, exitCode }, 'qemu job vm exited')\n this.deliverJobResult(vmId, result)\n }\n\n private deliverJobResult(vmId: string, result: VmRunResult): void {\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n await this.qmp(vmId, 'stop')\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n await this.qmp(vmId, 'cont')\n return this.setRunning(vmId, true)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n await this.qmp(vmId, 'stop')\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n await this.qmp(vmId, 'cont')\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n try {\n await this.qmp(vmId, 'quit')\n } catch {\n this.killVm(vm)\n }\n\n if (vm.process) {\n const proc = vm.process\n await new Promise<void>((resolve) => {\n if (proc.exitCode !== null) return resolve()\n proc.once('exit', resolve)\n setTimeout(() => {\n this.killVm(vm)\n resolve()\n }, 3_000)\n })\n } else {\n // Reattached VM \u2014 no live ChildProcess to wait on. QMP quit was already requested\n // above; give it a moment, then fall back to killing by pid.\n await new Promise((resolve) => setTimeout(resolve, 1_000))\n this.killVm(vm)\n }\n\n this.usedHttpPorts.delete(vm.hostPort)\n this.usedDisplays.delete(vm.vncDisplay)\n this.usedSerialPorts.delete(vm.serialPort)\n this.vms.delete(vmId)\n await fs.rm(path.join(this.vmDataPath, vmId), { recursive: true, force: true })\n logger.info({ vmId }, 'qemu vm destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n /**\n * Recover a QEMU VM after a worker restart: the process may well have survived (it's not\n * killed just because its Node parent exited), so probe its QMP socket \u2014 if it answers,\n * lifecycle control and HTTP proxying resume normally. There's no live ChildProcess to\n * reattach to, so destroy() falls back to killing the stored pid.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as\n | {\n hostPort?: number\n qmpSocketPath?: string\n vncDisplay?: number\n serialPort?: number\n pid?: number\n }\n | undefined\n if (\n !meta?.qmpSocketPath ||\n meta.hostPort === undefined ||\n meta.vncDisplay === undefined ||\n meta.serialPort === undefined\n ) {\n return undefined\n }\n\n try {\n await withTimeout(sendQmpCommand(meta.qmpSocketPath, 'query-status'), 5_000)\n } catch {\n return undefined\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running: record.state === 'running',\n vncPort: this.vncBasePort + meta.vncDisplay,\n serialPort: meta.serialPort,\n metadata: meta,\n }\n\n this.usedHttpPorts.add(meta.hostPort)\n this.usedDisplays.add(meta.vncDisplay)\n this.usedSerialPorts.add(meta.serialPort)\n this.vms.set(record.vmId, {\n handle,\n pid: meta.pid,\n hostPort: meta.hostPort,\n qmpSocketPath: meta.qmpSocketPath,\n vncDisplay: meta.vncDisplay,\n serialPort: meta.serialPort,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n\n // Note: a job VM that finished (or is still running) while this worker was offline has\n // no recoverable path here \u2014 the serial buffer only ever lived in the dead worker's\n // memory, and if the guest already powered off the QMP probe above would have failed and\n // returned undefined before reaching this point (reported as \"resource no longer exists\"\n // by MultiEngineExecutor.reattachAll). A still-running job just resumes being watched\n // normally below via the QMP-confirmed process.\n\n logger.info({ vmId: record.vmId }, 'qemu vm reattached')\n return handle\n }\n\n private killVm(vm: ManagedVm): void {\n if (vm.process) {\n vm.process.kill('SIGKILL')\n return\n }\n if (vm.pid) {\n try {\n process.kill(vm.pid, 'SIGKILL')\n } catch {\n /* already gone */\n }\n }\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.vms.get(vmId)\n if (!vm?.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n const { default: http } = await import('http')\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: '127.0.0.1',\n port: vm.hostPort,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n\n private async qmp(vmId: string, execute: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n await sendQmpCommand(vm.qmpSocketPath, execute)\n }\n}\n\n/**\n * Opens our own client connection to the serial TCP port (QEMU holds it open as a server,\n * `nowait`) purely to capture a job's output \u2014 independent of whether a browser is also\n * watching live via SerialRelay/getSerialSource.\n */\nfunction connectSerialBuffer(port: number): {\n chunks: Buffer[]\n bytes: number\n socket: net.Socket\n} {\n const buffer = {\n chunks: [] as Buffer[],\n bytes: 0,\n socket: net.connect({ host: '127.0.0.1', port }),\n }\n buffer.socket.on('data', (chunk: Buffer) => {\n if (buffer.bytes >= MAX_OUTPUT_BYTES) return\n buffer.chunks.push(chunk)\n buffer.bytes += chunk.byteLength\n })\n buffer.socket.on('error', () => {\n /* best-effort capture \u2014 a dropped connection just means a shorter log, not a failure */\n })\n return buffer\n}\n\nfunction waitForQmp(socketPath: string, timeoutMs = 30_000): Promise<void> {\n return new Promise((resolve, reject) => {\n const deadline = Date.now() + timeoutMs\n const attempt = () => {\n if (Date.now() > deadline)\n return reject(new Error(`timed out waiting for QMP socket at ${socketPath}`))\n const sock = net.createConnection(socketPath)\n sock.once('connect', () => {\n sock.destroy()\n resolve()\n })\n sock.once('error', () => setTimeout(attempt, 500))\n }\n attempt()\n })\n}\n\nasync function sendQmpCommand(socketPath: string, execute: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const sock = net.createConnection(socketPath)\n let buf = ''\n let ready = false\n const send = (obj: object) => sock.write(JSON.stringify(obj) + '\\r\\n')\n\n sock.on('data', (data: Buffer) => {\n buf += data.toString()\n let idx: number\n while ((idx = buf.indexOf('\\n')) !== -1) {\n const line = buf.slice(0, idx).trim()\n buf = buf.slice(idx + 1)\n if (!line) continue\n let msg: Record<string, unknown>\n try {\n msg = JSON.parse(line)\n } catch {\n continue\n }\n\n if (msg['QMP']) {\n send({ execute: 'qmp_capabilities' })\n } else if (!ready && 'return' in msg) {\n ready = true\n send({ execute })\n } else if (ready && 'return' in msg) {\n sock.destroy()\n resolve()\n } else if (msg['error']) {\n sock.destroy()\n reject(new Error(`QMP error for \"${execute}\": ${JSON.stringify(msg['error'])}`))\n }\n }\n })\n\n sock.on('error', (e) => {\n if (execute === 'quit') resolve()\n else reject(e)\n })\n sock.on('close', () => resolve())\n })\n}\n", "/** Bounds a reattach probe so one unresponsive socket can't hang the whole `reattachAll` batch. */\nexport function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms)),\n ])\n}\n", "/**\n * Encodes a custom env var map into the single kernel-cmdline param QEMU/Firecracker guests\n * decode at boot (see the `ENV_B64=*` case in scripts/setup-vm-images.sh's init script).\n * The cmdline is space-delimited with no quoting, so raw `KEY=value with spaces` pairs can't\n * go directly on it (same reason APP_URL is base64-encoded as APP_URL_B64) \u2014 instead the\n * whole map is newline-joined and base64'd into one opaque param.\n */\nexport function encodeEnvB64(env: Record<string, string> | undefined): string | undefined {\n if (!env || Object.keys(env).length === 0) return undefined\n const lines = Object.entries(env)\n .map(([key, value]) => `${key}=${value}`)\n .join('\\n')\n return Buffer.from(lines).toString('base64')\n}\n", "import { spawn, type ChildProcess } from 'child_process'\nimport { exec } from 'child_process'\nimport { promisify } from 'util'\nimport http from 'http'\nimport net from 'net'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport os from 'os'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmRunMode,\n VmRunResult,\n} from '@multiplayer-app/builder-types'\nimport { resolveStackImages } from '../images'\nimport type { Executor, SerialSource, VmHandle, VmSpec } from './types'\nimport { withTimeout } from './reattach-utils'\nimport { encodeEnvB64 } from './env-encoding'\n\nconst execAsync = promisify(exec)\n\nconst MAX_OUTPUT_BYTES = 1024 * 1024\n/** Printed by the guest init script (see scripts/setup-vm-images.sh) right before it powers off in job mode. */\nconst JOB_EXIT_SENTINEL = '__JOB_EXIT_CODE__:'\n\nexport interface FirecrackerConfig {\n bin?: string // default: 'firecracker'\n /** Root of per-stack base images: <imagesDir>/<stack>/{vmlinuz,initramfs.img}. */\n imagesDir?: string\n /** Explicit single-image override (vmlinux/bzImage + cpio.gz); used for every stack when both are set. */\n kernelPath?: string\n initrdPath?: string\n vmDataPath?: string // default: /tmp/firecracker-vms\n}\n\ninterface ManagedVm {\n handle: VmHandle\n // Absent after a reattach \u2014 the original ChildProcess object doesn't survive a worker\n // restart. Lifecycle control and HTTP proxying still work via the API socket; the serial\n // console (piped over this process's inherited stdio) does not \u2014 see getSerialSource().\n process?: ChildProcess\n pid?: number\n apiSocketPath: string\n tapName: string\n subnet: number\n guestIp: string\n runMode: VmRunMode\n startedAt: number\n /** Job mode only: bounded capture of the guest's serial stdout, scraped for JOB_EXIT_SENTINEL on exit. */\n serialBuffer?: { chunks: Buffer[]; bytes: number }\n}\n\nexport class FirecrackerExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly usedSubnets = new Set<number>()\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n private tapCounter = 0\n private readonly bin: string\n private readonly vmDataPath: string\n private networkReady = false\n\n constructor(private readonly config: FirecrackerConfig) {\n this.bin = config.bin ?? 'firecracker'\n this.vmDataPath = config.vmDataPath ?? path.join(os.tmpdir(), 'firecracker-vms')\n }\n\n private allocateSubnet(): number {\n for (let s = 1; s <= 254; s++) {\n if (!this.usedSubnets.has(s)) {\n this.usedSubnets.add(s)\n return s\n }\n }\n throw new Error('no free TAP subnets (max 254 concurrent VMs)')\n }\n\n // Called once before the first VM; sets up host-level IP forwarding + masquerade.\n private async ensureNetworking(): Promise<void> {\n if (this.networkReady) return\n await execAsync('sysctl -w net.ipv4.ip_forward=1')\n const alreadySet = await execAsync(\n 'iptables -t nat -C POSTROUTING -s 172.16.0.0/12 ! -d 172.16.0.0/12 -j MASQUERADE',\n ).catch(() => null)\n if (!alreadySet) {\n await execAsync(\n 'iptables -t nat -A POSTROUTING -s 172.16.0.0/12 ! -d 172.16.0.0/12 -j MASQUERADE',\n )\n }\n this.networkReady = true\n }\n\n /** Explicit kernel/initrd override wins; otherwise the stack's base image, falling back to generic. */\n private resolveImages(stack: string): { kernelPath: string; initrdPath: string } {\n if (this.config.kernelPath && this.config.initrdPath) {\n return { kernelPath: this.config.kernelPath, initrdPath: this.config.initrdPath }\n }\n const resolved = this.config.imagesDir\n ? resolveStackImages(this.config.imagesDir, stack) ??\n resolveStackImages(this.config.imagesDir, 'generic')\n : undefined\n if (!resolved) {\n throw new Error(\n `no base image for stack \"${stack}\" under ${this.config.imagesDir} \u2014 run \"worker-cli images pull\"`,\n )\n }\n return resolved\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const { kernelPath, initrdPath } = this.resolveImages(spec.stack)\n await this.ensureNetworking()\n\n const subnet = this.allocateSubnet()\n const tapName = `fctap${++this.tapCounter}`\n const hostIp = `172.16.${subnet}.1`\n const guestIp = `172.16.${subnet}.2`\n\n const vmDir = path.join(this.vmDataPath, spec.vmId)\n await fs.mkdir(vmDir, { recursive: true })\n const apiSocketPath = path.join(vmDir, 'api.sock')\n await fs.rm(apiSocketPath, { force: true })\n\n // TAP device wired to this VM's Firecracker process\n await execAsync(`ip tuntap add dev ${tapName} mode tap`)\n await execAsync(`ip addr add ${hostIp}/30 dev ${tapName}`)\n await execAsync(`ip link set ${tapName} up`)\n\n const runMode = spec.runMode ?? 'service'\n const envB64 = encodeEnvB64(spec.env)\n const startedAt = Date.now()\n const serialBuffer = runMode === 'job' ? { chunks: [] as Buffer[], bytes: 0 } : undefined\n\n // stdin is piped so terminal input can be written to the guest's ttyS0 console\n const proc = spawn(this.bin, ['--api-sock', apiSocketPath], {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n proc.stdout?.on('data', (d: Buffer) => {\n logger.debug({ vmId: spec.vmId }, d.toString().trimEnd())\n if (serialBuffer && serialBuffer.bytes < MAX_OUTPUT_BYTES) {\n serialBuffer.chunks.push(d)\n serialBuffer.bytes += d.byteLength\n }\n })\n proc.stderr?.on('data', (d: Buffer) =>\n logger.debug({ vmId: spec.vmId }, d.toString().trimEnd()),\n )\n proc.on('exit', (code, signal) => {\n logger.info({ vmId: spec.vmId, code, signal }, 'firecracker process exited')\n const vm = this.vms.get(spec.vmId)\n if (vm) {\n this.usedSubnets.delete(vm.subnet)\n if (vm.runMode === 'job') {\n // Keep the map entry (marked not-running) until onExit() claims the result \u2014 see\n // docker-executor's deliverJobResult comment for why route() needs get() to work.\n vm.handle = { ...vm.handle, running: false }\n this.reportJobResult(spec.vmId, vm)\n } else {\n this.vms.delete(spec.vmId)\n }\n }\n execAsync(`ip link del ${tapName}`).catch(() => {})\n })\n\n await waitForSocket(apiSocketPath)\n\n const macHex = (n: number) => n.toString(16).padStart(2, '0')\n await fcRequest(apiSocketPath, 'PUT', '/machine-config', {\n vcpu_count: spec.resources.vcpuCount,\n mem_size_mib: spec.resources.memMib,\n })\n await fcRequest(apiSocketPath, 'PUT', '/boot-source', {\n kernel_image_path: kernelPath,\n initrd_path: initrdPath,\n boot_args: [\n 'console=ttyS0',\n 'reboot=k',\n 'panic=1',\n 'pci=off',\n 'net.ifnames=0',\n 'init=/init',\n `VM_ID=${spec.vmId}`,\n ...(spec.sessionId ? [`SESSION_ID=${spec.sessionId}`] : []),\n `STACK=${spec.stack}`,\n // base64: kernel cmdline is space-separated, raw presigned URLs are not safe\n ...(spec.appUrl ? [`APP_URL_B64=${Buffer.from(spec.appUrl).toString('base64')}`] : []),\n `GUEST_IP=${guestIp}`,\n `HOST_IP=${hostIp}`,\n ...(runMode === 'job' ? ['RUN_MODE=job'] : []),\n ...(envB64 ? [`ENV_B64=${envB64}`] : []),\n ].join(' '),\n })\n await fcRequest(apiSocketPath, 'PUT', '/network-interfaces/eth0', {\n iface_id: 'eth0',\n // AA = locally-administered unicast; encode subnet as last two bytes\n guest_mac: `AA:FC:00:00:${macHex(subnet >> 8)}:${macHex(subnet & 0xff)}`,\n host_dev_name: tapName,\n })\n await fcRequest(apiSocketPath, 'PUT', '/actions', { action_type: 'InstanceStart' })\n\n // A job's entrypoint may finish before it ever answers HTTP \u2014 the readiness gate below\n // only applies to persistent services.\n if (runMode !== 'job') await waitForHttp(guestIp, 8080)\n\n const metadata = { apiSocketPath, tapName, subnet, guestIp, pid: proc.pid }\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n metadata,\n }\n this.vms.set(spec.vmId, {\n handle,\n process: proc,\n pid: proc.pid,\n apiSocketPath,\n tapName,\n subnet,\n guestIp,\n runMode,\n startedAt,\n serialBuffer,\n })\n logger.info({ vmId: spec.vmId, guestIp, tapName, runMode }, 'firecracker vm ready')\n return handle\n }\n\n /** Scrapes JOB_EXIT_SENTINEL out of the buffered serial stdout and reports the result. */\n private reportJobResult(vmId: string, vm: ManagedVm): void {\n const output = Buffer.concat(vm.serialBuffer?.chunks ?? []).toString('utf8')\n const sentinelIndex = output.lastIndexOf(JOB_EXIT_SENTINEL)\n const exitCode =\n sentinelIndex === -1\n ? 1\n : Number.parseInt(output.slice(sentinelIndex + JOB_EXIT_SENTINEL.length), 10) || 0\n const stdout = sentinelIndex === -1 ? output : output.slice(0, sentinelIndex)\n\n const result: VmRunResult = {\n exitCode,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: '',\n truncated: (vm.serialBuffer?.bytes ?? 0) > MAX_OUTPUT_BYTES,\n durationMs: Date.now() - vm.startedAt,\n finishedAt: new Date().toISOString(),\n }\n logger.info({ vmId, exitCode }, 'firecracker job vm exited')\n this.deliverJobResult(vmId, result)\n }\n\n private deliverJobResult(vmId: string, result: VmRunResult): void {\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n await this.patchVmState(vmId, 'Paused')\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n await this.patchVmState(vmId, 'Resumed')\n return this.setRunning(vmId, true)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n await this.patchVmState(vmId, 'Paused')\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n await this.patchVmState(vmId, 'Resumed')\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n if (vm.process) {\n const proc = vm.process\n proc.kill('SIGKILL')\n await new Promise<void>((resolve) => {\n if (proc.exitCode !== null) return resolve()\n proc.once('exit', resolve)\n setTimeout(() => {\n proc.kill('SIGKILL')\n resolve()\n }, 3_000)\n })\n } else if (vm.pid) {\n // Reattached VM \u2014 no live ChildProcess to wait on; kill by the stored pid.\n try {\n process.kill(vm.pid, 'SIGKILL')\n } catch {\n /* already gone */\n }\n }\n\n this.usedSubnets.delete(vm.subnet)\n this.vms.delete(vmId)\n await execAsync(`ip link del ${vm.tapName}`).catch(() => {})\n await fs.rm(path.join(this.vmDataPath, vmId), { recursive: true, force: true })\n logger.info({ vmId }, 'firecracker vm destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n getSerialSource(vmId: string): SerialSource | undefined {\n const vm = this.vms.get(vmId)\n // Serial is piped over the child's inherited stdio \u2014 a reattached VM has no live\n // ChildProcess to read that from, so its serial console is unavailable until it's\n // recreated. Lifecycle control and HTTP proxying are unaffected.\n if (!vm?.process) return undefined\n return { type: 'pipe', process: vm.process }\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n /**\n * Recover a Firecracker VM after a worker restart: the process may well have survived, so\n * probe its API socket \u2014 if it answers, lifecycle control and HTTP proxying resume\n * normally. There's no live ChildProcess to reattach to, so destroy() falls back to\n * killing the stored pid, and the serial console is unavailable (see getSerialSource).\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as\n | {\n apiSocketPath?: string\n tapName?: string\n subnet?: number\n guestIp?: string\n pid?: number\n }\n | undefined\n if (!meta?.apiSocketPath || !meta.tapName || meta.subnet === undefined || !meta.guestIp) {\n return undefined\n }\n\n try {\n await withTimeout(fcRequest(meta.apiSocketPath, 'GET', '/', {}), 5_000)\n } catch {\n return undefined\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running: record.state === 'running',\n metadata: meta,\n }\n\n this.usedSubnets.add(meta.subnet)\n // Keep future tap names from colliding with this reattached one.\n const tapNumber = Number(meta.tapName.replace(/^fctap/, ''))\n if (Number.isFinite(tapNumber)) this.tapCounter = Math.max(this.tapCounter, tapNumber)\n\n this.vms.set(record.vmId, {\n handle,\n pid: meta.pid,\n apiSocketPath: meta.apiSocketPath,\n tapName: meta.tapName,\n subnet: meta.subnet,\n guestIp: meta.guestIp,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n\n // Note: same limitation as QemuExecutor.reattach \u2014 a job VM's serial buffer only ever\n // lived in the dead worker's memory, and a still-running one has no ChildProcess here to\n // detect its eventual exit (getSerialSource already documents the equivalent gap for the\n // live console). Not solved in v1.\n\n logger.info(\n { vmId: record.vmId, guestIp: meta.guestIp, tapName: meta.tapName },\n 'firecracker vm reattached',\n )\n return handle\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.vms.get(vmId)\n if (!vm?.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: vm.guestIp,\n port: 8080,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n private async patchVmState(vmId: string, state: 'Paused' | 'Resumed'): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n await fcRequest(vm.apiSocketPath, 'PATCH', '/vm', { state })\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n}\n\n// Send a request to the Firecracker REST API via Unix socket.\nfunction fcRequest(\n socketPath: string,\n method: string,\n urlPath: string,\n body: object,\n): Promise<object> {\n return new Promise((resolve, reject) => {\n const payload = JSON.stringify(body)\n const req = http.request(\n {\n socketPath,\n method,\n path: urlPath,\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(payload),\n Accept: 'application/json',\n },\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () => {\n const text = Buffer.concat(chunks).toString()\n if (res.statusCode && res.statusCode >= 400) {\n reject(new Error(`Firecracker ${method} ${urlPath} \u2192 ${res.statusCode}: ${text}`))\n } else {\n try {\n resolve(JSON.parse(text))\n } catch {\n resolve({})\n }\n }\n })\n },\n )\n req.on('error', reject)\n req.write(payload)\n req.end()\n })\n}\n\nfunction waitForSocket(socketPath: string, timeoutMs = 10_000): Promise<void> {\n return new Promise((resolve, reject) => {\n const deadline = Date.now() + timeoutMs\n const attempt = () => {\n if (Date.now() > deadline)\n return reject(new Error(`timed out waiting for Firecracker socket ${socketPath}`))\n const sock = net.createConnection(socketPath)\n sock.once('connect', () => {\n sock.destroy()\n resolve()\n })\n sock.once('error', () => setTimeout(attempt, 100))\n }\n attempt()\n })\n}\n\nfunction waitForHttp(host: string, port: number, timeoutMs = 60_000): Promise<void> {\n return new Promise((resolve, reject) => {\n const deadline = Date.now() + timeoutMs\n const attempt = () => {\n if (Date.now() > deadline)\n return reject(new Error(`timed out waiting for HTTP at ${host}:${port}`))\n const req = http.get(`http://${host}:${port}/health`, (res) => {\n if (res.statusCode && res.statusCode < 500) return resolve()\n res.resume()\n setTimeout(attempt, 1_000)\n })\n req.on('error', () => setTimeout(attempt, 1_000))\n req.setTimeout(2_000, () => {\n req.destroy()\n setTimeout(attempt, 1_000)\n })\n }\n attempt()\n })\n}\n", "import { execFile, spawn } from 'child_process'\nimport { promisify } from 'util'\nimport http from 'http'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmExecRequest,\n VmExecResult,\n VmFileWrite,\n VmRecord,\n VmRunMode,\n VmRunResult,\n VmWriteFilesResult,\n} from '@multiplayer-app/builder-types'\nimport type { DockerWorkerConfig } from '../config'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nconst DEFAULT_EXEC_TIMEOUT_MS = 60_000\nconst MAX_EXEC_TIMEOUT_MS = 300_000\nconst MAX_OUTPUT_BYTES = 1024 * 1024\nconst MAX_FILE_BYTES = 5 * 1024 * 1024\nconst WORKSPACE_DIR = '/workspace'\n\nconst execFileAsync = promisify(execFile)\n\ninterface ManagedVm {\n handle: VmHandle\n containerId: string\n containerName: string\n hostPort: number\n runMode: VmRunMode\n startedAt: number\n}\n\n/** Reject \"../\" and absolute paths, same rule MockExecutor applies to its own workspace. */\nfunction assertSafeWorkspacePath(relativePath: string): string {\n const normalized = relativePath.replace(/^([/\\\\])+/, '')\n if (normalized.split(/[/\\\\]/).includes('..')) {\n throw new Error(`Path escapes the VM workspace: ${relativePath}`)\n }\n return normalized\n}\n\n/**\n * Runs VMs as local Docker containers (one container per VM), via the `docker` CLI \u2014\n * same shell-out style QemuExecutor uses for qemu-system-*. No kernel/HVF/KVM needed,\n * so it's the lowest-friction local engine: just Docker Desktop/OrbStack.\n *\n * Unlike the other local engines, the container's process is directly reachable from\n * the host, so exec/writeFiles are real (`docker exec` / `docker cp`) rather than\n * MockExecutor-only stand-ins. pause/resume map to `docker pause`/`unpause` (a real\n * cgroup freeze); stop/restore map to `docker stop`/`start`, so every VmAction does\n * something meaningful \u2014 unlike QEMU (stop/restore alias pause/resume) or Fargate\n * (only stop works).\n */\nexport class DockerExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly usedPorts = new Set<number>()\n private readonly bin: string\n /** Job VMs that exited before onExit() was called to claim the result (create() \u2192 onExit() isn't atomic). */\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n\n constructor(private readonly config: DockerWorkerConfig) {\n this.bin = config.bin\n }\n\n private allocatePort(): number {\n for (let p = this.config.portRangeStart; p <= this.config.portRangeEnd; p++) {\n if (!this.usedPorts.has(p)) {\n this.usedPorts.add(p)\n return p\n }\n }\n throw new Error('no free ports in docker port range')\n }\n\n private async resolveImage(stack: string): Promise<string> {\n const explicit = this.config.stackImages[stack]\n if (explicit) return explicit\n\n const { imagePrefix, imageTag } = this.config\n const stackImage = `${imagePrefix}-${stack}:${imageTag}`\n if (await this.imageExists(stackImage)) return stackImage\n\n const genericImage = `${imagePrefix}-generic:${imageTag}`\n if (await this.imageExists(genericImage)) return genericImage\n\n throw new Error(\n `no local docker image for stack \"${stack}\" (${stackImage}) \u2014 run scripts/setup-docker-images.sh`,\n )\n }\n\n private async imageExists(image: string): Promise<boolean> {\n try {\n await execFileAsync(this.bin, ['image', 'inspect', image])\n return true\n } catch {\n return false\n }\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const image = await this.resolveImage(spec.stack)\n const hostPort = this.allocatePort()\n const containerName = `multiplayer-vm-${spec.vmId}`\n\n const args = [\n 'run',\n '-d',\n '--name',\n containerName,\n '-p',\n `127.0.0.1:${hostPort}:${this.config.guestPort}`,\n '--memory',\n `${spec.resources.memMib}m`,\n '--cpus',\n String(spec.resources.vcpuCount),\n '-e',\n `VM_ID=${spec.vmId}`,\n '-e',\n `STACK=${spec.stack}`,\n ...(spec.sessionId ? ['-e', `SESSION_ID=${spec.sessionId}`] : []),\n ...(spec.appUrl ? ['-e', `APP_URL=${spec.appUrl}`] : []),\n ...Object.entries(spec.env ?? {}).flatMap(([key, value]) => ['-e', `${key}=${value}`]),\n ...(this.config.network ? ['--network', this.config.network] : []),\n image,\n ]\n\n logger.info({ vmId: spec.vmId, bin: this.bin, args }, 'starting docker container')\n let containerId: string\n try {\n const { stdout } = await execFileAsync(this.bin, args)\n containerId = stdout.trim()\n } catch (error) {\n this.usedPorts.delete(hostPort)\n throw error\n }\n\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n metadata: { containerId, containerName, hostPort },\n }\n const runMode = spec.runMode ?? 'service'\n this.vms.set(spec.vmId, {\n handle,\n containerId,\n containerName,\n hostPort,\n runMode,\n startedAt: Date.now(),\n })\n this.watchExit(spec.vmId, containerId)\n\n // A job's entrypoint may run to completion before the agent ever comes up (e.g. it never\n // listens on a port) \u2014 waitForAgent would hang forever, so job VMs skip that readiness gate.\n if (runMode !== 'job') await this.waitForAgent(hostPort)\n logger.info({ vmId: spec.vmId, containerId, hostPort, runMode }, 'docker vm ready')\n return handle\n }\n\n /**\n * For 'service' VMs: frees the allocated port once the container exits on its own (crash,\n * OOM kill, `docker stop` from outside us) \u2014 same as before.\n * For 'job' VMs: captures the exit code + logs, tears the container down, and reports the\n * result to whoever calls onExit() (immediately if they already have, otherwise once they do).\n */\n private watchExit(vmId: string, containerId: string): void {\n execFileAsync(this.bin, ['wait', containerId])\n .catch(() => ({ stdout: '' }))\n .then(async ({ stdout }) => {\n const vm = this.vms.get(vmId)\n if (!vm || vm.containerId !== containerId) return\n\n if (vm.runMode !== 'job') {\n vm.handle = { ...vm.handle, running: false }\n return\n }\n\n const exitCode = Number.parseInt(stdout.trim(), 10) || 0\n const logs = await this.captureLogs(containerId)\n await execFileAsync(this.bin, ['rm', '-f', containerId]).catch((error: Error) =>\n logger.warn({ vmId, err: error }, 'docker rm after job exit failed'),\n )\n this.usedPorts.delete(vm.hostPort)\n // Resources are already freed above, but the map entry stays (marked not-running)\n // until onExit() claims the result \u2014 MultiEngineExecutor.route() needs get(vmId) to\n // keep finding it in the window between exit and onExit() being called (e.g. right\n // after a reattach discovers the job already finished).\n vm.handle = { ...vm.handle, running: false }\n\n const result: VmRunResult = {\n exitCode,\n ...logs,\n durationMs: Date.now() - vm.startedAt,\n finishedAt: new Date().toISOString(),\n }\n logger.info({ vmId, exitCode }, 'docker job vm exited')\n this.deliverJobResult(vmId, result)\n })\n }\n\n private deliverJobResult(vmId: string, result: VmRunResult): void {\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n /** `docker logs` mirrors the container's stdout/stderr onto its own, so the CLI's streams stay separate. */\n private async captureLogs(\n containerId: string,\n ): Promise<{ stdout: string; stderr: string; truncated: boolean }> {\n try {\n const { stdout, stderr } = await execFileAsync(this.bin, ['logs', containerId], {\n maxBuffer: MAX_OUTPUT_BYTES,\n })\n return {\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n truncated: stdout.length > MAX_OUTPUT_BYTES || stderr.length > MAX_OUTPUT_BYTES,\n }\n } catch (error) {\n const failed = error as NodeJS.ErrnoException & { stdout?: string; stderr?: string }\n return {\n stdout: (failed.stdout ?? '').slice(0, MAX_OUTPUT_BYTES),\n stderr: (failed.stderr ?? '').slice(0, MAX_OUTPUT_BYTES),\n truncated: true,\n }\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['pause', vm.containerId])\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['unpause', vm.containerId])\n return this.setRunning(vmId, true)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['stop', vm.containerId])\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['start', vm.containerId])\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n await execFileAsync(this.bin, ['rm', '-f', vm.containerId]).catch((error: Error) =>\n logger.warn({ vmId, err: error }, 'docker rm on destroy failed'),\n )\n this.usedPorts.delete(vm.hostPort)\n this.vms.delete(vmId)\n logger.info({ vmId }, 'docker vm destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n /**\n * Recover a container after a worker restart: it's an independent process the\n * Docker daemon owns, so just re-inspect it by ID and rebuild the local handle.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as\n | { containerId?: string; containerName?: string; hostPort?: number }\n | undefined\n if (!meta?.containerId || meta.hostPort === undefined) return undefined\n\n let running: boolean\n try {\n const { stdout } = await execFileAsync(this.bin, [\n 'inspect',\n '-f',\n '{{.State.Running}}',\n meta.containerId,\n ])\n running = stdout.trim() === 'true'\n } catch {\n return undefined\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running,\n metadata: meta,\n }\n this.usedPorts.add(meta.hostPort)\n this.vms.set(record.vmId, {\n handle,\n containerId: meta.containerId,\n containerName: meta.containerName ?? `multiplayer-vm-${record.vmId}`,\n hostPort: meta.hostPort,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n\n if (running) {\n this.watchExit(record.vmId, meta.containerId)\n } else if (record.runMode === 'job') {\n // The job already finished while this worker was offline (or restarting) \u2014 capture\n // whatever's left of it now instead of waiting on watchExit for a container that's\n // already dead, since `docker wait` never resolves for a container in a terminal state.\n void this.finishExitedJob(record.vmId, meta.containerId)\n }\n\n logger.info({ vmId: record.vmId, containerId: meta.containerId }, 'docker vm reattached')\n return handle\n }\n\n /** Same capture-and-report sequence as watchExit's job branch, for a container found already stopped. */\n private async finishExitedJob(vmId: string, containerId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n let exitCode = 0\n try {\n const { stdout } = await execFileAsync(this.bin, [\n 'inspect',\n '-f',\n '{{.State.ExitCode}}',\n containerId,\n ])\n exitCode = Number.parseInt(stdout.trim(), 10) || 0\n } catch {\n // container gone entirely \u2014 best effort, report a generic failure below\n }\n\n const logs = await this.captureLogs(containerId)\n await execFileAsync(this.bin, ['rm', '-f', containerId]).catch(() => {})\n this.usedPorts.delete(vm.hostPort)\n vm.handle = { ...vm.handle, running: false }\n\n const result: VmRunResult = {\n exitCode,\n ...logs,\n durationMs: Date.now() - vm.startedAt,\n finishedAt: new Date().toISOString(),\n }\n this.deliverJobResult(vmId, result)\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.mustGet(vmId)\n if (!vm.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: '127.0.0.1',\n port: vm.hostPort,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n async exec(vmId: string, request: VmExecRequest): Promise<VmExecResult> {\n const vm = this.mustGet(vmId)\n const cwd = request.cwd\n ? `${WORKSPACE_DIR}/${assertSafeWorkspacePath(request.cwd)}`\n : WORKSPACE_DIR\n const timeoutMs = Math.min(request.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS, MAX_EXEC_TIMEOUT_MS)\n const startedAt = Date.now()\n\n return new Promise((resolve) => {\n execFile(\n this.bin,\n ['exec', '-w', cwd, vm.containerId, '/bin/sh', '-c', request.command],\n { timeout: timeoutMs, maxBuffer: MAX_OUTPUT_BYTES },\n (error, stdout, stderr) => {\n const failed = error as\n | (NodeJS.ErrnoException & { code?: number | string; killed?: boolean })\n | null\n const timedOut = Boolean(failed?.killed)\n const truncated = failed?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'\n resolve({\n exitCode: typeof failed?.code === 'number' ? failed.code : failed ? 1 : 0,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n durationMs: Date.now() - startedAt,\n truncated: Boolean(truncated),\n timedOut,\n })\n },\n )\n })\n }\n\n async writeFiles(vmId: string, files: VmFileWrite[]): Promise<VmWriteFilesResult> {\n const vm = this.mustGet(vmId)\n const written: Array<{ path: string; bytes: number }> = []\n\n for (const file of files) {\n const relativePath = assertSafeWorkspacePath(file.path)\n const buffer = Buffer.from(file.content, file.encoding === 'base64' ? 'base64' : 'utf8')\n if (buffer.byteLength > MAX_FILE_BYTES) {\n throw new Error(\n `File too large (${buffer.byteLength} bytes, max ${MAX_FILE_BYTES}): ${file.path}`,\n )\n }\n\n const dir = relativePath.includes('/')\n ? relativePath.slice(0, relativePath.lastIndexOf('/'))\n : ''\n if (dir) {\n await execFileAsync(this.bin, [\n 'exec',\n vm.containerId,\n 'mkdir',\n '-p',\n `${WORKSPACE_DIR}/${dir}`,\n ])\n }\n await this.copyIntoContainer(vm.containerId, `${WORKSPACE_DIR}/${relativePath}`, buffer)\n written.push({ path: relativePath, bytes: buffer.byteLength })\n }\n\n logger.info({ vmId, files: written.length }, 'docker vm files written')\n return { written }\n }\n\n /** `docker cp` needs a tar stream on stdin; build the smallest valid ustar archive for one file. */\n private copyIntoContainer(containerId: string, destPath: string, content: Buffer): Promise<void> {\n const entryName = destPath.replace(/^\\//, '')\n const tarStream = buildSingleFileTar(entryName, content)\n\n return new Promise((resolve, reject) => {\n const proc = spawn(this.bin, ['cp', '-', `${containerId}:/`], {\n stdio: ['pipe', 'ignore', 'pipe'],\n })\n let stderr = ''\n proc.stderr?.on('data', (d: Buffer) => {\n stderr += d.toString()\n })\n proc.on('error', reject)\n proc.on('exit', (code) =>\n code === 0 ? resolve() : reject(new Error(`docker cp exited ${code}: ${stderr}`)),\n )\n proc.stdin.end(tarStream)\n })\n }\n\n private mustGet(vmId: string): ManagedVm {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n return vm\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.mustGet(vmId)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n\n private async waitForAgent(port: number, timeoutMs = 30_000): Promise<void> {\n const deadline = Date.now() + timeoutMs\n for (;;) {\n const ok = await new Promise<boolean>((resolve) => {\n const req = http.get({ host: '127.0.0.1', port, path: '/', timeout: 2_000 }, (res) => {\n res.resume()\n resolve(true)\n })\n req.on('error', () => resolve(false))\n req.on('timeout', () => {\n req.destroy()\n resolve(false)\n })\n })\n if (ok) return\n if (Date.now() > deadline)\n throw new Error(`timed out waiting for docker vm agent on port ${port}`)\n await new Promise((resolve) => setTimeout(resolve, 500))\n }\n }\n}\n\n/** POSIX ustar archive containing exactly one regular file \u2014 enough for `docker cp -`. */\nfunction buildSingleFileTar(name: string, content: Buffer): Buffer {\n const header = Buffer.alloc(512)\n header.write(name, 0, 'utf8')\n header.write('0000644\\0', 100, 'utf8') // mode\n header.write('0000000\\0', 108, 'utf8') // uid\n header.write('0000000\\0', 116, 'utf8') // gid\n header.write(content.byteLength.toString(8).padStart(11, '0') + '\\0', 124, 'utf8') // size (octal)\n header.write(\n Math.floor(Date.now() / 1000)\n .toString(8)\n .padStart(11, '0') + '\\0',\n 136,\n 'utf8',\n ) // mtime\n header.write(' ', 148, 'utf8') // checksum placeholder (spaces while computing)\n header.write('0', 156, 'utf8') // typeflag: regular file\n header.write('ustar\\0', 257, 'utf8')\n header.write('00', 263, 'utf8')\n\n let checksum = 0\n for (const byte of header) checksum += byte\n header.write(checksum.toString(8).padStart(6, '0') + '\\0 ', 148, 'utf8')\n\n const paddedContentLength = Math.ceil(content.byteLength / 512) * 512\n const paddedContent = Buffer.alloc(paddedContentLength)\n content.copy(paddedContent)\n\n return Buffer.concat([header, paddedContent, Buffer.alloc(1024)]) // two 512-byte zero blocks terminate the archive\n}\n", "import { execFile, spawn } from 'child_process'\nimport { promisify } from 'util'\nimport fs from 'fs/promises'\nimport os from 'os'\nimport path from 'path'\nimport http from 'http'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmExecRequest,\n VmExecResult,\n VmFileWrite,\n VmRecord,\n VmRunMode,\n VmRunResult,\n VmWriteFilesResult,\n} from '@multiplayer-app/builder-types'\nimport type { DockerSandboxWorkerConfig } from '../config'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nconst DEFAULT_EXEC_TIMEOUT_MS = 60_000\nconst MAX_EXEC_TIMEOUT_MS = 300_000\nconst MAX_OUTPUT_BYTES = 1024 * 1024\nconst MAX_FILE_BYTES = 5 * 1024 * 1024\nconst WORKSPACE_DIR = '/workspace'\nconst AGENT_DIR = '/app'\n\nconst execFileAsync = promisify(execFile)\n\ninterface ManagedVm {\n handle: VmHandle\n sandboxName: string\n vmDir: string\n hostPort: number\n agentCommand: string\n runMode: VmRunMode\n startedAt: number\n}\n\n/** Reject \"../\" and absolute paths, same rule MockExecutor/DockerExecutor apply to their workspace. */\nfunction assertSafeWorkspacePath(relativePath: string): string {\n const normalized = relativePath.replace(/^([/\\\\])+/, '')\n if (normalized.split(/[/\\\\]/).includes('..')) {\n throw new Error(`Path escapes the VM workspace: ${relativePath}`)\n }\n return normalized\n}\n\n/** sbx sandbox names: letters/digits/hyphens/periods only, starting with a letter or digit. */\nfunction sandboxNameFor(vmId: string): string {\n return `mp-${vmId.replace(/[^a-zA-Z0-9.-]/g, '-')}`\n}\n\n/**\n * Runs VMs as Docker Sandboxes (`sbx`, docker.com/products/docker-sandboxes) \u2014 Docker's own\n * microVM-per-sandbox product, originally built for safely running AI coding agents. Reuses\n * the exact same per-stack images `docker` (DockerExecutor) already builds via\n * scripts/setup-docker-images.sh, bridged into sbx's own image store with `docker save` +\n * `sbx template load`.\n *\n * Two things `sbx` does differently from plain `docker run`, driven by its \"isolated agent\n * sandbox\" design rather than \"run this image\" design:\n * - `sbx create` doesn't execute the image's own Dockerfile CMD (confirmed via `ps aux`:\n * PID 1 is a `sleep infinity` placeholder) \u2014 the guest agent is launched explicitly via\n * `sbx exec -d` right after creation.\n * - `sbx create`/`run` require a real host directory to mount as the sandbox's workspace;\n * unrelated to the image's own internal /workspace (used by the guest agent for release\n * deploys) \u2014 just a disposable per-VM directory to satisfy the CLI.\n *\n * No `docker pause`-equivalent primitive exists here, so pause/resume alias stop/restore,\n * same precedent QemuExecutor already sets for engines without a distinct freeze primitive.\n */\nexport class DockerSandboxExecutor implements Executor {\n private readonly vms = new Map<string, ManagedVm>()\n private readonly usedPorts = new Set<number>()\n private readonly loadedTemplates = new Set<string>()\n private readonly bin: string\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n\n constructor(private readonly config: DockerSandboxWorkerConfig) {\n this.bin = config.bin\n }\n\n private allocatePort(): number {\n for (let p = this.config.portRangeStart; p <= this.config.portRangeEnd; p++) {\n if (!this.usedPorts.has(p)) {\n this.usedPorts.add(p)\n return p\n }\n }\n throw new Error('no free ports in docker-sandbox port range')\n }\n\n private resolveAgentCommand(stack: string): string {\n return (\n this.config.stackAgentCommands[stack] ??\n this.config.stackAgentCommands.generic ??\n 'node app.js'\n )\n }\n\n /** Local `docker` image tag for a stack, same resolution order as DockerExecutor.resolveImage. */\n private localImageFor(stack: string): string {\n const { imagePrefix, imageTag } = this.config\n return `${imagePrefix}-${stack}:${imageTag}`\n }\n\n /** Bridges the local docker image into sbx's own image store once per process; returns its ref. */\n private async ensureTemplateLoaded(stack: string): Promise<string> {\n const explicit = this.config.stackTemplates[stack]\n if (explicit) return explicit\n\n const localImage = this.localImageFor(stack)\n const templateRef = `docker.io/library/${localImage}`\n if (this.loadedTemplates.has(templateRef)) return templateRef\n\n const tmpFile = path.join(os.tmpdir(), `sbx-template-${stack}-${Date.now()}.tar`)\n try {\n await execFileAsync('docker', ['save', localImage, '-o', tmpFile])\n await execFileAsync(this.bin, ['template', 'load', tmpFile])\n } catch (error) {\n throw new Error(\n `failed to bridge local image \"${localImage}\" into sbx \u2014 run scripts/setup-docker-images.sh: ${error}`,\n )\n } finally {\n await fs.rm(tmpFile, { force: true })\n }\n\n this.loadedTemplates.add(templateRef)\n return templateRef\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const templateRef = await this.ensureTemplateLoaded(spec.stack)\n const agentCommand = this.resolveAgentCommand(spec.stack)\n const sandboxName = sandboxNameFor(spec.vmId)\n const hostPort = this.allocatePort()\n const vmDir = path.join(this.config.workspaceRoot, spec.vmId)\n await fs.mkdir(vmDir, { recursive: true })\n const memMib = Math.max(spec.resources.memMib, this.config.minMemoryMib)\n\n const createArgs = [\n 'create',\n 'shell',\n vmDir,\n '--template',\n templateRef,\n '--name',\n sandboxName,\n '-p',\n `127.0.0.1:${hostPort}:${this.config.guestPort}`,\n '-m',\n `${memMib}m`,\n '--cpus',\n String(spec.resources.vcpuCount),\n '-e',\n `VM_ID=${spec.vmId}`,\n '-e',\n `STACK=${spec.stack}`,\n ...(spec.sessionId ? ['-e', `SESSION_ID=${spec.sessionId}`] : []),\n ...(spec.appUrl ? ['-e', `APP_URL=${spec.appUrl}`] : []),\n ...Object.entries(spec.env ?? {}).flatMap(([key, value]) => ['-e', `${key}=${value}`]),\n ]\n\n const runMode = spec.runMode ?? 'service'\n\n logger.info({ vmId: spec.vmId, bin: this.bin, args: createArgs }, 'creating docker sandbox')\n try {\n await execFileAsync(this.bin, createArgs)\n if (runMode !== 'job') this.launchAgent(sandboxName, agentCommand)\n } catch (error) {\n this.usedPorts.delete(hostPort)\n await fs.rm(vmDir, { recursive: true, force: true }).catch(() => {})\n throw error\n }\n\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: { ...spec.resources, memMib },\n running: true,\n metadata: { sandboxName, hostPort, vmDir, agentCommand },\n }\n this.vms.set(spec.vmId, {\n handle,\n sandboxName,\n vmDir,\n hostPort,\n agentCommand,\n runMode,\n startedAt: Date.now(),\n })\n\n if (runMode === 'job') {\n this.runJob(spec.vmId, sandboxName, agentCommand)\n } else {\n await this.waitForAgent(hostPort)\n }\n logger.info({ vmId: spec.vmId, sandboxName, hostPort, runMode }, 'docker sandbox ready')\n return handle\n }\n\n /**\n * Job mode: unlike `launchAgent` (fire-and-forget `sbx exec -d`, used for persistent\n * services), run the entrypoint in the *foreground* \u2014 the CLI call itself blocks until the\n * command exits and hands back its exit code + captured stdout/stderr directly, so there's\n * no separate wait/logs step needed the way DockerExecutor needs for a backgrounded container.\n */\n private runJob(vmId: string, sandboxName: string, agentCommand: string): void {\n const startedAt = this.vms.get(vmId)?.startedAt ?? Date.now()\n execFile(\n this.bin,\n ['exec', '-w', AGENT_DIR, sandboxName, '/bin/sh', '-c', agentCommand],\n { maxBuffer: MAX_OUTPUT_BYTES },\n (error, stdout, stderr) => {\n const failed = error as (NodeJS.ErrnoException & { code?: number | string }) | null\n const truncated = failed?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'\n const result: VmRunResult = {\n exitCode: typeof failed?.code === 'number' ? failed.code : failed ? 1 : 0,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n truncated: Boolean(truncated),\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n }\n void this.finishJob(vmId, sandboxName, result)\n },\n )\n }\n\n private async finishJob(vmId: string, sandboxName: string, result: VmRunResult): Promise<void> {\n logger.info({ vmId, exitCode: result.exitCode }, 'docker sandbox job exited')\n await execFileAsync(this.bin, ['rm', '-f', sandboxName]).catch((error: Error) =>\n logger.warn({ vmId, err: error }, 'sbx rm after job exit failed'),\n )\n const vm = this.vms.get(vmId)\n if (vm) {\n await fs.rm(vm.vmDir, { recursive: true, force: true }).catch(() => {})\n this.usedPorts.delete(vm.hostPort)\n // Resources are already freed above, but the map entry stays (marked not-running)\n // until onExit() claims the result \u2014 see docker-executor's deliverJobResult for why.\n vm.handle = { ...vm.handle, running: false }\n }\n\n this.deliverJobResult(vmId, result)\n }\n\n private deliverJobResult(vmId: string, result: VmRunResult): void {\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n /**\n * `sbx create shell` doesn't run the image's own CMD \u2014 launch the guest agent explicitly.\n *\n * Fire-and-forget: `sbx exec -d` (detach) launches the background command correctly but its\n * own CLI process then hangs indefinitely instead of returning \u2014 confirmed live (the agent\n * was already answering on its port while the CLI call itself sat stuck for 14+ minutes,\n * needing a kill -9). `waitForAgent`'s port poll is the real readiness signal here, not this\n * process exiting, so it's spawned detached and never awaited.\n */\n private launchAgent(sandboxName: string, agentCommand: string): void {\n const proc = spawn(\n this.bin,\n ['exec', '-d', '-w', AGENT_DIR, sandboxName, '/bin/sh', '-c', agentCommand],\n {\n stdio: 'ignore',\n },\n )\n proc.on('error', (error) =>\n logger.warn({ sandboxName, err: error }, 'sbx exec -d failed to spawn'),\n )\n proc.unref()\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n return this.stop(vmId)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n return this.restore(vmId)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['stop', vm.sandboxName])\n return this.setRunning(vmId, false)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await execFileAsync(this.bin, ['run', '--name', vm.sandboxName, '--detached'])\n const alreadyUp = await this.probeAgent(vm.hostPort)\n if (!alreadyUp) this.launchAgent(vm.sandboxName, vm.agentCommand)\n await this.waitForAgent(vm.hostPort)\n return this.setRunning(vmId, true)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n await execFileAsync(this.bin, ['rm', '-f', vm.sandboxName]).catch((error: Error) =>\n logger.warn({ vmId, err: error }, 'sbx rm on destroy failed'),\n )\n await fs.rm(vm.vmDir, { recursive: true, force: true }).catch(() => {})\n this.usedPorts.delete(vm.hostPort)\n this.vms.delete(vmId)\n logger.info({ vmId }, 'docker sandbox destroyed')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n /**\n * Recover a sandbox after a worker restart: it's owned by the independent `sandboxd`\n * daemon, so a liveness probe against its name is enough to confirm it's still there.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as\n | { sandboxName?: string; hostPort?: number; vmDir?: string; agentCommand?: string }\n | undefined\n if (!meta?.sandboxName || meta.hostPort === undefined || !meta.vmDir || !meta.agentCommand)\n return undefined\n\n let running: boolean\n try {\n await execFileAsync(this.bin, ['exec', meta.sandboxName, 'true'])\n running = true\n } catch {\n try {\n await execFileAsync(this.bin, ['ls', '--json'])\n running = false // ran but the sandbox isn't reachable \u2014 treat as stopped, not gone\n } catch {\n return undefined\n }\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running,\n metadata: meta,\n }\n this.usedPorts.add(meta.hostPort)\n this.vms.set(record.vmId, {\n handle,\n sandboxName: meta.sandboxName,\n vmDir: meta.vmDir,\n hostPort: meta.hostPort,\n agentCommand: meta.agentCommand,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n\n if (record.runMode === 'job') {\n // The job's entrypoint ran as this worker's own foreground child process (see runJob) \u2014\n // it died with the worker, so there's nothing left to resume watching. Report it as\n // failed rather than leaving the record stuck in 'running' forever.\n void this.finishJob(record.vmId, meta.sandboxName, {\n exitCode: -1,\n stdout: '',\n stderr: 'worker restarted while this job was still running',\n truncated: false,\n durationMs: Date.now() - (Date.parse(record.createdAt) || Date.now()),\n finishedAt: new Date().toISOString(),\n })\n }\n\n logger.info({ vmId: record.vmId, sandboxName: meta.sandboxName }, 'docker sandbox reattached')\n return handle\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.mustGet(vmId)\n if (!vm.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: '127.0.0.1',\n port: vm.hostPort,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n async exec(vmId: string, request: VmExecRequest): Promise<VmExecResult> {\n const vm = this.mustGet(vmId)\n const cwd = request.cwd\n ? `${WORKSPACE_DIR}/${assertSafeWorkspacePath(request.cwd)}`\n : WORKSPACE_DIR\n const timeoutMs = Math.min(request.timeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS, MAX_EXEC_TIMEOUT_MS)\n const startedAt = Date.now()\n\n return new Promise((resolve) => {\n execFile(\n this.bin,\n ['exec', '-w', cwd, vm.sandboxName, '/bin/sh', '-c', request.command],\n { timeout: timeoutMs, maxBuffer: MAX_OUTPUT_BYTES },\n (error, stdout, stderr) => {\n const failed = error as\n | (NodeJS.ErrnoException & { code?: number | string; killed?: boolean })\n | null\n const timedOut = Boolean(failed?.killed)\n const truncated = failed?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'\n resolve({\n exitCode: typeof failed?.code === 'number' ? failed.code : failed ? 1 : 0,\n stdout: stdout.slice(0, MAX_OUTPUT_BYTES),\n stderr: stderr.slice(0, MAX_OUTPUT_BYTES),\n durationMs: Date.now() - startedAt,\n truncated: Boolean(truncated),\n timedOut,\n })\n },\n )\n })\n }\n\n async writeFiles(vmId: string, files: VmFileWrite[]): Promise<VmWriteFilesResult> {\n const vm = this.mustGet(vmId)\n const written: Array<{ path: string; bytes: number }> = []\n\n for (const file of files) {\n const relativePath = assertSafeWorkspacePath(file.path)\n const buffer = Buffer.from(file.content, file.encoding === 'base64' ? 'base64' : 'utf8')\n if (buffer.byteLength > MAX_FILE_BYTES) {\n throw new Error(\n `File too large (${buffer.byteLength} bytes, max ${MAX_FILE_BYTES}): ${file.path}`,\n )\n }\n\n const dir = relativePath.includes('/')\n ? relativePath.slice(0, relativePath.lastIndexOf('/'))\n : ''\n if (dir) {\n await execFileAsync(this.bin, [\n 'exec',\n vm.sandboxName,\n 'mkdir',\n '-p',\n `${WORKSPACE_DIR}/${dir}`,\n ])\n }\n\n // sbx cp takes a real host path on one side \u2014 simpler than DockerExecutor's tar-over-stdin hack.\n const tmpFile = path.join(\n os.tmpdir(),\n `sbx-write-${vmId}-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n )\n await fs.writeFile(tmpFile, buffer)\n try {\n await execFileAsync(this.bin, [\n 'cp',\n tmpFile,\n `${vm.sandboxName}:${WORKSPACE_DIR}/${relativePath}`,\n ])\n } finally {\n await fs.rm(tmpFile, { force: true })\n }\n written.push({ path: relativePath, bytes: buffer.byteLength })\n }\n\n logger.info({ vmId, files: written.length }, 'docker sandbox files written')\n return { written }\n }\n\n private mustGet(vmId: string): ManagedVm {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n return vm\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.mustGet(vmId)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n\n private async probeAgent(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const req = http.get({ host: '127.0.0.1', port, path: '/', timeout: 2_000 }, (res) => {\n res.resume()\n resolve(true)\n })\n req.on('error', () => resolve(false))\n req.on('timeout', () => {\n req.destroy()\n resolve(false)\n })\n })\n }\n\n private async waitForAgent(port: number, timeoutMs = 30_000): Promise<void> {\n const deadline = Date.now() + timeoutMs\n for (;;) {\n if (await this.probeAgent(port)) return\n if (Date.now() > deadline)\n throw new Error(`timed out waiting for docker sandbox agent on port ${port}`)\n await new Promise((resolve) => setTimeout(resolve, 500))\n }\n }\n}\n", "import http from 'http'\nimport https from 'https'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmRunResult,\n} from '@multiplayer-app/builder-types'\nimport type { Executor, VmHandle, VmSpec } from './types'\nimport { withTimeout } from './reattach-utils'\n\nconst JOB_POLL_INTERVAL_MS = 3_000\n\nexport interface RemoteExecutorConfig {\n agentUrl: string // e.g. http://192.168.1.10:4040\n authToken?: string\n}\n\nexport class RemoteExecutor implements Executor {\n private readonly base: string\n private readonly headers: Record<string, string>\n // The remote agent is the actual source of truth, but MultiEngineExecutor.route() (used by\n // pause/resume/stop/restore/destroy/proxyHttp/exec/writeFiles) needs get() to find the\n // right executor for a vmId \u2014 cache the handle each call returns so it does.\n private readonly vms = new Map<string, VmHandle>()\n private readonly jobStartedAt = new Map<string, number>()\n\n constructor(config: RemoteExecutorConfig) {\n this.base = config.agentUrl.replace(/\\/$/, '')\n this.headers = {\n 'Content-Type': 'application/json',\n ...(config.authToken ? { Authorization: `Bearer ${config.authToken}` } : {}),\n }\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const handle = await this.request<VmHandle>('POST', '/vms', spec)\n this.vms.set(spec.vmId, handle)\n if (spec.runMode === 'job') this.jobStartedAt.set(spec.vmId, Date.now())\n return handle\n }\n\n /**\n * The remote agent's own wire protocol (VmHandle) has no exit-code/output field \u2014 extending\n * it is out of this repo's control, so this only detects completion (poll GET /vms/:vmId\n * until running flips false) without a real exit code or captured output. Good enough to\n * unblock the record from being stuck in 'running' forever; a real RemoteExecutor deployment\n * wanting full job support needs its agent protocol extended first.\n */\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const startedAt = this.jobStartedAt.get(vmId) ?? Date.now()\n const poll = async () => {\n const handle = await this.request<VmHandle>('GET', `/vms/${vmId}`).catch(() => undefined)\n if (handle) this.vms.set(vmId, handle)\n\n if (!handle || !handle.running) {\n this.jobStartedAt.delete(vmId)\n this.vms.delete(vmId)\n handler({\n exitCode: 0,\n stdout: '',\n stderr:\n 'remote engine does not report job exit codes/output \u2014 completion detected via polling only',\n truncated: false,\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n })\n return\n }\n setTimeout(() => void poll(), JOB_POLL_INTERVAL_MS)\n }\n void poll()\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n return this.updateCached(vmId, await this.request('POST', `/vms/${vmId}/pause`))\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n return this.updateCached(vmId, await this.request('POST', `/vms/${vmId}/resume`))\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n return this.updateCached(vmId, await this.request('POST', `/vms/${vmId}/stop`))\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n return this.updateCached(vmId, await this.request('POST', `/vms/${vmId}/restore`))\n }\n\n async destroy(vmId: string): Promise<void> {\n await this.request('DELETE', `/vms/${vmId}`)\n this.vms.delete(vmId)\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()]\n }\n\n /**\n * Recover a remote-agent VM after a worker restart. The agent owns the actual VM state\n * independently of this process, so reattaching is just confirming it still knows about\n * this vmId and re-populating the local get()/list() cache above.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n try {\n const handle = await withTimeout(this.request<VmHandle>('GET', `/vms/${record.vmId}`), 5_000)\n this.vms.set(record.vmId, handle)\n return handle\n } catch {\n return undefined\n }\n }\n\n private updateCached(vmId: string, handle: VmHandle): VmHandle {\n this.vms.set(vmId, handle)\n return handle\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const result = await this.request<{\n statusCode: number\n headers: Record<string, string>\n body?: string\n }>('POST', `/vms/${vmId}/proxy`, {\n method: request.method,\n path: request.path,\n headers: request.headers,\n body: request.body?.toString('base64'),\n })\n\n return {\n statusCode: result.statusCode,\n headers: result.headers,\n body: result.body ? Buffer.from(result.body, 'base64') : Buffer.alloc(0),\n }\n }\n\n private request<T = unknown>(method: string, path: string, body?: unknown): Promise<T> {\n const url = new URL(this.base + path)\n const lib = url.protocol === 'https:' ? https : http\n const payload = body !== undefined ? JSON.stringify(body) : undefined\n\n return new Promise((resolve, reject) => {\n const req = lib.request(\n {\n hostname: url.hostname,\n port: url.port || (url.protocol === 'https:' ? 443 : 80),\n path: url.pathname,\n method,\n headers: {\n ...this.headers,\n ...(payload ? { 'Content-Length': Buffer.byteLength(payload) } : {}),\n },\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () => {\n const text = Buffer.concat(chunks).toString()\n if (res.statusCode && res.statusCode >= 400) {\n reject(new Error(`vm-agent ${method} ${path} \u2192 ${res.statusCode}: ${text}`))\n return\n }\n if (res.statusCode === 204 || !text) {\n resolve(undefined as T)\n return\n }\n try {\n resolve(JSON.parse(text) as T)\n } catch {\n resolve(text as unknown as T)\n }\n })\n },\n )\n req.on('error', reject)\n if (payload) req.write(payload)\n req.end()\n })\n }\n}\n", "import https from 'https'\nimport {\n LambdaMicrovmsClient,\n RunMicrovmCommand,\n SuspendMicrovmCommand,\n ResumeMicrovmCommand,\n TerminateMicrovmCommand,\n GetMicrovmCommand,\n CreateMicrovmAuthTokenCommand,\n} from '@aws-sdk/client-lambda-microvms'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmStack,\n} from '@multiplayer-app/builder-types'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nexport interface LambdaMicrovmConfig {\n region?: string\n /** Default MicroVM image ARN, used for any stack without a specific image. */\n imageArn: string\n /** Per-stack image ARN overrides, e.g. { node: 'arn:...', python: 'arn:...' }. */\n stackImageArns?: Partial<Record<VmStack, string>>\n ingressConnectorArns?: string[]\n egressConnectorArns?: string[]\n executionRoleArn?: string\n /** Suspend automatically after this many seconds without endpoint traffic (0 disables the idle policy). */\n maxIdleSeconds?: number\n /** Terminate automatically after this many seconds in the suspended state. */\n suspendedDurationSeconds?: number\n /** Hard lifetime cap for a MicroVM (running + suspended), max 28800. */\n maximumDurationInSeconds?: number\n /** How long to wait for the RUNNING state after run-microvm. */\n createTimeoutMs?: number\n}\n\ninterface ManagedMicrovm {\n handle: VmHandle\n microvmId: string\n endpoint: string\n authToken?: { headers: Record<string, string>; expiresAt: number }\n}\n\nconst AUTH_TOKEN_TTL_MINUTES = 60\nconst AUTH_TOKEN_REFRESH_MARGIN_MS = 2 * 60_000\n\n/**\n * Runs VMs as AWS Lambda MicroVMs (Firecracker snapshots managed by Lambda).\n * No VNC framebuffer or serial console \u2014 HTTP(S) into the guest only, via the\n * MicroVM's dedicated endpoint with JWE auth. Suspend/resume preserve full\n * memory + disk state, so pause/resume here is a true checkpoint, unlike QEMU's.\n *\n * Intentionally has no onExit(): unlike Fargate (whose ECS task actually stops when the\n * container's process exits) or QEMU/Firecracker (a guest poweroff kills the local hypervisor\n * process we spawned), a MicroVM's AWS-managed lifecycle has no state that reflects \"the\n * guest's own entrypoint finished\" \u2014 it only transitions via explicit suspend/resume/terminate\n * calls or the idle/duration policies above. 'job' run mode isn't supported on this engine\n * until the guest image itself can signal completion back out (e.g. call TerminateMicrovm on\n * itself, or a callback through the existing HTTP proxy path) \u2014 MultiEngineExecutor.onExit()\n * already surfaces a clear \"does not support job run mode\" error for this engine as-is.\n */\nexport class LambdaMicrovmExecutor implements Executor {\n private readonly client: LambdaMicrovmsClient\n private readonly vms = new Map<string, ManagedMicrovm>()\n\n constructor(private readonly config: LambdaMicrovmConfig) {\n this.client = new LambdaMicrovmsClient(config.region ? { region: config.region } : {})\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const imageIdentifier = this.config.stackImageArns?.[spec.stack] ?? this.config.imageArn\n const maxIdle = this.config.maxIdleSeconds ?? 900\n\n const run = await this.client.send(\n new RunMicrovmCommand({\n imageIdentifier,\n ingressNetworkConnectors: this.config.ingressConnectorArns,\n egressNetworkConnectors: this.config.egressConnectorArns,\n executionRoleArn: this.config.executionRoleArn,\n maximumDurationInSeconds: this.config.maximumDurationInSeconds ?? 28_800,\n ...(maxIdle > 0\n ? {\n idlePolicy: {\n autoResumeEnabled: true,\n maxIdleDurationSeconds: maxIdle,\n suspendedDurationSeconds: this.config.suspendedDurationSeconds ?? 28_800,\n },\n }\n : {}),\n // The guest's /run lifecycle hook receives this payload \u2014 lets the image\n // identify which builder session/VM it serves.\n runHookPayload: JSON.stringify({\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n appUrl: spec.appUrl,\n env: spec.env,\n }),\n }),\n )\n\n if (!run.microvmId || !run.endpoint) {\n throw new Error('run-microvm returned no microvmId/endpoint')\n }\n\n logger.info(\n { vmId: spec.vmId, microvmId: run.microvmId, endpoint: run.endpoint, state: run.state },\n '[LambdaMicrovm] run-microvm accepted',\n )\n\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n // Resources are fixed at MicroVM image build time; echo the request back for bookkeeping.\n resources: spec.resources,\n running: true,\n metadata: { microvmId: run.microvmId, endpoint: run.endpoint },\n }\n\n const vm: ManagedMicrovm = { handle, microvmId: run.microvmId, endpoint: run.endpoint }\n this.vms.set(spec.vmId, vm)\n\n try {\n await this.waitForState(run.microvmId, 'RUNNING', this.config.createTimeoutMs ?? 25_000)\n } catch (error) {\n this.vms.delete(spec.vmId)\n await this.client\n .send(new TerminateMicrovmCommand({ microvmIdentifier: run.microvmId }))\n .catch(() => {})\n throw error\n }\n\n logger.info({ vmId: spec.vmId, microvmId: run.microvmId }, '[LambdaMicrovm] vm running')\n return handle\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await this.client.send(new SuspendMicrovmCommand({ microvmIdentifier: vm.microvmId }))\n return this.setRunning(vmId, false)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await this.client.send(new ResumeMicrovmCommand({ microvmIdentifier: vm.microvmId }))\n return this.setRunning(vmId, true)\n }\n\n // Suspend preserves memory + disk, so stop/restore are the same checkpoint\n // operations as pause/resume \u2014 there is no separate \"powered off\" state.\n stop(vmId: string): Promise<VmHandle> {\n return this.pause(vmId)\n }\n\n restore(vmId: string): Promise<VmHandle> {\n return this.resume(vmId)\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n\n await this.client.send(new TerminateMicrovmCommand({ microvmIdentifier: vm.microvmId }))\n this.vms.delete(vmId)\n logger.info({ vmId, microvmId: vm.microvmId }, '[LambdaMicrovm] vm terminated')\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((v) => v.handle)\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.mustGet(vmId)\n const auth = await this.getAuthHeaders(vm)\n\n return new Promise((resolve, reject) => {\n const req = https.request(\n {\n host: vm.endpoint,\n method: request.method,\n path: request.path,\n headers: {\n ...request.headers,\n ...auth,\n // Lambda routes to port 8080 by default; make the guest port explicit.\n 'X-aws-proxy-port': '8080',\n host: vm.endpoint,\n },\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n /**\n * Recover a Lambda MicroVM after a worker restart. It's an independent AWS-managed\n * resource that outlives this process \u2014 just re-describe it by ID and, unless it's been\n * terminated, rebuild the local handle (the auth token refetches lazily as usual).\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as { microvmId?: string; endpoint?: string } | undefined\n if (!meta?.microvmId || !meta.endpoint) return undefined\n\n const described = await this.client\n .send(new GetMicrovmCommand({ microvmIdentifier: meta.microvmId }))\n .catch(() => undefined)\n if (!described || described.state === 'TERMINATED' || described.state === 'TERMINATING') {\n return undefined\n }\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running: described.state === 'RUNNING',\n metadata: meta,\n }\n this.vms.set(record.vmId, { handle, microvmId: meta.microvmId, endpoint: meta.endpoint })\n logger.info(\n { vmId: record.vmId, microvmId: meta.microvmId, state: described.state },\n '[LambdaMicrovm] vm reattached',\n )\n return handle\n }\n\n private mustGet(vmId: string): ManagedMicrovm {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n return vm\n }\n\n private setRunning(vmId: string, running: boolean): VmHandle {\n const vm = this.mustGet(vmId)\n vm.handle = { ...vm.handle, running }\n return vm.handle\n }\n\n private async getAuthHeaders(vm: ManagedMicrovm): Promise<Record<string, string>> {\n if (vm.authToken && vm.authToken.expiresAt - Date.now() > AUTH_TOKEN_REFRESH_MARGIN_MS) {\n return vm.authToken.headers\n }\n\n const resp = await this.client.send(\n new CreateMicrovmAuthTokenCommand({\n microvmIdentifier: vm.microvmId,\n expirationInMinutes: AUTH_TOKEN_TTL_MINUTES,\n allowedPorts: [{ allPorts: {} }],\n }),\n )\n if (!resp.authToken) throw new Error('create-microvm-auth-token returned no token')\n\n vm.authToken = {\n headers: resp.authToken,\n expiresAt: Date.now() + AUTH_TOKEN_TTL_MINUTES * 60_000,\n }\n return vm.authToken.headers\n }\n\n private async waitForState(microvmId: string, target: string, timeoutMs: number): Promise<void> {\n const deadline = Date.now() + timeoutMs\n for (;;) {\n const resp = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: microvmId }))\n if (resp.state === target) return\n if (resp.state === 'TERMINATED' || resp.state === 'TERMINATING') {\n throw new Error(`microvm ${microvmId} entered ${resp.state} while waiting for ${target}`)\n }\n if (Date.now() > deadline) {\n throw new Error(\n `timed out waiting for microvm ${microvmId} to reach ${target} (still ${resp.state})`,\n )\n }\n await new Promise((r) => setTimeout(r, 1_000))\n }\n }\n}\n", "import http from 'http'\nimport {\n ECSClient,\n RunTaskCommand,\n StopTaskCommand,\n DescribeTasksCommand,\n DescribeTaskDefinitionCommand,\n} from '@aws-sdk/client-ecs'\nimport logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmRecord,\n VmRunMode,\n VmRunResult,\n VmStack,\n} from '@multiplayer-app/builder-types'\nimport type { Executor, VmHandle, VmSpec } from './types'\n\nconst JOB_POLL_INTERVAL_MS = 5_000\n\nexport interface FargateConfig {\n region?: string\n /** ECS cluster name or ARN. */\n cluster: string\n /** Default task definition (family[:revision] or ARN), used for stacks without an override. */\n taskDefinition?: string\n /** Per-stack task definition overrides, e.g. { node: 'builder-node:3' }. */\n stackTaskDefinitions?: Partial<Record<VmStack, string>>\n /** VPC subnets for awsvpc networking. */\n subnets: string[]\n securityGroups?: string[]\n /**\n * ENABLED: task gets a public IP and the worker proxies to it (worker outside the VPC).\n * DISABLED (default): the worker proxies to the task's private IP (worker inside the VPC).\n */\n assignPublicIp?: boolean\n /** Guest HTTP port the app/agent listens on. */\n guestPort?: number\n /** How long to wait for the task to reach RUNNING (image pulls can be slow). */\n startTimeoutMs?: number\n}\n\ninterface ManagedTask {\n handle: VmHandle\n taskArn: string\n ip: string\n runMode: VmRunMode\n startedAt: number\n}\n\n// Valid Fargate cpu (units) \u2192 [min, max] task memory (MiB).\nconst FARGATE_MEM_RANGES: Record<number, [number, number]> = {\n 256: [512, 2048],\n 512: [1024, 4096],\n 1024: [2048, 8192],\n 2048: [4096, 16384],\n 4096: [8192, 30720],\n}\n\n/** Snap requested VM resources to a valid Fargate cpu/memory combination. */\nexport function fargateResources(\n vcpuCount: number,\n memMib: number,\n): { cpu: string; memory: string } {\n const cpu = Math.min(4096, Math.max(256, vcpuCount * 1024))\n const [min, max] = FARGATE_MEM_RANGES[cpu]\n let memory = Math.min(max, Math.max(min, memMib))\n // Above 512 MiB, Fargate only accepts 1 GiB increments\n if (memory > 512) memory = Math.ceil(memory / 1024) * 1024\n return { cpu: String(cpu), memory: String(Math.min(max, memory)) }\n}\n\n/**\n * Runs VMs as AWS Fargate tasks (one task per VM). No VNC or serial console and no\n * pause/resume \u2014 HTTP(S) into the container only, via the task's IP on the guest port.\n * Slower to start than Lambda MicroVMs (image pull + task provisioning), but supports\n * arbitrary container images via standard ECS task definitions.\n */\nexport class FargateExecutor implements Executor {\n private readonly client: ECSClient\n private readonly vms = new Map<string, ManagedTask>()\n private readonly containerNames = new Map<string, string>()\n private readonly pendingResults = new Map<string, VmRunResult>()\n private readonly exitHandlers = new Map<string, (result: VmRunResult) => void>()\n\n constructor(private readonly config: FargateConfig) {\n this.client = new ECSClient(config.region ? { region: config.region } : {})\n }\n\n /** First container of the task definition \u2014 the target for env overrides. Cached per definition. */\n private async resolveContainerName(taskDefinition: string): Promise<string> {\n const cached = this.containerNames.get(taskDefinition)\n if (cached) return cached\n\n const described = await this.client.send(new DescribeTaskDefinitionCommand({ taskDefinition }))\n const name = described.taskDefinition?.containerDefinitions?.[0]?.name\n if (!name) throw new Error(`task definition ${taskDefinition} has no containers`)\n this.containerNames.set(taskDefinition, name)\n return name\n }\n\n private async waitForRunning(taskArn: string): Promise<string> {\n const timeoutMs = this.config.startTimeoutMs ?? 180_000\n const deadline = Date.now() + timeoutMs\n\n for (;;) {\n const described = await this.client.send(\n new DescribeTasksCommand({ cluster: this.config.cluster, tasks: [taskArn] }),\n )\n const task = described.tasks?.[0]\n if (!task) throw new Error(`task ${taskArn} not found`)\n\n if (task.lastStatus === 'STOPPED') {\n throw new Error(`fargate task stopped: ${task.stoppedReason ?? 'unknown reason'}`)\n }\n if (task.lastStatus === 'RUNNING') {\n const ip = this.config.assignPublicIp\n ? await this.resolvePublicIp(task.attachments)\n : task.containers?.[0]?.networkInterfaces?.[0]?.privateIpv4Address\n if (!ip)\n throw new Error(\n `fargate task ${taskArn} is RUNNING but has no ${this.config.assignPublicIp ? 'public' : 'private'} IP`,\n )\n return ip\n }\n if (Date.now() > deadline) {\n throw new Error(\n `fargate task did not reach RUNNING within ${timeoutMs}ms (last status: ${task.lastStatus})`,\n )\n }\n await new Promise((resolve) => setTimeout(resolve, 3000))\n }\n }\n\n private async resolvePublicIp(\n attachments: { type?: string; details?: { name?: string; value?: string }[] }[] | undefined,\n ): Promise<string | undefined> {\n const eniId = attachments\n ?.find((a) => a.type === 'ElasticNetworkInterface')\n ?.details?.find((d) => d.name === 'networkInterfaceId')?.value\n if (!eniId) return undefined\n\n const { EC2Client, DescribeNetworkInterfacesCommand } = await import('@aws-sdk/client-ec2')\n const ec2 = new EC2Client(this.config.region ? { region: this.config.region } : {})\n const described = await ec2.send(\n new DescribeNetworkInterfacesCommand({ NetworkInterfaceIds: [eniId] }),\n )\n return described.NetworkInterfaces?.[0]?.Association?.PublicIp\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const taskDefinition =\n this.config.stackTaskDefinitions?.[spec.stack] ?? this.config.taskDefinition\n if (!taskDefinition) {\n throw new Error(`no Fargate task definition configured for stack \"${spec.stack}\"`)\n }\n\n const containerName = await this.resolveContainerName(taskDefinition)\n const { cpu, memory } = fargateResources(spec.resources.vcpuCount, spec.resources.memMib)\n\n const run = await this.client.send(\n new RunTaskCommand({\n cluster: this.config.cluster,\n taskDefinition,\n launchType: 'FARGATE',\n count: 1,\n networkConfiguration: {\n awsvpcConfiguration: {\n subnets: this.config.subnets,\n securityGroups: this.config.securityGroups,\n assignPublicIp: this.config.assignPublicIp ? 'ENABLED' : 'DISABLED',\n },\n },\n overrides: {\n cpu,\n memory,\n containerOverrides: [\n {\n name: containerName,\n environment: [\n { name: 'VM_ID', value: spec.vmId },\n ...(spec.sessionId ? [{ name: 'SESSION_ID', value: spec.sessionId }] : []),\n { name: 'STACK', value: spec.stack },\n // Release artifact: the container agent pulls, unzips, and starts it\n ...(spec.appUrl ? [{ name: 'APP_URL', value: spec.appUrl }] : []),\n ...Object.entries(spec.env ?? {}).map(([name, value]) => ({ name, value })),\n ],\n },\n ],\n },\n tags: [\n { key: 'vmId', value: spec.vmId },\n ...(spec.sessionId ? [{ key: 'sessionId', value: spec.sessionId }] : []),\n ],\n }),\n )\n\n const taskArn = run.tasks?.[0]?.taskArn\n if (!taskArn) {\n throw new Error(`RunTask failed: ${run.failures?.[0]?.reason ?? 'no task returned'}`)\n }\n logger.info({ vmId: spec.vmId, taskArn, taskDefinition, cpu, memory }, 'fargate task started')\n\n const runMode = spec.runMode ?? 'service'\n try {\n const ip = await this.waitForRunning(taskArn)\n const handle: VmHandle = {\n vmId: spec.vmId,\n sessionId: spec.sessionId,\n stack: spec.stack,\n resources: spec.resources,\n running: true,\n metadata: { taskArn, ip },\n }\n this.vms.set(spec.vmId, { handle, taskArn, ip, runMode, startedAt: Date.now() })\n if (runMode === 'job') void this.watchJob(spec.vmId, taskArn)\n logger.info({ vmId: spec.vmId, ip, runMode }, 'fargate task running')\n return handle\n } catch (error) {\n await this.client\n .send(\n new StopTaskCommand({\n cluster: this.config.cluster,\n task: taskArn,\n reason: 'startup failed',\n }),\n )\n .catch(() => {})\n throw error\n }\n }\n\n async pause(vmId: string): Promise<VmHandle> {\n throw new Error(`fargate tasks cannot be paused (vm ${vmId})`)\n }\n\n async resume(vmId: string): Promise<VmHandle> {\n throw new Error(`fargate tasks cannot be resumed (vm ${vmId})`)\n }\n\n async restore(vmId: string): Promise<VmHandle> {\n throw new Error(`fargate tasks cannot be restored (vm ${vmId})`)\n }\n\n async stop(vmId: string): Promise<VmHandle> {\n const vm = this.mustGet(vmId)\n await this.client.send(\n new StopTaskCommand({\n cluster: this.config.cluster,\n task: vm.taskArn,\n reason: 'stopped via API',\n }),\n )\n vm.handle.running = false\n return vm.handle\n }\n\n async destroy(vmId: string): Promise<void> {\n const vm = this.vms.get(vmId)\n if (!vm) return\n await this.client\n .send(\n new StopTaskCommand({\n cluster: this.config.cluster,\n task: vm.taskArn,\n reason: 'destroyed via API',\n }),\n )\n .catch((error: Error) => logger.warn({ vmId, err: error }, 'fargate stop on destroy failed'))\n this.vms.delete(vmId)\n }\n\n get(vmId: string): VmHandle | undefined {\n return this.vms.get(vmId)?.handle\n }\n\n list(): VmHandle[] {\n return [...this.vms.values()].map((vm) => vm.handle)\n }\n\n async proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n const vm = this.mustGet(vmId)\n if (!vm.handle.running) throw new Error(`vm ${vmId} is not running`)\n\n return new Promise((resolve, reject) => {\n const req = http.request(\n {\n host: vm.ip,\n port: this.config.guestPort ?? 8080,\n method: request.method,\n path: request.path,\n headers: request.headers,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (c: Buffer) => chunks.push(c))\n res.on('end', () =>\n resolve({\n statusCode: res.statusCode ?? 502,\n headers: Object.fromEntries(\n Object.entries(res.headers).map(([k, v]) => [\n k,\n Array.isArray(v) ? v.join(', ') : v ?? '',\n ]),\n ),\n body: Buffer.concat(chunks),\n }),\n )\n },\n )\n req.on('error', reject)\n if (request.body) req.write(request.body)\n req.end()\n })\n }\n\n /**\n * Recover a Fargate task after a worker restart. The task is an independent AWS resource\n * that outlives this process \u2014 just re-describe it by ARN and, if it's still RUNNING,\n * rebuild the local handle.\n */\n async reattach(record: VmRecord): Promise<VmHandle | undefined> {\n const meta = record.runtimeMetadata as { taskArn?: string } | undefined\n if (!meta?.taskArn) return undefined\n\n const described = await this.client\n .send(new DescribeTasksCommand({ cluster: this.config.cluster, tasks: [meta.taskArn] }))\n .catch(() => undefined)\n const task = described?.tasks?.[0]\n if (!task || task.lastStatus !== 'RUNNING') return undefined\n\n const ip = this.config.assignPublicIp\n ? await this.resolvePublicIp(task.attachments)\n : task.containers?.[0]?.networkInterfaces?.[0]?.privateIpv4Address\n if (!ip) return undefined\n\n const handle: VmHandle = {\n vmId: record.vmId,\n sessionId: record.sessionId,\n stack: record.stack,\n resources: record.resources,\n running: true,\n metadata: { taskArn: meta.taskArn, ip },\n }\n this.vms.set(record.vmId, {\n handle,\n taskArn: meta.taskArn,\n ip,\n runMode: record.runMode,\n startedAt: Date.parse(record.createdAt) || Date.now(),\n })\n if (record.runMode === 'job') void this.watchJob(record.vmId, meta.taskArn)\n logger.info({ vmId: record.vmId, taskArn: meta.taskArn, ip }, 'fargate task reattached')\n return handle\n }\n\n /**\n * No push notification exists for \"task stopped\" without EventBridge wiring (v1 doesn't set\n * that up), so poll DescribeTasks. Exit code comes straight from the container's own\n * `exitCode` field \u2014 no CloudWatch Logs integration yet, so stdout/stderr capture isn't\n * implemented for this engine (the caller can still find full output in CloudWatch directly,\n * via the task's own log configuration).\n */\n private async watchJob(vmId: string, taskArn: string): Promise<void> {\n const startedAt = this.vms.get(vmId)?.startedAt ?? Date.now()\n for (;;) {\n await new Promise((resolve) => setTimeout(resolve, JOB_POLL_INTERVAL_MS))\n if (!this.vms.has(vmId)) return // destroyed out from under the poll\n\n const described = await this.client\n .send(new DescribeTasksCommand({ cluster: this.config.cluster, tasks: [taskArn] }))\n .catch(() => undefined)\n const task = described?.tasks?.[0]\n\n if (!task) {\n this.finishJob(vmId, {\n exitCode: -1,\n stdout: '',\n stderr: 'fargate task not found while polling for completion',\n truncated: false,\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n })\n return\n }\n if (task.lastStatus === 'STOPPED') {\n const exitCode = task.containers?.[0]?.exitCode\n this.finishJob(vmId, {\n exitCode: exitCode ?? 1,\n stdout: '',\n stderr: [\n task.stoppedReason ? `stoppedReason: ${task.stoppedReason}` : undefined,\n 'output capture not implemented for the fargate engine \u2014 see CloudWatch Logs for this task',\n ]\n .filter(Boolean)\n .join('; '),\n truncated: false,\n durationMs: Date.now() - startedAt,\n finishedAt: new Date().toISOString(),\n })\n return\n }\n }\n }\n\n private finishJob(vmId: string, result: VmRunResult): void {\n logger.info({ vmId, exitCode: result.exitCode }, 'fargate job task exited')\n // Keep the map entry (marked not-running) until onExit() claims the result \u2014 see\n // docker-executor's deliverJobResult comment for why route() needs get() to still work.\n const vm = this.vms.get(vmId)\n if (vm) vm.handle = { ...vm.handle, running: false }\n\n const handler = this.exitHandlers.get(vmId)\n if (handler) {\n this.exitHandlers.delete(vmId)\n this.vms.delete(vmId)\n handler(result)\n } else {\n this.pendingResults.set(vmId, result)\n }\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const pending = this.pendingResults.get(vmId)\n if (pending) {\n this.pendingResults.delete(vmId)\n this.vms.delete(vmId)\n handler(pending)\n return\n }\n this.exitHandlers.set(vmId, handler)\n }\n\n private mustGet(vmId: string): ManagedTask {\n const vm = this.vms.get(vmId)\n if (!vm) throw new Error(`vm ${vmId} not found`)\n return vm\n }\n}\n", "import fs from 'fs'\nimport { execFileSync } from 'child_process'\nimport logger from '@multiplayer-app/logger'\nimport { VM_STACKS, type VmEngine } from '@multiplayer-app/builder-types'\nimport { availableStacks } from '../images'\nimport type { WorkerConfig } from '../config'\n\n/** Auto-mode default preference when multiple engines are runnable on this host. */\nconst ENGINE_PRIORITY: VmEngine[] = [\n 'firecracker',\n 'qemu',\n 'docker-sandbox',\n 'docker',\n 'lambda-microvm',\n 'fargate',\n 'remote',\n 'mock',\n]\n\nexport interface EngineProbe {\n engine: VmEngine\n available: boolean\n /** Why the engine is unavailable (for startup logs). */\n reason?: string\n}\n\nfunction binaryOnPath(bin: string): boolean {\n if (bin.includes('/')) {\n try {\n fs.accessSync(bin, fs.constants.X_OK)\n return true\n } catch {\n return false\n }\n }\n try {\n execFileSync('which', [bin], { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nfunction kvmUsable(): boolean {\n try {\n fs.accessSync('/dev/kvm', fs.constants.R_OK | fs.constants.W_OK)\n return true\n } catch {\n return false\n }\n}\n\n/** Explicit kernel/initrd override present, or at least one stack dir with both image files. */\nfunction hasBaseImages(cfg: {\n imagesDir: string\n kernelPath?: string\n initrdPath?: string\n}): boolean {\n if (cfg.kernelPath && cfg.initrdPath)\n return fs.existsSync(cfg.kernelPath) && fs.existsSync(cfg.initrdPath)\n return availableStacks(cfg.imagesDir).length > 0\n}\n\nfunction probeQemu(config: WorkerConfig): EngineProbe {\n const { bin, accel } = config.qemu\n if (!hasBaseImages(config.qemu)) {\n return {\n engine: 'qemu',\n available: false,\n reason: `no base images under ${config.qemu.imagesDir} \u2014 run \"worker-cli images pull\" or scripts/setup-vm-images.sh`,\n }\n }\n if (!binaryOnPath(bin)) {\n return { engine: 'qemu', available: false, reason: `${bin} not found on PATH` }\n }\n if (accel === 'hvf' && process.platform !== 'darwin') {\n return {\n engine: 'qemu',\n available: false,\n reason: 'QEMU_ACCEL=hvf requires macOS (use kvm or tcg)',\n }\n }\n if (accel === 'kvm' && !kvmUsable()) {\n return {\n engine: 'qemu',\n available: false,\n reason: 'QEMU_ACCEL=kvm but /dev/kvm is not accessible',\n }\n }\n return { engine: 'qemu', available: true }\n}\n\nfunction probeFirecracker(config: WorkerConfig): EngineProbe {\n const { bin } = config.firecracker\n if (process.platform !== 'linux') {\n return { engine: 'firecracker', available: false, reason: 'requires a Linux host' }\n }\n if (!kvmUsable()) {\n return { engine: 'firecracker', available: false, reason: '/dev/kvm is not accessible' }\n }\n if (!hasBaseImages(config.firecracker)) {\n return {\n engine: 'firecracker',\n available: false,\n reason: `no base images under ${config.firecracker.imagesDir} \u2014 run \"worker-cli images pull\" or scripts/setup-vm-images.sh`,\n }\n }\n if (!binaryOnPath(bin)) {\n return { engine: 'firecracker', available: false, reason: `${bin} not found on PATH` }\n }\n return { engine: 'firecracker', available: true }\n}\n\n/** Whether at least one <imagePrefix>-<stack>:<imageTag> image exists in the local `docker` daemon. */\nfunction hasLocalDockerImage(\n bin: string,\n imagePrefix: string,\n imageTag: string,\n stackImages: Record<string, string> = {},\n): boolean {\n return VM_STACKS.some((stack) => {\n try {\n const image = stackImages[stack] ?? `${imagePrefix}-${stack}:${imageTag}`\n execFileSync(bin, ['image', 'inspect', image], { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n })\n}\n\nfunction probeDocker(config: WorkerConfig): EngineProbe {\n const { bin, imagePrefix, imageTag, stackImages } = config.docker\n if (!binaryOnPath(bin)) {\n return { engine: 'docker', available: false, reason: `${bin} not found on PATH` }\n }\n try {\n execFileSync(bin, ['info'], { stdio: 'ignore' })\n } catch {\n return { engine: 'docker', available: false, reason: 'docker daemon not reachable' }\n }\n if (!hasLocalDockerImage(bin, imagePrefix, imageTag, stackImages)) {\n return {\n engine: 'docker',\n available: false,\n reason: 'no local docker images \u2014 run scripts/setup-docker-images.sh',\n }\n }\n return { engine: 'docker', available: true }\n}\n\n/**\n * `docker-sandbox` (Docker's own Sandboxes product, the `sbx` CLI) bridges the same local\n * `docker` images in on demand (see DockerSandboxExecutor.ensureTemplateLoaded), so it needs\n * both `sbx` itself and those local images to exist. A not-yet-initialized global network\n * policy (`sbx policy init balanced|allow-all|deny-all`, required once before any sandbox can\n * be created) isn't checked here \u2014 same as Fargate detect not validating IAM permissions\n * upfront \u2014 it'll surface as a clear error the first time `create()` is called instead.\n */\nfunction probeDockerSandbox(config: WorkerConfig): EngineProbe {\n const { bin, imagePrefix, imageTag } = config.dockerSandbox\n if (!binaryOnPath(bin)) {\n return { engine: 'docker-sandbox', available: false, reason: `${bin} not found on PATH` }\n }\n try {\n execFileSync(bin, ['ls'], { stdio: 'ignore' })\n } catch {\n return {\n engine: 'docker-sandbox',\n available: false,\n reason: 'sbx daemon not reachable \u2014 run \"sbx daemon start\" and \"sbx login\"',\n }\n }\n if (!hasLocalDockerImage(config.docker.bin, imagePrefix, imageTag)) {\n return {\n engine: 'docker-sandbox',\n available: false,\n reason: 'no local docker images \u2014 run scripts/setup-docker-images.sh',\n }\n }\n return { engine: 'docker-sandbox', available: true }\n}\n\nfunction probeRemote(config: WorkerConfig): EngineProbe {\n return config.remote.agentUrl\n ? { engine: 'remote', available: true }\n : { engine: 'remote', available: false, reason: 'AGENT_URL not set' }\n}\n\nfunction probeLambdaMicrovm(config: WorkerConfig): EngineProbe {\n const { imageArn, stackImageArns } = config.lambdaMicrovm\n return imageArn || Object.keys(stackImageArns).length\n ? { engine: 'lambda-microvm', available: true }\n : {\n engine: 'lambda-microvm',\n available: false,\n reason: 'MICROVM_IMAGE_ARN / MICROVM_STACK_IMAGE_ARNS not set',\n }\n}\n\nfunction probeFargate(config: WorkerConfig): EngineProbe {\n const { cluster, taskDefinition, stackTaskDefinitions, subnets } = config.fargate\n if (!cluster) {\n return { engine: 'fargate', available: false, reason: 'FARGATE_CLUSTER not set' }\n }\n if (!taskDefinition && !Object.keys(stackTaskDefinitions).length) {\n return {\n engine: 'fargate',\n available: false,\n reason: 'FARGATE_TASK_DEFINITION / FARGATE_STACK_TASK_DEFS not set',\n }\n }\n if (!subnets.length) {\n return { engine: 'fargate', available: false, reason: 'FARGATE_SUBNETS not set' }\n }\n return { engine: 'fargate', available: true }\n}\n\n/** Probe every engine against this host + config. Mock is always runnable. */\nexport function probeEngines(config: WorkerConfig): EngineProbe[] {\n return [\n { engine: 'mock', available: true },\n probeQemu(config),\n probeFirecracker(config),\n probeDocker(config),\n probeDockerSandbox(config),\n probeRemote(config),\n probeLambdaMicrovm(config),\n probeFargate(config),\n ]\n}\n\nexport function detectEngines(config: WorkerConfig): {\n engines: VmEngine[]\n defaultEngine: VmEngine\n} {\n const probes = probeEngines(config)\n\n for (const probe of probes) {\n if (probe.available) {\n logger.info({ engine: probe.engine }, 'micro-VM engine available')\n } else {\n logger.debug({ engine: probe.engine, reason: probe.reason }, 'micro-VM engine unavailable')\n }\n }\n\n const engines = probes.filter((p) => p.available).map((p) => p.engine)\n const defaultEngine = ENGINE_PRIORITY.find((engine) => engines.includes(engine)) ?? 'mock'\n return { engines, defaultEngine }\n}\n", "import logger from '@multiplayer-app/logger'\nimport type {\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmEngine,\n VmExecRequest,\n VmExecResult,\n VmFileWrite,\n VmRecord,\n VmRunResult,\n VmWriteFilesResult,\n} from '@multiplayer-app/builder-types'\nimport { MockExecutor } from './mock-executor'\nimport { QemuExecutor } from './qemu-executor'\nimport { FirecrackerExecutor } from './firecracker-executor'\nimport { DockerExecutor } from './docker-executor'\nimport { DockerSandboxExecutor } from './docker-sandbox-executor'\nimport { RemoteExecutor } from './remote-executor'\nimport { LambdaMicrovmExecutor } from './lambda-microvm-executor'\nimport { FargateExecutor } from './fargate-executor'\nimport { detectEngines } from './detect'\nimport type { Executor, SerialSource, VmHandle, VmSpec } from './types'\nimport type { WorkerConfig } from '../config'\n\nexport type { Executor, SerialSource, VmHandle, VmSpec } from './types'\n\n/**\n * Of the VM records sandbox says this workerId owns, the ones this executor isn't already\n * tracking in memory \u2014 i.e. the ones actually worth attempting to reattach. A plain reconnect\n * (network blip, not a real process restart) never loses in-memory state, so this naturally\n * comes back empty in that case.\n */\nexport function findNotAttachedVms(\n executor: Pick<Executor, 'get'>,\n records: VmRecord[],\n): VmRecord[] {\n return records.filter((record) => !executor.get(record.vmId))\n}\n\n/** Only called for engines `detectEngines` reported runnable, so prerequisites are already verified. */\nfunction createEngineExecutor(engine: VmEngine, config: WorkerConfig): Executor {\n switch (engine) {\n case 'mock':\n return new MockExecutor()\n case 'qemu':\n return new QemuExecutor(config.qemu)\n case 'firecracker':\n return new FirecrackerExecutor(config.firecracker)\n case 'docker':\n return new DockerExecutor(config.docker)\n case 'docker-sandbox':\n return new DockerSandboxExecutor(config.dockerSandbox)\n case 'remote':\n return new RemoteExecutor(config.remote)\n case 'lambda-microvm':\n return new LambdaMicrovmExecutor(config.lambdaMicrovm)\n case 'fargate':\n return new FargateExecutor(config.fargate)\n default:\n throw new Error(`unknown engine \"${engine as string}\"`)\n }\n}\n\n/**\n * Routes VM operations to per-engine executors. `create` picks the executor from\n * `spec.engine` (falling back to the worker default); every other operation is\n * routed to whichever executor owns the vmId.\n */\nexport class MultiEngineExecutor implements Executor {\n constructor(\n private readonly executors: Map<VmEngine, Executor>,\n readonly defaultEngine: VmEngine,\n ) {}\n\n get engines(): VmEngine[] {\n return [...this.executors.keys()]\n }\n\n async create(spec: VmSpec): Promise<VmHandle> {\n const engine = spec.engine ?? this.defaultEngine\n const executor = this.executors.get(engine)\n if (!executor) {\n throw new Error(\n `engine \"${engine}\" is not available on this worker (available: ${this.engines.join(', ')})`,\n )\n }\n const handle = await executor.create(spec)\n return { ...handle, engine }\n }\n\n pause(vmId: string): Promise<VmHandle> {\n return this.route(vmId).pause(vmId)\n }\n resume(vmId: string): Promise<VmHandle> {\n return this.route(vmId).resume(vmId)\n }\n stop(vmId: string): Promise<VmHandle> {\n return this.route(vmId).stop(vmId)\n }\n restore(vmId: string): Promise<VmHandle> {\n return this.route(vmId).restore(vmId)\n }\n destroy(vmId: string): Promise<void> {\n return this.route(vmId).destroy(vmId)\n }\n\n proxyHttp(vmId: string, request: ProxyRequestDescriptor): Promise<ProxyResponseDescriptor> {\n return this.route(vmId).proxyHttp(vmId, request)\n }\n\n get(vmId: string): VmHandle | undefined {\n for (const executor of this.executors.values()) {\n const handle = executor.get(vmId)\n if (handle) return handle\n }\n return undefined\n }\n\n list(): VmHandle[] {\n return [...this.executors.values()].flatMap((executor) => executor.list())\n }\n\n getSerialSource(vmId: string): SerialSource | undefined {\n for (const executor of this.executors.values()) {\n if (executor.get(vmId)) return executor.getSerialSource?.(vmId)\n }\n return undefined\n }\n\n exec(vmId: string, request: VmExecRequest): Promise<VmExecResult> {\n const executor = this.route(vmId)\n if (!executor.exec) return Promise.reject(new Error('executor does not support guest exec'))\n return executor.exec(vmId, request)\n }\n\n writeFiles(vmId: string, files: VmFileWrite[]): Promise<VmWriteFilesResult> {\n const executor = this.route(vmId)\n if (!executor.writeFiles)\n return Promise.reject(new Error('executor does not support guest file writes'))\n return executor.writeFiles(vmId, files)\n }\n\n onExit(vmId: string, handler: (result: VmRunResult) => void): void {\n const executor = this.route(vmId)\n if (!executor.onExit) throw new Error('executor does not support job run mode')\n executor.onExit(vmId, handler)\n }\n\n /**\n * Recover VMs sandbox says this workerId owns but that aren't currently tracked (a worker\n * restart, most likely). Runs in parallel \u2014 probing many VMs serially would needlessly\n * delay the first heartbeat, which reports capacity from `list()` and must reflect\n * reattached VMs to avoid sandbox overbooking this worker. Best-effort: failures are logged,\n * never thrown \u2014 a VM that can't be reattached just stays unavailable until something\n * touches it again (create/proxy/lifecycle), which already errors gracefully today.\n */\n async reattachAll(records: VmRecord[]): Promise<void> {\n const pending = findNotAttachedVms(this, records)\n if (!pending.length) return\n\n const results = await Promise.allSettled(\n pending.map(async (record) => {\n const executor = record.engine ? this.executors.get(record.engine) : undefined\n if (!executor)\n throw new Error(`engine \"${record.engine ?? 'unknown'}\" not available on this worker`)\n if (!executor.reattach)\n throw new Error(`engine \"${record.engine}\" does not support reattach`)\n const handle = await executor.reattach(record)\n if (!handle) throw new Error('resource no longer exists')\n }),\n )\n\n results.forEach((result, i) => {\n const vmId = pending[i].vmId\n if (result.status === 'fulfilled') logger.info({ vmId }, 'vm reattached')\n else\n logger.warn(\n { vmId, err: result.reason },\n 'vm reattach failed \u2014 staying unavailable until next touch',\n )\n })\n }\n\n private route(vmId: string): Executor {\n for (const executor of this.executors.values()) {\n if (executor.get(vmId)) return executor\n }\n throw new Error(`vm ${vmId} not found on this worker`)\n }\n}\n\n/**\n * Probes the host (KVM, HVF, binaries, images, ARNs) and registers every runnable engine,\n * defaulting to the most capable one. Per-VM engine selection comes from the create request.\n */\nexport function createExecutor(config: WorkerConfig): MultiEngineExecutor {\n const { engines, defaultEngine } = detectEngines(config)\n\n const executors = new Map<VmEngine, Executor>()\n for (const engine of engines) {\n executors.set(engine, createEngineExecutor(engine, config))\n }\n\n logger.info({ engines, defaultEngine }, 'micro-VM engines initialized')\n return new MultiEngineExecutor(executors, defaultEngine)\n}\n", "import os from 'os'\nimport { io, type Socket } from 'socket.io-client'\nimport logger from '@multiplayer-app/logger'\nimport type {\n CommandAck,\n ProxyRequestDescriptor,\n ProxyResponseDescriptor,\n VmExecRequest,\n VmFileWrite,\n VmRecord,\n WorkerHeartbeat,\n} from '@multiplayer-app/builder-types'\nimport { WorkerEvent } from '@multiplayer-app/builder-types'\nimport type { WorkerConfig } from './config'\nimport { WORKER_VERSION } from './config'\nimport type { MultiEngineExecutor, VmSpec } from './executor'\n\nconst HEARTBEAT_INTERVAL_MS = 10_000\n// If sandbox never sends the reattach handshake (older version, edge case), start\n// heartbeating anyway rather than hanging the connection forever.\nconst REATTACH_FALLBACK_MS = 5_000\n\nfunction primaryIp(): string | undefined {\n for (const ifaces of Object.values(os.networkInterfaces())) {\n for (const iface of ifaces ?? []) {\n if (!iface.internal && iface.family === 'IPv4') return iface.address\n }\n }\n return undefined\n}\n\nfunction buildHeartbeat(config: WorkerConfig, executor: MultiEngineExecutor): WorkerHeartbeat {\n return {\n hostname: os.hostname(),\n ip: primaryIp(),\n region: config.region,\n version: WORKER_VERSION,\n engines: executor.engines,\n defaultEngine: executor.defaultEngine,\n capacity: {\n maxVms: config.maxVms,\n usedVms: executor.list().length,\n cpuCores: os.cpus().length,\n memMib: Math.round(os.totalmem() / (1024 * 1024)),\n },\n }\n}\n\nfunction wrap<TPayload, TResult>(\n handler: (payload: TPayload) => Promise<TResult>,\n): (payload: TPayload, callback: (ack: CommandAck<TResult>) => void) => void {\n return (payload, callback) => {\n handler(payload)\n .then((result) => callback({ ok: true, result }))\n .catch((error: Error) => {\n logger.error({ err: error }, 'command failed')\n callback({ ok: false, error: error.message })\n })\n }\n}\n\nfunction registerCommandHandlers(socket: Socket, executor: MultiEngineExecutor): void {\n socket.on(\n WorkerEvent.VM_CREATE,\n wrap(async (spec: VmSpec) => {\n const handle = await executor.create(spec)\n if (spec.runMode === 'job') {\n try {\n executor.onExit(spec.vmId, (result) =>\n socket.emit(WorkerEvent.VM_RUN_EXITED, { vmId: spec.vmId, ...result }),\n )\n } catch (error) {\n // The engine doesn't support job mode \u2014 don't leave an orphaned resource behind.\n await executor.destroy(spec.vmId).catch(() => { })\n throw error\n }\n }\n return handle\n }),\n )\n socket.on(\n WorkerEvent.VM_PAUSE,\n wrap(({ vmId }: { vmId: string }) => executor.pause(vmId)),\n )\n socket.on(\n WorkerEvent.VM_RESUME,\n wrap(({ vmId }: { vmId: string }) => executor.resume(vmId)),\n )\n socket.on(\n WorkerEvent.VM_STOP,\n wrap(({ vmId }: { vmId: string }) => executor.stop(vmId)),\n )\n socket.on(\n WorkerEvent.VM_RESTORE,\n wrap(({ vmId }: { vmId: string }) => executor.restore(vmId)),\n )\n socket.on(\n WorkerEvent.VM_DESTROY,\n wrap(({ vmId }: { vmId: string }) => executor.destroy(vmId)),\n )\n\n socket.on(\n WorkerEvent.PROXY_HTTP,\n wrap(\n ({\n vmId,\n ...request\n }: ProxyRequestDescriptor & { vmId: string }): Promise<ProxyResponseDescriptor> =>\n executor.proxyHttp(vmId, request),\n ),\n )\n\n socket.on(\n WorkerEvent.VM_EXEC,\n wrap(({ vmId, ...request }: VmExecRequest & { vmId: string }) => {\n if (!executor.exec) {\n return Promise.reject(new Error('executor does not support guest exec'))\n }\n return executor.exec(vmId, request)\n }),\n )\n\n socket.on(\n WorkerEvent.VM_WRITE_FILES,\n wrap(({ vmId, files }: { vmId: string; files: VmFileWrite[] }) => {\n if (!executor.writeFiles) {\n return Promise.reject(new Error('executor does not support guest file writes'))\n }\n return executor.writeFiles(vmId, files)\n }),\n )\n}\n\nexport function connectToSandbox(config: WorkerConfig, executor: MultiEngineExecutor): Socket {\n let assignedWorkerId: string | undefined\n const socket = io(config.sandboxUrl, {\n path: config.workerSocketPath,\n auth: (callback) =>\n callback({\n workerId: config.workerId,\n ...(assignedWorkerId ? { assignedWorkerId } : {}),\n ...(config.token ? { token: config.token } : {}),\n }),\n transports: ['websocket'],\n reconnection: true,\n })\n\n let heartbeatTimer: NodeJS.Timeout | undefined\n let reattachFallbackTimer: NodeJS.Timeout | undefined\n\n socket.on(WorkerEvent.ASSIGNED_ID, ({ workerId }: { workerId: string }) => {\n assignedWorkerId = workerId\n logger.info({ workerId: config.workerId, assignedWorkerId }, 'worker runtime ID assigned')\n })\n\n const sendHeartbeat = () => socket.emit(WorkerEvent.HEARTBEAT, buildHeartbeat(config, executor))\n\n function startHeartbeat(): void {\n if (heartbeatTimer) return // already running for this connection\n sendHeartbeat()\n heartbeatTimer = setInterval(sendHeartbeat, HEARTBEAT_INTERVAL_MS)\n }\n\n socket.on('connect', () => {\n logger.info(\n { workerId: config.workerId, assignedWorkerId, url: config.sandboxUrl },\n 'connected to sandbox',\n )\n\n // Sandbox emits REATTACH once, right after auth, listing any VMs it thinks this worker\n // still owns. Reattach them before the first heartbeat so capacity.usedVms is accurate \u2014\n // otherwise sandbox could schedule new VMs onto capacity that's actually already in use.\n socket.off(WorkerEvent.REATTACH)\n reattachFallbackTimer = setTimeout(() => {\n logger.warn(\n { workerId: config.workerId },\n 'no reattach handshake from sandbox \u2014 starting heartbeat anyway',\n )\n startHeartbeat()\n }, REATTACH_FALLBACK_MS)\n\n socket.once(WorkerEvent.REATTACH, (records: VmRecord[]) => {\n clearTimeout(reattachFallbackTimer)\n executor\n .reattachAll(records)\n .catch((error: Error) => logger.error({ err: error }, 'reattach batch failed'))\n .finally(() => {\n // Reattached job VMs may already have a result waiting (finished while this worker\n // was offline) or may still be running \u2014 either way, re-register so its eventual\n // VM_RUN_EXITED gets (re-)sent now that we're connected again.\n for (const record of records) {\n if (record.runMode !== 'job' || !executor.get(record.vmId)) continue\n try {\n executor.onExit(record.vmId, (result) =>\n socket.emit(WorkerEvent.VM_RUN_EXITED, { vmId: record.vmId, ...result }),\n )\n } catch (error) {\n logger.warn(\n { vmId: record.vmId, err: error },\n 'reattached job vm has no onExit support',\n )\n }\n }\n startHeartbeat()\n })\n })\n })\n\n socket.on('disconnect', (reason) => {\n logger.warn({ workerId: config.workerId, reason }, 'disconnected from sandbox')\n clearInterval(heartbeatTimer)\n clearTimeout(reattachFallbackTimer)\n heartbeatTimer = undefined\n socket.off(WorkerEvent.REATTACH)\n })\n\n socket.on('connect_error', (error) => {\n logger.error({\n err: error,\n sandboxUrl: config.sandboxUrl\n }, 'sandbox connection error')\n })\n\n registerCommandHandlers(socket, executor)\n\n return socket\n}\n", "import rfb from 'rfb2'\nimport type { Socket } from 'socket.io-client'\nimport logger from '@multiplayer-app/logger'\nimport {\n WorkerEvent,\n type VncFramePayload,\n type VncCopyFramePayload,\n type VncMousePayload,\n type VncKeyboardPayload,\n} from '@multiplayer-app/builder-types'\n\nfunction bgraToRgba(src: Buffer): Buffer {\n const dst = Buffer.allocUnsafe(src.length)\n for (let i = 0; i < src.length; i += 4) {\n dst[i] = src[i + 2]\n dst[i + 1] = src[i + 1]\n dst[i + 2] = src[i]\n dst[i + 3] = 0xff\n }\n return dst\n}\n\n/** Connects to a QEMU VNC server and relays frames upstream to the sandbox socket. */\nexport class VncRelay {\n private rfbc: ReturnType<typeof rfb.createConnection> & any = null\n private interval: ReturnType<typeof setInterval> | null = null\n private mouseHandler: ((e: VncMousePayload) => void) | null = null\n private keyHandler: ((e: VncKeyboardPayload) => void) | null = null\n\n constructor(\n private readonly vmId: string,\n private readonly host: string,\n private readonly port: number,\n private readonly socket: Socket,\n ) {}\n\n start(): void {\n this.rfbc = rfb.createConnection({ host: this.host, port: this.port, password: '' })\n const rfbc = this.rfbc\n\n rfbc.on('connect', () => {\n rfbc.autoUpdate = true\n this.socket.emit(WorkerEvent.VNC_INIT, {\n vmId: this.vmId,\n width: rfbc.width,\n height: rfbc.height,\n })\n this.interval = setInterval(() => {\n rfbc.requestUpdate(false, 0, 0, rfbc.width, rfbc.height)\n }, 300)\n })\n\n rfbc.on('rect', (rect: any) => {\n switch (rect.encoding) {\n case rfb.encodings.raw: {\n const frame: VncFramePayload = {\n vmId: this.vmId,\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n encoding: 'raw',\n data: bgraToRgba(rect.data),\n }\n this.socket.emit(WorkerEvent.VNC_FRAME, frame)\n break\n }\n case rfb.encodings.copyRect: {\n const frame: VncCopyFramePayload = {\n vmId: this.vmId,\n x: rect.x,\n y: rect.y,\n src: rect.src,\n width: rect.width,\n height: rect.height,\n }\n this.socket.emit(WorkerEvent.VNC_COPY_FRAME, frame)\n break\n }\n }\n })\n\n // Guest display init/resize (e.g. QEMU placeholder 640x480 \u2192 guest fb 1280x800).\n // rfb2 updates rfbc.width/height itself; re-announce dimensions and pull a\n // full frame so browsers aren't stuck on the pre-boot placeholder.\n rfbc.on('resize', (rect: { width: number; height: number }) => {\n logger.info(\n { vmId: this.vmId, width: rect.width, height: rect.height },\n '[VNC] desktop resized',\n )\n this.socket.emit(WorkerEvent.VNC_INIT, {\n vmId: this.vmId,\n width: rect.width,\n height: rect.height,\n })\n rfbc.requestUpdate(false, 0, 0, rect.width, rect.height)\n })\n\n rfbc.on('error', (err: Error) => logger.error({ vmId: this.vmId, err }, '[VNC] RFB error'))\n\n this.mouseHandler = (e: VncMousePayload) => {\n if (e.vmId === this.vmId) rfbc.pointerEvent(e.x, e.y, e.button)\n }\n this.keyHandler = (e: VncKeyboardPayload) => {\n if (e.vmId === this.vmId) rfbc.keyEvent(e.keyCode, e.isDown)\n }\n this.socket.on(WorkerEvent.VNC_MOUSE, this.mouseHandler)\n this.socket.on(WorkerEvent.VNC_KEYBOARD, this.keyHandler)\n logger.info({ vmId: this.vmId, port: this.port }, '[VNC] relay started')\n }\n\n destroy(): void {\n if (this.interval) clearInterval(this.interval)\n if (this.mouseHandler) this.socket.off(WorkerEvent.VNC_MOUSE, this.mouseHandler)\n if (this.keyHandler) this.socket.off(WorkerEvent.VNC_KEYBOARD, this.keyHandler)\n try {\n this.rfbc?.end()\n } catch {}\n this.rfbc = null\n logger.info({ vmId: this.vmId }, '[VNC] relay destroyed')\n }\n}\n", "import net from 'net'\nimport type { ChildProcess } from 'child_process'\nimport type { Socket } from 'socket.io-client'\nimport logger from '@multiplayer-app/logger'\nimport { WorkerEvent, type TerminalInputPayload } from '@multiplayer-app/builder-types'\nimport type { SerialSource } from '../executor/types'\n\n/** Relays VM serial console data upstream to the sandbox socket. */\nexport class SerialRelay {\n private conn: net.Socket | null = null\n private inputHandler: ((e: TerminalInputPayload) => void) | null = null\n\n constructor(\n private readonly vmId: string,\n private readonly source: SerialSource,\n private readonly socket: Socket,\n ) {}\n\n connect(): void {\n if (this.source.type === 'tcp') {\n this.connectTcp()\n } else {\n this.connectPipe()\n }\n\n this.inputHandler = (e: TerminalInputPayload) => {\n if (e.vmId !== this.vmId) return\n if (this.source.type === 'tcp' && this.conn) {\n this.conn.write(e.data)\n } else if (this.source.type === 'pipe') {\n const proc = (this.source as { type: 'pipe'; process: ChildProcess }).process\n proc.stdin?.write(e.data)\n }\n }\n this.socket.on(WorkerEvent.TERMINAL_INPUT, this.inputHandler)\n }\n\n private connectTcp(): void {\n const { host, port } = this.source as { type: 'tcp'; host: string; port: number }\n const attempt = () => {\n const sock = net.createConnection(port, host)\n sock.once('connect', () => {\n this.conn = sock\n logger.info({ vmId: this.vmId, port }, '[Serial] TCP connected')\n sock.on('data', (d: Buffer) =>\n this.socket.emit(WorkerEvent.TERMINAL_DATA, { vmId: this.vmId, data: d }),\n )\n sock.on('end', () => logger.info({ vmId: this.vmId }, '[Serial] TCP ended'))\n sock.on('error', (err) => logger.error({ vmId: this.vmId, err }, '[Serial] TCP error'))\n })\n sock.once('error', () => setTimeout(attempt, 1_000))\n }\n attempt()\n }\n\n private connectPipe(): void {\n const { process: proc } = this.source as { type: 'pipe'; process: ChildProcess }\n proc.stdout?.on('data', (d: Buffer) =>\n this.socket.emit(WorkerEvent.TERMINAL_DATA, { vmId: this.vmId, data: d }),\n )\n proc.stderr?.on('data', (d: Buffer) =>\n this.socket.emit(WorkerEvent.TERMINAL_DATA, { vmId: this.vmId, data: d }),\n )\n }\n\n destroy(): void {\n if (this.inputHandler) this.socket.off(WorkerEvent.TERMINAL_INPUT, this.inputHandler)\n try {\n this.conn?.destroy()\n } catch {}\n this.conn = null\n logger.info({ vmId: this.vmId }, '[Serial] relay destroyed')\n }\n}\n", "import type { Socket } from 'socket.io-client'\nimport type { MultiEngineExecutor } from './executor'\nimport { VncRelay } from './services/vnc-relay'\nimport { SerialRelay } from './services/serial-relay'\n\n/**\n * Wires up VNC and serial relays for any executor that exposes console endpoints (QEMU: VNC +\n * serial TCP ports; Firecracker: serial via process stdio pipe). All media (frames, terminal\n * data) flows through the sandbox socket to browsers \u2014 the worker never accepts inbound\n * connections from the internet. Wraps `executor.create`/`destroy` in place.\n */\nexport function attachConsoleRelays(executor: MultiEngineExecutor, sandboxSocket: Socket): void {\n const relays = new Map<string, { vnc?: VncRelay; serial?: SerialRelay }>()\n\n const originalCreate = executor.create.bind(executor)\n executor.create = async (spec) => {\n const handle = await originalCreate(spec)\n const entry: { vnc?: VncRelay; serial?: SerialRelay } = {}\n\n if (handle.vncPort) {\n const vnc = new VncRelay(handle.vmId, '127.0.0.1', handle.vncPort, sandboxSocket)\n vnc.start()\n entry.vnc = vnc\n }\n\n const serialSource = handle.serialPort\n ? { type: 'tcp' as const, host: '127.0.0.1', port: handle.serialPort }\n : executor.getSerialSource?.(handle.vmId)\n if (serialSource) {\n const serial = new SerialRelay(handle.vmId, serialSource, sandboxSocket)\n serial.connect()\n entry.serial = serial\n }\n\n if (entry.vnc || entry.serial) relays.set(handle.vmId, entry)\n return handle\n }\n\n const originalDestroy = executor.destroy.bind(executor)\n executor.destroy = async (vmId) => {\n const entry = relays.get(vmId)\n entry?.vnc?.destroy()\n entry?.serial?.destroy()\n relays.delete(vmId)\n return originalDestroy(vmId)\n }\n}\n", "import { execFile } from 'child_process'\nimport { promisify } from 'util'\nimport type { WorkerConfig } from './config'\nimport { availableStacks, hostArch, PUBLISHED_IMAGE_STACKS, pullImages } from './images'\nimport { version as WORKER_VERSION } from '../package.json'\n\nconst execFileAsync = promisify(execFile)\n\nexport function artifactImageLocation(env: NodeJS.ProcessEnv = process.env): string | undefined {\n const bucket = env.S3_BUCKET_ARTIFACTS?.trim()\n if (!bucket) return undefined\n if (bucket.includes('/') || bucket.includes('://')) {\n throw new Error('S3_BUCKET_ARTIFACTS must contain only the bucket name (no scheme or path)')\n }\n const version = env.NODE_ENV === 'development' || env.BUILDER_ENV === 'local'\n ? 'local'\n : WORKER_VERSION\n return `s3://${bucket}/${version}/qemu`\n}\n\nfunction allStacksAvailable(imagesDir: string): boolean {\n const available = new Set(availableStacks(imagesDir))\n return PUBLISHED_IMAGE_STACKS.every((stack) => available.has(stack))\n}\n\nasync function dockerAvailable(bin: string): Promise<boolean> {\n try {\n await execFileAsync(bin, ['info'])\n return true\n } catch {\n return false\n }\n}\n\nasync function dockerImageExists(bin: string, image: string): Promise<boolean> {\n try {\n await execFileAsync(bin, ['image', 'inspect', image])\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Materialize remotely published images before engine detection.\n *\n * S3_BUCKET_ARTIFACTS is the artifact bucket name. The worker derives the\n * environment/version and runner prefix; pullImages appends\n * <arch>/<stack>/<file>.\n * Registry-backed Docker images are pulled whenever the configured prefix is\n * a qualified repository (contains a slash), while local development prefixes\n * continue to require locally built images.\n */\nexport async function prepareWorkerImages(\n config: WorkerConfig,\n env: NodeJS.ProcessEnv = process.env,\n): Promise<void> {\n const vmImagesUrl = artifactImageLocation(env)\n const refreshVmImages = env.VM_IMAGES_REFRESH === 'true'\n if (vmImagesUrl) {\n const destinations = new Set([config.qemu.imagesDir, config.firecracker.imagesDir])\n for (const imagesDir of destinations) {\n if (!refreshVmImages && allStacksAvailable(imagesDir)) continue\n await pullImages({\n location: vmImagesUrl,\n arch: hostArch(),\n endpoint: env.S3_ARTIFACTS_ENDPOINT,\n }, imagesDir)\n }\n }\n\n const shouldPullDocker = env.DOCKER_PULL_IMAGES === 'true'\n || (env.DOCKER_PULL_IMAGES !== 'false' && config.docker.imagePrefix.includes('/'))\n if (!shouldPullDocker || !await dockerAvailable(config.docker.bin)) return\n\n for (const stack of PUBLISHED_IMAGE_STACKS) {\n const image = config.docker.stackImages[stack]\n ?? `${config.docker.imagePrefix}-${stack}:${config.docker.imageTag}`\n if (!await dockerImageExists(config.docker.bin, image)) {\n await execFileAsync(config.docker.bin, ['pull', image])\n }\n }\n}\n", "import http, { type IncomingMessage, type Server, type ServerResponse } from 'http'\n\nexport interface SandboxHealthServerOptions {\n host: string\n port: number\n pathPrefix: string\n isReady: () => boolean\n}\n\n/** Local probe server under API_PREFIX: /healthz is liveness; /health is readiness. */\nexport async function startSandboxHealthServer(\n options: SandboxHealthServerOptions,\n): Promise<Server> {\n const server = http.createServer((req: IncomingMessage, res: ServerResponse) => {\n const pathname = new URL(req.url ?? '/', 'http://localhost').pathname\n if (pathname === `${options.pathPrefix}/healthz`) {\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ ok: true, status: 'alive' }))\n return\n }\n if (pathname === `${options.pathPrefix}/health`) {\n const ready = options.isReady()\n res.writeHead(ready ? 200 : 503, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ ok: ready, status: ready ? 'ready' : 'not-ready' }))\n return\n }\n res.writeHead(404, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ ok: false, error: 'not found' }))\n })\n\n await new Promise<void>((resolve, reject) => {\n server.listen(options.port, options.host, resolve)\n server.once('error', reject)\n })\n return server\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_config", "import_os", "import_path", "path", "os", "fs", "os", "path", "import_os", "bunyan", "import_bunyan", "import_os", "HOST_NAME", "import_promises", "import_os", "import_path", "path", "http", "fs", "os", "import_child_process", "import_path", "import_promises", "import_os", "MAX_OUTPUT_BYTES", "path", "os", "fs", "vm", "http", "net", "import_child_process", "import_http", "import_net", "import_path", "import_promises", "import_os", "MAX_OUTPUT_BYTES", "JOB_EXIT_SENTINEL", "path", "os", "fs", "http", "net", "import_child_process", "import_util", "import_http", "DEFAULT_EXEC_TIMEOUT_MS", "MAX_EXEC_TIMEOUT_MS", "MAX_OUTPUT_BYTES", "MAX_FILE_BYTES", "http", "import_child_process", "import_util", "import_promises", "import_os", "import_path", "import_http", "DEFAULT_EXEC_TIMEOUT_MS", "MAX_EXEC_TIMEOUT_MS", "MAX_OUTPUT_BYTES", "MAX_FILE_BYTES", "WORKSPACE_DIR", "execFileAsync", "assertSafeWorkspacePath", "path", "os", "fs", "http", "import_http", "path", "https", "http", "import_https", "https", "import_http", "JOB_POLL_INTERVAL_MS", "http", "import_fs", "import_child_process", "fs", "import_os", "os", "rfb", "import_net", "net", "import_child_process", "import_util", "execFileAsync", "version", "import_http", "http"]
|
|
7
7
|
}
|