@ghalex/kvbox-server 0.0.11 → 0.0.12

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.
@@ -153,6 +153,7 @@ async function run(argv, opts = {}) {
153
153
  return { stdout, stderr };
154
154
  } catch (err) {
155
155
  const e = err;
156
+ if (typeof e.code === "number" && opts.okExitCodes?.includes(e.code)) return { stdout: e.stdout ?? "", stderr: e.stderr ?? "" };
156
157
  const detail = (e.stderr ?? e.message ?? "").trim();
157
158
  throw new KvboxError(`${[cmd, ...args].join(" ")} failed${detail ? `: ${detail}` : ""}`);
158
159
  }
@@ -322,7 +323,7 @@ function versionOf(srcFileUrl, injected) {
322
323
  }
323
324
 
324
325
  // src/version.ts
325
- var VERSION = versionOf(import.meta.url, true ? "0.0.11" : void 0);
326
+ var VERSION = versionOf(import.meta.url, true ? "0.0.12" : void 0);
326
327
 
327
328
  // src/routes/capacity.ts
328
329
  import { Hono } from "hono";
@@ -369,6 +370,12 @@ var CreateMachineRequest = z3.object({
369
370
  from: z3.string().optional(),
370
371
  force: z3.boolean().optional()
371
372
  });
373
+ var RescaleMachineRequest = z3.object({
374
+ size: SizeSchema.optional(),
375
+ vcpu: z3.number().int().min(1).max(64).optional(),
376
+ memMib: z3.number().int().min(256).optional(),
377
+ diskGib: z3.number().int().min(1).optional()
378
+ });
372
379
  var SnapshotSchema = z3.object({
373
380
  name: z3.string(),
374
381
  source: z3.string(),
@@ -954,6 +961,55 @@ async function startMachine(name, p = paths()) {
954
961
  throw err;
955
962
  }
956
963
  }
964
+ async function applyAtNextBoot(meta, changes, cfg, p, whileStopped) {
965
+ const wasRunning = pidAlive(meta.pid);
966
+ if (wasRunning) {
967
+ await shutdown(meta, cfg, p, 1e4);
968
+ await rm(p.machine(meta.name).memBase, { force: true });
969
+ }
970
+ const updated = { ...meta, ...changes, pid: null, memSnapshots: void 0 };
971
+ await writeMachineMeta(updated, p);
972
+ if (whileStopped) await whileStopped();
973
+ return wasRunning ? startMachine(meta.name, p) : toMachine(updated, p);
974
+ }
975
+ async function updateMachine(name, p = paths()) {
976
+ const meta = await readMeta(name, p);
977
+ const cfg = await loadConfig(p);
978
+ if (meta.base === void 0) {
979
+ throw new KvboxError(`box ${name} was made before overlays and runs on its own disk copy; it cannot be moved to another base image`);
980
+ }
981
+ assertAssets(cfg);
982
+ const base = await currentBase(cfg, p);
983
+ if (base.version === meta.base) return toMachine(meta, p);
984
+ await assertOverlayCapable(base.file, base.version);
985
+ return applyAtNextBoot(meta, { base: base.version }, cfg, p);
986
+ }
987
+ async function rescaleMachine(name, req, p = paths()) {
988
+ const meta = await readMeta(name, p);
989
+ const cfg = await loadConfig(p);
990
+ const disk = ownDisk(meta, p);
991
+ const currentDiskGib = Math.round(statSync(disk).size / 1024 ** 3);
992
+ const preset = req.size !== void 0 && isSizeName(req.size) ? SIZES[req.size] : void 0;
993
+ const target = {
994
+ vcpu: req.vcpu ?? preset?.vcpu ?? meta.vcpu,
995
+ memMib: req.memMib ?? preset?.memMib ?? meta.memMib,
996
+ diskGib: req.diskGib ?? preset?.diskGib ?? currentDiskGib
997
+ };
998
+ if (target.diskGib < currentDiskGib) {
999
+ throw new KvboxError(`box ${name} has a ${currentDiskGib} GB disk and a disk cannot shrink; ${target.diskGib} GB is smaller`);
1000
+ }
1001
+ const changes = {};
1002
+ if (target.vcpu !== meta.vcpu) changes.vcpu = target.vcpu;
1003
+ if (target.memMib !== meta.memMib) changes.memMib = target.memMib;
1004
+ const growTo = target.diskGib > currentDiskGib ? target.diskGib : void 0;
1005
+ if (Object.keys(changes).length === 0 && growTo === void 0) return toMachine(meta, p);
1006
+ return applyAtNextBoot(meta, changes, cfg, p, growTo === void 0 ? void 0 : () => growDisk(disk, growTo));
1007
+ }
1008
+ async function growDisk(file, gib) {
1009
+ await truncate(file, gib * 1024 ** 3);
1010
+ await run(["e2fsck", "-f", "-p", file], { okExitCodes: [1] });
1011
+ await run(["resize2fs", file]);
1012
+ }
957
1013
  async function readMeta(name, p) {
958
1014
  try {
959
1015
  return await readMachineMeta(name, p);
@@ -979,6 +1035,11 @@ function machineRoutes() {
979
1035
  });
980
1036
  r.post("/:name/stop", async (c) => c.json(await stopMachine(c.req.param("name"))));
981
1037
  r.post("/:name/start", async (c) => c.json(await startMachine(c.req.param("name"))));
1038
+ r.post("/:name/update", async (c) => c.json(await updateMachine(c.req.param("name"))));
1039
+ r.post("/:name/rescale", async (c) => {
1040
+ const body = RescaleMachineRequest.parse(await c.req.json().catch(() => ({})));
1041
+ return c.json(await rescaleMachine(c.req.param("name"), body));
1042
+ });
982
1043
  r.delete("/:name", async (c) => {
983
1044
  await destroyMachine(c.req.param("name"));
984
1045
  return c.body(null, 204);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../../shared/src/errors.ts","../../shared/src/paths.ts","../src/core/config.ts","../../shared/src/sizes.ts","../src/core/network.ts","../src/core/exec.ts","../src/listen.ts","../src/core/state.ts","../src/app.ts","../../shared/src/version.ts","../src/version.ts","../src/routes/capacity.ts","../src/core/capacity.ts","../src/routes/machines.ts","../../shared/src/api.ts","../src/core/machines.ts","../src/core/agent.ts","../src/core/firecracker.ts","../src/routes/snapshots.ts","../src/core/snapshots.ts"],"sourcesContent":["/**\n * kvbox-server: the host daemon. `kvbox-server` (or `kvbox-server start`) serves\n * the kvbox API on ~/.kvbox/server.sock in the foreground; the CLI's\n * `kvbox server start` spawns it detached. M2 adds `register`.\n */\nimport { spawnSync } from \"node:child_process\";\nimport { Command } from \"commander\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { paths } from \"@kvbox/shared/paths\";\nimport { loadConfig } from \"./core/config.js\";\nimport { ensureHostNetwork, netSetupScript } from \"./core/network.js\";\nimport { listen } from \"./listen.js\";\nimport { VERSION } from \"./version.js\";\n\nconst program = new Command(\"kvbox-server\")\n .description(\"kvbox host daemon: owns Firecracker and ~/.kvbox, serves the kvbox API\")\n .version(VERSION, \"-v, --version\")\n .showHelpAfterError();\n\nprogram\n .command(\"start\", { isDefault: true })\n .description(\"serve the API on the local Unix socket (foreground)\")\n .option(\"--socket <path>\", \"socket to listen on (default: $KVBOX_HOME/server.sock)\")\n .action(async (opts: { socket?: string }) => {\n const { socketPath } = await listen(opts.socket ? { socketPath: opts.socket } : {});\n console.log(`kvbox-server ${VERSION} listening on ${socketPath} (pid ${process.pid})`);\n // The bridge vanishes on host reboot; recreate it. Not fatal: ls/status must still work.\n try {\n const cfg = await loadConfig(paths());\n const state = await ensureHostNetwork(cfg);\n console.log(`host network: bridge ${cfg.bridge} ${state}`);\n } catch (err) {\n console.error(`warning: host network not ready (${(err as Error).message}); run: kvbox-server net up`);\n }\n });\n\nprogram\n .command(\"net <action>\")\n .description(\"host network: up | down | status (bridge, forwarding, NAT; uses sudo)\")\n .action(async (action: string) => {\n if (![\"up\", \"down\", \"status\"].includes(action)) throw new KvboxError(\"net: expected up, down or status\");\n const cfg = await loadConfig(paths());\n const res = spawnSync(netSetupScript(), [action], {\n stdio: \"inherit\",\n env: { ...process.env, KVBOX_BRIDGE: cfg.bridge, KVBOX_SUBNET: cfg.subnet, KVBOX_GATEWAY: cfg.gateway },\n });\n process.exit(res.status ?? 1);\n });\n\ntry {\n await program.parseAsync(process.argv);\n} catch (err) {\n if (err instanceof KvboxError) {\n console.error(`error: ${err.message}`);\n process.exit(err.exitCode);\n }\n throw err;\n}\n","/** Errors with an exit code; the entry point prints `message` and exits with `exitCode`. */\nexport class KvboxError extends Error {\n constructor(\n message: string,\n public readonly exitCode: number = 1,\n ) {\n super(message);\n this.name = \"KvboxError\";\n }\n}\n\nexport class NotImplementedError extends KvboxError {\n constructor(what: string) {\n super(`${what}: not implemented yet`, 2);\n this.name = \"NotImplementedError\";\n }\n}\n\n/** The named box/snapshot/host does not exist: HTTP 404, exit 1. */\nexport class NotFoundError extends KvboxError {\n constructor(what: string) {\n super(`${what}: not found`, 1);\n this.name = \"NotFoundError\";\n }\n}\n","/**\n * Host state layout. The filesystem is the database and `~/.kvbox` is its root.\n * This module is dependency-free so both the CLI (socket path, hosts.json)\n * and core (everything else) can use it without crossing the layer boundary.\n *\n * `KVBOX_HOME` overrides the root, mainly for tests.\n */\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport function kvboxHome(): string {\n return process.env[\"KVBOX_HOME\"] ?? join(homedir(), \".kvbox\");\n}\n\nexport function paths(home: string = kvboxHome()) {\n return {\n home,\n config: join(home, \"config.json\"),\n serverSock: join(home, \"server.sock\"),\n serverPid: join(home, \"server.pid\"),\n serverLog: join(home, \"server.log\"),\n hosts: join(home, \"hosts.json\"),\n ssh: join(home, \"ssh\"),\n sshKey: join(home, \"ssh\", \"id_ed25519\"),\n bin: join(home, \"bin\"),\n firecracker: join(home, \"bin\", \"firecracker\"),\n /** Firecracker's snapshot-editor, from the same release: merges a diff snapshot onto a full memory image. */\n snapshotEditor: join(home, \"bin\", \"snapshot-editor\"),\n assets: join(home, \"assets\"),\n kernel: join(home, \"assets\", \"vmlinux\"),\n /** Symlink to the current base image, assets/rootfs-<version>.ext4; boxes keep using the version they were made from. */\n rootfs: join(home, \"assets\", \"rootfs.ext4\"),\n baseImage: (version: string) => join(home, \"assets\", `rootfs-${version}.ext4`),\n machines: join(home, \"machines\"),\n snapshots: join(home, \"snapshots\"),\n machine: (name: string) => ({\n dir: join(home, \"machines\", name),\n meta: join(home, \"machines\", name, \"meta.json\"),\n /** The box's writable layer, stacked on the read-only base image inside the guest. */\n overlay: join(home, \"machines\", name, \"overlay.ext4\"),\n /** Boxes made before overlays: a full copy of the base image. Kept bootable, never created anymore. */\n disk: join(home, \"machines\", name, \"disk.ext4\"),\n /**\n * The box's memory as of its last snapshot (a hard link to that snapshot's `mem`, never modified).\n * The next snapshot is a diff of the pages dirtied since, merged onto this. Absent after a boot.\n */\n memBase: join(home, \"machines\", name, \"mem.base\"),\n sock: join(home, \"machines\", name, \"fc.sock\"),\n /** Firecracker's vsock endpoint: the host connects here to reach kvbox-agent inside the box (core/agent.ts). */\n vsock: join(home, \"machines\", name, \"vsock.sock\"),\n log: join(home, \"machines\", name, \"fc.log\"),\n }),\n snapshot: (name: string) => ({\n dir: join(home, \"snapshots\", name),\n meta: join(home, \"snapshots\", name, \"meta.json\"),\n vmstate: join(home, \"snapshots\", name, \"vmstate\"),\n mem: join(home, \"snapshots\", name, \"mem\"),\n /** Copy of the box's overlay at the moment of the snapshot; the base image is referenced by version in meta.json. */\n overlay: join(home, \"snapshots\", name, \"overlay.ext4\"),\n }),\n } as const;\n}\n\nexport type Paths = ReturnType<typeof paths>;\n","/** `~/.kvbox/config.json`: asset paths, subnet, default size. Written with defaults on first run. */\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { z } from \"zod\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\nimport { DEFAULT_SIZE, SIZE_NAMES } from \"@kvbox/shared/sizes\";\n\nexport const ConfigSchema = z.object({\n kernel: z.string(),\n rootfs: z.string(),\n firecracker: z.string(),\n snapshotEditor: z.string().optional(), // default: bin/snapshot-editor next to firecracker\n bridge: z.string().default(\"kvbox0\"),\n subnet: z.string().default(\"172.30.0.0/24\"),\n gateway: z.string().default(\"172.30.0.1\"),\n defaultSize: z.enum(SIZE_NAMES as [string, ...string[]]).default(DEFAULT_SIZE),\n});\nexport type Config = z.infer<typeof ConfigSchema>;\n\nexport function defaultConfig(p: Paths = paths()): Config {\n return ConfigSchema.parse({\n kernel: p.kernel,\n rootfs: p.rootfs,\n firecracker: p.firecracker,\n snapshotEditor: p.snapshotEditor,\n });\n}\n\nexport async function loadConfig(p: Paths = paths()): Promise<Config> {\n try {\n const raw = await readFile(p.config, \"utf8\");\n return ConfigSchema.parse(JSON.parse(raw));\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n const cfg = defaultConfig(p);\n await writeFile(p.config, JSON.stringify(cfg, null, 2) + \"\\n\");\n return cfg;\n }\n throw err;\n }\n}\n","/**\n * Fixed box sizes. Firecracker backs guest memory lazily and the disk is a sparse overlay on the\n * shared base image, so a box only costs what the guest actually touches.\n */\nexport const SIZES = {\n s: { vcpu: 2, memMib: 4096, diskGib: 8 },\n m: { vcpu: 4, memMib: 8192, diskGib: 16 },\n l: { vcpu: 8, memMib: 16384, diskGib: 32 },\n} as const;\n\nexport type SizeName = keyof typeof SIZES;\nexport const SIZE_NAMES = Object.keys(SIZES) as SizeName[];\nexport const DEFAULT_SIZE: SizeName = \"s\";\n\nexport function isSizeName(value: string): value is SizeName {\n return value in SIZES;\n}\n","/**\n * Host networking: bridge `kvbox0`, one tap `kv-<box>` per box, IP allocation\n * inside the subnet. Everything that needs root goes through one script,\n * `net-setup.sh`, which re-execs itself with `sudo -n` when run from here.\n * `install-server.sh` installs a root-owned copy at PRIVILEGED_SCRIPT plus a\n * sudoers rule for exactly that path; the package copy is the dev fallback.\n */\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport type { Config } from \"./config.js\";\nimport { run } from \"./exec.js\";\n\nexport const TAP_PREFIX = \"kv-\";\nexport const PRIVILEGED_SCRIPT = \"/usr/local/lib/kvbox/net-setup.sh\";\n\ntype NetConfig = Pick<Config, \"bridge\" | \"subnet\" | \"gateway\">;\n\nexport function tapName(box: string): string {\n // Linux interface names are limited to 15 characters.\n return `${TAP_PREFIX}${box}`.slice(0, 15);\n}\n\n/** The script to run: KVBOX_NET_SETUP override, the root-owned install, else the package copy (dist/ or src/core/). */\nexport function netSetupScript(): string {\n const override = process.env[\"KVBOX_NET_SETUP\"];\n if (override) return override;\n if (existsSync(PRIVILEGED_SCRIPT)) return PRIVILEGED_SCRIPT;\n for (const rel of [\"../scripts/net-setup.sh\", \"../../scripts/net-setup.sh\"]) {\n const candidate = fileURLToPath(new URL(rel, import.meta.url));\n if (existsSync(candidate)) return candidate;\n }\n throw new KvboxError(\"net-setup.sh not found next to kvbox-server\");\n}\n\nexport function bridgeExists(bridge: string): boolean {\n return existsSync(`/sys/class/net/${bridge}`);\n}\n\nfunction netRun(cfg: NetConfig, args: string[]) {\n return run([netSetupScript(), ...args], {\n env: { ...process.env, KVBOX_BRIDGE: cfg.bridge, KVBOX_SUBNET: cfg.subnet, KVBOX_GATEWAY: cfg.gateway },\n }).catch((err: Error) => {\n throw new KvboxError(\n `${err.message}\\n (root is needed for host networking; install-server.sh sets up a sudoers rule for ${PRIVILEGED_SCRIPT})`,\n );\n });\n}\n\n/** Run `net-setup.sh up` when the bridge is missing, which is the case after every host reboot. */\nexport async function ensureHostNetwork(cfg: NetConfig): Promise<\"present\" | \"created\"> {\n if (bridgeExists(cfg.bridge)) return \"present\";\n await netRun(cfg, [\"up\"]);\n return \"created\";\n}\n\n/**\n * Create the box's tap (owned by this user) and return its name. Plugged into the bridge unless\n * `detached`: a box restored from a snapshot still carries the source box's MAC and IP, so its tap\n * stays off the switch until kvbox-agent has given it its own (attachTap).\n */\nexport async function createTap(box: string, cfg: NetConfig, opts: { detached?: boolean } = {}): Promise<string> {\n const tap = tapName(box);\n await netRun(cfg, [\"tap\", \"add\", tap, ...(opts.detached ? [\"detached\"] : [])]);\n return tap;\n}\n\nexport async function attachTap(box: string, cfg: NetConfig): Promise<void> {\n await netRun(cfg, [\"tap\", \"attach\", tapName(box)]);\n}\n\nexport async function deleteTap(box: string, cfg: NetConfig): Promise<void> {\n await netRun(cfg, [\"tap\", \"del\", tapName(box)]);\n}\n\n// ── addresses ────────────────────────────────────────────────────────────────\nconst ipToInt = (ip: string) => ip.split(\".\").reduce((acc, o) => (acc << 8) + Number(o), 0) >>> 0;\nconst intToIp = (n: number) => [24, 16, 8, 0].map((s) => (n >>> s) & 255).join(\".\");\n\n/** Lowest free host address in `subnet` (a.b.c.d/len), skipping network, gateway (.1) and broadcast. */\nexport function nextFreeIp(subnet: string, inUse: readonly string[]): string {\n const [base, lenStr] = subnet.split(\"/\");\n const len = Number(lenStr);\n if (!base || !Number.isInteger(len) || len < 8 || len > 30) throw new KvboxError(`bad subnet: ${subnet}`);\n const mask = len === 0 ? 0 : (~0 << (32 - len)) >>> 0;\n const network = (ipToInt(base) & mask) >>> 0;\n const broadcast = (network | (~mask >>> 0)) >>> 0;\n const used = new Set(inUse.map(ipToInt));\n for (let n = network + 2; n < broadcast; n++) {\n if (!used.has(n)) return intToIp(n);\n }\n throw new KvboxError(`no free IP left in ${subnet}`);\n}\n\n/** Locally administered MAC derived from the IP: 06:00:<a>:<b>:<c>:<d>, unique per box and readable. */\nexport function macFor(ip: string): string {\n const hex = ip.split(\".\").map((o) => Number(o).toString(16).padStart(2, \"0\").toUpperCase());\n return [\"06\", \"00\", ...hex].join(\":\");\n}\n","/**\n * The one shell-out helper. Every `firecracker`, `ip`, `ssh`, `cp` call goes\n * through here: argv arrays only (never a shell string), the command is logged,\n * and stderr ends up in the thrown error.\n */\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\n\nconst execFileAsync = promisify(execFile);\n\nexport interface RunOptions {\n sudo?: boolean;\n cwd?: string;\n timeoutMs?: number;\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface RunResult {\n stdout: string;\n stderr: string;\n}\n\nexport async function run(argv: readonly string[], opts: RunOptions = {}): Promise<RunResult> {\n const [cmd, ...args] = opts.sudo ? [\"sudo\", \"-n\", ...argv] : argv;\n if (!cmd) throw new KvboxError(\"run: empty argv\");\n if (process.env[\"KVBOX_DEBUG\"]) console.error(`[exec] ${[cmd, ...args].join(\" \")}`);\n try {\n const { stdout, stderr } = await execFileAsync(cmd, args, {\n cwd: opts.cwd,\n env: opts.env ?? process.env,\n timeout: opts.timeoutMs ?? 30_000,\n maxBuffer: 8 * 1024 * 1024,\n });\n return { stdout, stderr };\n } catch (err) {\n const e = err as NodeJS.ErrnoException & { stderr?: string; code?: number | string };\n const detail = (e.stderr ?? e.message ?? \"\").trim();\n throw new KvboxError(`${[cmd, ...args].join(\" \")} failed${detail ? `: ${detail}` : \"\"}`);\n }\n}\n","/** Bind the app to the local Unix socket and write the pid file. */\nimport { rm, writeFile } from \"node:fs/promises\";\nimport { createAdaptorServer } from \"@hono/node-server\";\nimport { ensureLayout } from \"./core/state.js\";\nimport { loadConfig } from \"./core/config.js\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { paths } from \"@kvbox/shared/paths\";\nimport { createApp } from \"./app.js\";\n\nexport interface ListenOptions {\n socketPath?: string;\n}\n\nexport async function listen(opts: ListenOptions = {}) {\n const p = await ensureLayout(paths());\n await loadConfig(p);\n const socketPath = opts.socketPath ?? p.serverSock;\n // Linux limits a Unix socket path (sun_path) to 108 bytes; bind() fails with EINVAL past it.\n if (Buffer.byteLength(socketPath) > 100) {\n throw new KvboxError(`socket path too long for a Unix socket (${socketPath}); set KVBOX_HOME to a shorter path`);\n }\n\n // A stale socket file from a crashed server blocks bind(); the pid file tells\n // `server status` whether anything is actually alive.\n await rm(socketPath, { force: true });\n\n const server = createAdaptorServer({ fetch: createApp().fetch });\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(socketPath, () => resolve());\n });\n await writeFile(p.serverPid, `${process.pid}\\n`);\n\n const shutdown = async () => {\n server.close();\n await rm(socketPath, { force: true });\n await rm(p.serverPid, { force: true });\n process.exit(0);\n };\n process.once(\"SIGINT\", () => void shutdown());\n process.once(\"SIGTERM\", () => void shutdown());\n\n return { socketPath, server };\n}\n","/**\n * The `~/.kvbox` layout and the per-box / per-snapshot `meta.json` files.\n * The server is the only writer; every read is validated with zod.\n */\nimport { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { z } from \"zod\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\n\nexport const MachineMetaSchema = z.object({\n name: z.string(),\n ip: z.string(),\n mac: z.string(),\n pid: z.number().int().nullable(), // null: stopped on purpose, disk kept\n vcpu: z.number().int(),\n memMib: z.number().int(),\n createdAt: z.string(),\n source: z.string(),\n /** Base image version (assets/rootfs-<version>.ext4) the box overlays. Absent: a pre-overlay box with its own disk.ext4. */\n base: z.string().optional(),\n /**\n * Snapshots taken since this VM started (boot or restore). Firecracker resets its dirty-page bitmap at\n * each one, so when this is > 0 the next diff is only standalone merged onto `mem.base`; if that file\n * is missing the lineage is broken and the next snapshot has to be a full dump. Absent: 0.\n */\n memSnapshots: z.number().int().optional(),\n});\nexport type MachineMeta = z.infer<typeof MachineMetaSchema>;\n\nexport const SnapshotMetaSchema = z.object({\n name: z.string(),\n source: z.string(),\n base: z.string(),\n vcpu: z.number().int(),\n memMib: z.number().int(),\n sizeBytes: z.number().int(),\n createdAt: z.string(),\n});\nexport type SnapshotMeta = z.infer<typeof SnapshotMetaSchema>;\n\n/** Create every directory of the layout. Idempotent; called by `kvbox server start`. */\nexport async function ensureLayout(p: Paths = paths()): Promise<Paths> {\n for (const dir of [p.home, p.ssh, p.bin, p.assets, p.machines, p.snapshots]) {\n await mkdir(dir, { recursive: true, mode: 0o700 });\n }\n return p;\n}\n\nasync function readJson<T>(file: string, schema: z.ZodType<T>): Promise<T> {\n return schema.parse(JSON.parse(await readFile(file, \"utf8\")));\n}\n\nasync function listDirs(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw err;\n }\n}\n\nexport async function readMachineMeta(name: string, p: Paths = paths()) {\n return readJson(p.machine(name).meta, MachineMetaSchema);\n}\n\nexport async function writeMachineMeta(meta: MachineMeta, p: Paths = paths()) {\n await mkdir(p.machine(meta.name).dir, { recursive: true });\n await writeFile(p.machine(meta.name).meta, JSON.stringify(meta, null, 2) + \"\\n\");\n}\n\nexport async function listMachineNames(p: Paths = paths()) {\n return listDirs(p.machines);\n}\n\nexport async function readSnapshotMeta(name: string, p: Paths = paths()) {\n return readJson(p.snapshot(name).meta, SnapshotMetaSchema);\n}\n\nexport async function writeSnapshotMeta(meta: SnapshotMeta, p: Paths = paths()) {\n await mkdir(p.snapshot(meta.name).dir, { recursive: true });\n await writeFile(p.snapshot(meta.name).meta, JSON.stringify(meta, null, 2) + \"\\n\");\n}\n\nexport async function listSnapshotNames(p: Paths = paths()) {\n return listDirs(p.snapshots);\n}\n\n/** True when a pid is alive (signal 0). */\nexport function pidAlive(pid: number | null): boolean {\n if (pid === null || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n return (err as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n","/**\n * The hono app behind `kvbox-server`. Served over `~/.kvbox/server.sock`\n * in M1; the same app goes behind HTTPS in M2.\n */\nimport { Hono } from \"hono\";\nimport { KvboxError, NotFoundError } from \"@kvbox/shared/errors\";\nimport { VERSION } from \"./version.js\";\nimport { capacityRoutes } from \"./routes/capacity.js\";\nimport { machineRoutes } from \"./routes/machines.js\";\nimport { snapshotRoutes } from \"./routes/snapshots.js\";\n\nexport function createApp() {\n const app = new Hono();\n\n app.get(\"/health\", (c) => c.json({ ok: true as const, version: VERSION, pid: process.pid }));\n app.route(\"/machines\", machineRoutes());\n app.route(\"/snapshots\", snapshotRoutes());\n app.route(\"/capacity\", capacityRoutes());\n\n app.notFound((c) => c.json({ error: `no route: ${c.req.method} ${c.req.path}` }, 404));\n app.onError((err, c) => {\n if (err instanceof NotFoundError) return c.json({ error: err.message }, 404);\n if (err instanceof KvboxError) {\n return c.json({ error: err.message }, err.exitCode === 2 ? 501 : 400);\n }\n console.error(err);\n return c.json({ error: err.message }, 500);\n });\n\n return app;\n}\n\nexport type App = ReturnType<typeof createApp>;\n","/**\n * Each binary's version comes from its own package.json: tsup injects\n * `__KVBOX_VERSION__` at build time; the dev path (tsx) reads the file.\n * Usage in a package: `versionOf(import.meta.url)` from its `src/version.ts`.\n */\nimport { createRequire } from \"node:module\";\n\nexport function versionOf(srcFileUrl: string, injected?: string): string {\n if (typeof injected === \"string\") return injected;\n try {\n const require = createRequire(srcFileUrl);\n return (require(\"../package.json\") as { version: string }).version;\n } catch {\n return \"0.0.0-dev\";\n }\n}\n","import { versionOf } from \"@kvbox/shared/version\";\n\ndeclare const __KVBOX_VERSION__: string | undefined;\n\nexport const VERSION: string = versionOf(import.meta.url, typeof __KVBOX_VERSION__ === \"string\" ? __KVBOX_VERSION__ : undefined);\n","import { Hono } from \"hono\";\nimport { capacity } from \"../core/capacity.js\";\n\nexport function capacityRoutes() {\n const r = new Hono();\n r.get(\"/\", async (c) => c.json(await capacity()));\n return r;\n}\n","/**\n * The capacity guard: `kvbox new` refuses when reserved RAM of running boxes\n * plus the new one exceeds host RAM minus 2 GB (hard), or reserved vCPUs exceed\n * 2x host cores (soft). `--force` skips it.\n */\nimport { NotImplementedError } from \"@kvbox/shared/errors\";\nimport type { Capacity } from \"@kvbox/shared/api\";\n\nexport const MEM_HEADROOM_MIB = 2048;\nexport const VCPU_OVERSUBSCRIPTION = 2;\n\nexport async function capacity(): Promise<Capacity> {\n throw new NotImplementedError(\"capacity.capacity\");\n}\n\nexport async function assertRoomFor(_vcpu: number, _memMib: number, _force: boolean): Promise<void> {\n throw new NotImplementedError(\"capacity.assertRoomFor\");\n}\n","import { Hono } from \"hono\";\nimport { CreateMachineRequest } from \"@kvbox/shared/api\";\nimport { createMachine, destroyMachine, listMachines, startMachine, stopMachine } from \"../core/machines.js\";\n\nexport function machineRoutes() {\n const r = new Hono();\n r.get(\"/\", async (c) => c.json(await listMachines()));\n r.post(\"/\", async (c) => {\n const body = CreateMachineRequest.parse(await c.req.json().catch(() => ({})));\n return c.json(await createMachine(body), 201);\n });\n r.post(\"/:name/stop\", async (c) => c.json(await stopMachine(c.req.param(\"name\"))));\n r.post(\"/:name/start\", async (c) => c.json(await startMachine(c.req.param(\"name\"))));\n r.delete(\"/:name\", async (c) => {\n await destroyMachine(c.req.param(\"name\"));\n return c.body(null, 204);\n });\n return r;\n}\n","/**\n * Wire shapes of the kvbox HTTP API, shared by the client (src/cli) and the\n * server (src/server). Validated with zod on both sides because the client\n * may be talking to an older or newer server.\n */\nimport { z } from \"zod\";\nimport { SIZE_NAMES } from \"./sizes.js\";\n\nexport const SizeSchema = z.enum(SIZE_NAMES as [string, ...string[]]);\n\nexport const MachineSchema = z.object({\n name: z.string(),\n ip: z.string(),\n mac: z.string(),\n pid: z.number().int().nullable(),\n vcpu: z.number().int(),\n memMib: z.number().int(),\n diskBytes: z.number().int(), // the box's own writable disk, as the guest sees it\n diskUsedBytes: z.number().int(), // what that sparse file really occupies on the host\n base: z.string().nullable(), // base image version the box runs on (null: pre-overlay box with its own copy)\n createdAt: z.string(),\n source: z.string(), // \"base\" or \"snapshot:<name>\"\n status: z.enum([\"running\", \"stopped\"]),\n});\nexport type Machine = z.infer<typeof MachineSchema>;\n\nexport const CreateMachineRequest = z.object({\n name: z.string().optional(),\n size: SizeSchema.optional(),\n from: z.string().optional(),\n force: z.boolean().optional(),\n});\nexport type CreateMachineRequest = z.infer<typeof CreateMachineRequest>;\n\nexport const SnapshotSchema = z.object({\n name: z.string(),\n source: z.string(), // the box it was taken from\n base: z.string(), // base image version the overlay stacks on; a restore needs the same one\n vcpu: z.number().int(),\n memMib: z.number().int(),\n sizeBytes: z.number().int(), // what vmstate + mem + overlay really occupy on the host\n createdAt: z.string(),\n});\nexport type Snapshot = z.infer<typeof SnapshotSchema>;\n\nexport const CreateSnapshotRequest = z.object({\n box: z.string(),\n name: z.string(),\n});\nexport type CreateSnapshotRequest = z.infer<typeof CreateSnapshotRequest>;\n\nexport const CapacitySchema = z.object({\n hostMemMib: z.number().int(),\n hostCores: z.number().int(),\n reservedMemMib: z.number().int(),\n reservedVcpu: z.number().int(),\n running: z.number().int(),\n});\nexport type Capacity = z.infer<typeof CapacitySchema>;\n\nexport const HealthSchema = z.object({\n ok: z.literal(true),\n version: z.string(),\n pid: z.number().int(),\n});\nexport type Health = z.infer<typeof HealthSchema>;\n\nexport const ApiErrorSchema = z.object({\n error: z.string(),\n});\n","/**\n * Create, list and destroy boxes: what spikes #4 and #6 did by hand.\n * See architecture \"Process model\". The server is the only writer of ~/.kvbox/machines.\n */\nimport { spawn } from \"node:child_process\";\nimport { closeSync, existsSync, openSync, statSync } from \"node:fs\";\nimport { link, mkdir, readFile, realpath, rm, truncate, writeFile } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { KvboxError, NotFoundError } from \"@kvbox/shared/errors\";\nimport type { CreateMachineRequest, Machine } from \"@kvbox/shared/api\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\nimport { SIZES, isSizeName } from \"@kvbox/shared/sizes\";\nimport { setIdentity } from \"./agent.js\";\nimport { loadConfig, type Config } from \"./config.js\";\nimport { run } from \"./exec.js\";\nimport { FirecrackerClient } from \"./firecracker.js\";\nimport { attachTap, createTap, deleteTap, ensureHostNetwork, macFor, nextFreeIp } from \"./network.js\";\nimport {\n listMachineNames,\n pidAlive,\n readMachineMeta,\n readSnapshotMeta,\n writeMachineMeta,\n type MachineMeta,\n type SnapshotMeta,\n} from \"./state.js\";\n\n/** Box names double as hostnames and tap suffixes (kv- + name ≤ 15 chars). */\nconst NAME_RE = /^[a-z0-9][a-z0-9-]{0,11}$/;\nconst AUTO_PREFIX = \"box\";\n/** Every box's vsock address. Firecracker's vsock is per process, so the number need not be unique on the host. */\nconst GUEST_CID = 3;\n/** The overlay drive's path as Firecracker sees it: relative to the box dir, see spawnFirecracker. */\nconst OVERLAY_REL = \"overlay.ext4\";\n\nfunction diskStats(disk: string): { diskBytes: number; diskUsedBytes: number } {\n try {\n const st = statSync(disk);\n return { diskBytes: st.size, diskUsedBytes: st.blocks * 512 };\n } catch {\n return { diskBytes: 0, diskUsedBytes: 0 };\n }\n}\n\n/** A box's own disk file: its overlay, or the full copy pre-overlay boxes were made with. */\nfunction ownDisk(meta: MachineMeta, p: Paths): string {\n const m = p.machine(meta.name);\n return meta.base === undefined ? m.disk : m.overlay;\n}\n\nfunction toMachine(meta: MachineMeta, p: Paths = paths()): Machine {\n const alive = pidAlive(meta.pid);\n return {\n name: meta.name,\n ip: meta.ip,\n mac: meta.mac,\n pid: alive ? meta.pid : null,\n vcpu: meta.vcpu,\n memMib: meta.memMib,\n ...diskStats(ownDisk(meta, p)),\n base: meta.base ?? null,\n createdAt: meta.createdAt,\n source: meta.source,\n status: alive ? \"running\" : \"stopped\",\n };\n}\n\nasync function readAllMeta(p: Paths): Promise<MachineMeta[]> {\n const metas: MachineMeta[] = [];\n for (const name of await listMachineNames(p)) {\n try {\n metas.push(await readMachineMeta(name, p));\n } catch (err) {\n console.error(`warning: skipping machines/${name}: ${(err as Error).message}`);\n }\n }\n return metas;\n}\n\nexport async function listMachines(p: Paths = paths()): Promise<Machine[]> {\n return (await readAllMeta(p)).map((m) => toMachine(m, p));\n}\n\nexport async function getMachine(name: string, p: Paths = paths()): Promise<Machine> {\n return toMachine(await readMeta(name, p), p);\n}\n\nfunction pickName(requested: string | undefined, taken: Set<string>): string {\n if (requested !== undefined) {\n if (!NAME_RE.test(requested)) {\n throw new KvboxError(`invalid box name \"${requested}\": 1-12 chars, lowercase letters, digits and '-', starting with a letter or digit`);\n }\n if (taken.has(requested)) throw new KvboxError(`box ${requested} already exists`);\n return requested;\n }\n for (let i = 1; ; i++) {\n const candidate = `${AUTO_PREFIX}${i}`;\n if (!taken.has(candidate)) return candidate;\n }\n}\n\nexport function bootArgs(name: string, ip: string, cfg: Config, pubkeyB64: string, mode: { overlay: boolean }): string {\n // Firecracker appends `pci=off root=/dev/vda` plus ro/rw itself. ip= is read by the guest\n // kernel, kvbox.name= / kvbox.sshkey= by kvbox-init on first boot (the kvbox-images contract).\n // With an overlay, /sbin/overlay-init in the image stacks the box's disk (/dev/vdb) on the\n // read-only base before systemd starts.\n const init = mode.overlay ? \" init=/sbin/overlay-init kvbox.overlay=/dev/vdb\" : \"\";\n const args = `console=ttyS0 reboot=k panic=1${init} ip=${ip}::${cfg.gateway}:255.255.255.0:${name}:eth0:off kvbox.name=${name} kvbox.sshkey=${pubkeyB64}`;\n return process.arch === \"arm64\" ? `keep_bootcon ${args}` : args;\n}\n\n/** `assets/rootfs-<version>.ext4` -> `<version>`; anything else is the layout from before overlays. */\nexport function baseVersionOf(file: string): string {\n const m = /^rootfs-(.+)\\.ext4$/.exec(basename(file));\n if (!m) throw new KvboxError(`base image ${file} is not versioned (expected assets/rootfs-<version>.ext4); run install-server.sh`);\n return m[1]!;\n}\n\n/** Follow config's rootfs symlink to the base image a new box should be made from. */\nasync function currentBase(cfg: Config, p: Paths): Promise<{ version: string; file: string }> {\n const file = await realpath(cfg.rootfs);\n const version = baseVersionOf(file);\n const expected = p.baseImage(version);\n if (file !== expected) throw new KvboxError(`base image ${cfg.rootfs} points outside ${p.assets} (${file})`);\n return { version, file };\n}\n\n/** The base image this box boots from; a pre-overlay box has none (its own disk copy is the root). */\nfunction baseFileFor(meta: Pick<MachineMeta, \"name\" | \"base\">, p: Paths): string | undefined {\n if (meta.base === undefined) return undefined;\n const file = p.baseImage(meta.base);\n if (!existsSync(file)) throw new KvboxError(`box ${meta.name} runs on base image ${meta.base}, which is gone from ${p.assets}`);\n return file;\n}\n\nconst overlayCapable = new Map<string, boolean>();\n\n/** A base image older than the overlay layout has no /sbin/overlay-init and would panic at boot. debugfs reads the ext4 without mounting it. */\nasync function assertOverlayCapable(baseFile: string, version: string): Promise<void> {\n let ok = overlayCapable.get(baseFile);\n if (ok === undefined) {\n const { stdout } = await run([\"debugfs\", \"-R\", \"stat /sbin/overlay-init\", baseFile]);\n ok = /Type:\\s+regular/.test(stdout);\n overlayCapable.set(baseFile, ok);\n }\n if (!ok) throw new KvboxError(`base image ${version} is too old for this server (no /sbin/overlay-init); rerun install-server.sh to get a newer one`);\n}\n\n/** The box's writable disk: a sparse ext4 of `gib` GiB, ready in milliseconds and occupying a few MB until written to. */\nexport async function createOverlay(file: string, gib: number): Promise<void> {\n await writeFile(file, \"\", { mode: 0o600 });\n await truncate(file, gib * 1024 ** 3);\n // -F: it is a file, not a block device. -m 0: no blocks held back for root, the whole disk is the box's.\n // Lazy init: the inode tables are zeroed by the guest kernel as it goes, so mkfs writes almost nothing.\n await run([\"mkfs.ext4\", \"-q\", \"-F\", \"-m\", \"0\", \"-L\", \"kvbox-box\", \"-E\", \"lazy_itable_init=1,lazy_journal_init=1\", file]);\n}\n\nasync function waitFor(pred: () => boolean, timeoutMs: number, stepMs = 50): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (pred()) return true;\n await sleep(stepMs);\n }\n return pred();\n}\n\nasync function tailOf(file: string, lines = 5): Promise<string> {\n try {\n return (await readFile(file, \"utf8\")).trim().split(\"\\n\").slice(-lines).join(\"\\n\");\n } catch {\n return \"\";\n }\n}\n\ninterface LaunchSpec {\n name: string;\n ip: string;\n mac: string;\n vcpu: number;\n memMib: number;\n base?: string | undefined;\n}\n\n/**\n * Spawn Firecracker detached for box `name` and wait for its API socket. Returns the pid; the\n * caller kills it on any later failure. Its working directory is the box dir and the overlay drive\n * is given as a relative path (OVERLAY_REL): a snapshot's vmstate stores drive paths verbatim, so a\n * relative one resolves to whichever box dir the snapshot is restored into.\n */\nasync function spawnFirecracker(name: string, cfg: Config, p: Paths): Promise<number> {\n const m = p.machine(name);\n await rm(m.sock, { force: true });\n await rm(m.vsock, { force: true });\n const logFd = openSync(m.log, \"a\");\n let child;\n try {\n child = spawn(cfg.firecracker, [\"--api-sock\", m.sock, \"--id\", name, \"--level\", \"Error\"], {\n cwd: m.dir,\n detached: true,\n stdio: [\"ignore\", logFd, logFd],\n });\n } finally {\n closeSync(logFd);\n }\n child.unref();\n const pid = child.pid;\n if (pid === undefined) throw new KvboxError(\"could not start firecracker\");\n if (!(await waitFor(() => existsSync(m.sock), 3000))) {\n killQuietly(pid);\n throw new KvboxError(`firecracker did not open its API socket; last log lines:\\n${await tailOf(m.log)}`);\n }\n return pid;\n}\n\nfunction killQuietly(pid: number): void {\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {\n /* already gone */\n }\n}\n\n/** Spawn Firecracker, configure it over its socket, InstanceStart. Returns the pid. Caller rolls back on throw. */\nasync function launch(spec: LaunchSpec, tap: string, cfg: Config, pubkeyB64: string, p: Paths): Promise<number> {\n const m = p.machine(spec.name);\n const baseFile = baseFileFor(spec, p);\n const pid = await spawnFirecracker(spec.name, cfg, p);\n try {\n const fc = new FirecrackerClient(m.sock);\n try {\n await fc.bootSource(cfg.kernel, bootArgs(spec.name, spec.ip, cfg, pubkeyB64, { overlay: baseFile !== undefined }));\n if (baseFile !== undefined) {\n await fc.rootDrive(baseFile, true);\n await fc.overlayDrive(OVERLAY_REL);\n } else {\n await fc.rootDrive(m.disk, false);\n }\n await fc.machineConfig(spec.vcpu, spec.memMib);\n await fc.networkInterface(\"eth0\", tap, spec.mac);\n await fc.vsock(GUEST_CID, m.vsock);\n await fc.start();\n } finally {\n await fc.close();\n }\n return pid;\n } catch (err) {\n killQuietly(pid);\n throw err;\n }\n}\n\n/**\n * Spawn Firecracker and restore the snapshot into it, still paused, with this box's tap and vsock\n * in place of the source box's. Drive paths cannot be overridden at load: a vmstate written by this\n * server names the overlay relatively and already resolves to this box's copy, while one from an\n * older server names the source box's file (which must still exist for the load to succeed) and is\n * re-pointed afterwards. Returns the pid; the caller resumes and rolls back on throw.\n */\nasync function loadSnapshot(spec: LaunchSpec, snapshotName: string, tap: string, cfg: Config, p: Paths): Promise<number> {\n const m = p.machine(spec.name);\n const s = p.snapshot(snapshotName);\n const pid = await spawnFirecracker(spec.name, cfg, p);\n try {\n const fc = new FirecrackerClient(m.sock);\n try {\n try {\n await fc.snapshotLoad({\n snapshotPath: s.vmstate,\n memFilePath: s.mem,\n tap: { ifaceId: \"eth0\", hostDevName: tap },\n vsockPath: m.vsock,\n trackDirtyPages: true,\n resume: false,\n });\n } catch (err) {\n // No vsock device in the vmstate: the source box predates kvbox-agent, so nothing inside could take the new identity.\n if (/Unknown Vsock Device/.test((err as Error).message)) throw new KvboxError(tooOldToRestore(snapshotName));\n throw err;\n }\n if (await namesOverlayAbsolutely(s.vmstate)) await fc.patchDrivePath(\"overlay\", m.overlay);\n } finally {\n await fc.close();\n }\n return pid;\n } catch (err) {\n killQuietly(pid);\n throw err;\n }\n}\n\nfunction tooOldToRestore(snapshot: string): string {\n return `snapshot ${snapshot} was taken from a box made before kvbox-agent existed (older base image) and cannot be restored: make a fresh box with this kvbox, set it up, and snapshot that one`;\n}\n\n/** The vmstate stores drive paths as plain strings; one with a directory in front is the pre-relative layout. */\nasync function namesOverlayAbsolutely(vmstate: string): Promise<boolean> {\n return (await readFile(vmstate)).includes(`/${OVERLAY_REL}`);\n}\n\nasync function readPubkeyB64(p: Paths): Promise<string> {\n try {\n return Buffer.from((await readFile(`${p.sshKey}.pub`, \"utf8\")).trim()).toString(\"base64\");\n } catch {\n throw new KvboxError(`SSH key missing at ${p.sshKey}.pub; run install-server.sh`);\n }\n}\n\nfunction assertAssets(cfg: Config): void {\n for (const [what, file] of [[\"kernel\", cfg.kernel], [\"base image\", cfg.rootfs], [\"firecracker\", cfg.firecracker]] as const) {\n if (!existsSync(file)) throw new KvboxError(`${what} missing at ${file}; run install-server.sh`);\n }\n}\n\nexport async function createMachine(req: CreateMachineRequest, p: Paths = paths()): Promise<Machine> {\n const cfg = await loadConfig(p);\n if (req.from !== undefined) return restoreMachine(req.from, req, cfg, p);\n const sizeName = req.size ?? cfg.defaultSize;\n if (!isSizeName(sizeName)) throw new KvboxError(`unknown size \"${sizeName}\"; use one of ${Object.keys(SIZES).join(\", \")}`);\n const size = SIZES[sizeName];\n assertAssets(cfg);\n const pubkeyB64 = await readPubkeyB64(p);\n\n const existing = await readAllMeta(p);\n const name = pickName(req.name, new Set(existing.map((m) => m.name)));\n const ip = nextFreeIp(cfg.subnet, [...existing.map((m) => m.ip), cfg.gateway]);\n const mac = macFor(ip);\n const m = p.machine(name);\n\n const base = await currentBase(cfg, p);\n await assertOverlayCapable(base.file, base.version);\n\n await ensureHostNetwork(cfg);\n await mkdir(m.dir, { recursive: true, mode: 0o700 });\n let tapCreated = false;\n try {\n // The base image is shared read-only by every box; only the box's own writes land in its overlay.\n await createOverlay(m.overlay, size.diskGib);\n const tap = await createTap(name, cfg);\n tapCreated = true;\n const spec: LaunchSpec = { name, ip, mac, vcpu: size.vcpu, memMib: size.memMib, base: base.version };\n const pid = await launch(spec, tap, cfg, pubkeyB64, p);\n const meta: MachineMeta = { ...spec, pid, createdAt: new Date().toISOString(), source: \"base\" };\n await writeMachineMeta(meta, p);\n return toMachine(meta, p);\n } catch (err) {\n // leave nothing half-made behind\n if (tapCreated) await deleteTap(name, cfg).catch(() => undefined);\n await rm(m.dir, { recursive: true, force: true });\n throw err;\n }\n}\n\n\nasync function readSnap(name: string, p: Paths): Promise<SnapshotMeta> {\n try {\n return await readSnapshotMeta(name, p);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") throw new NotFoundError(`snapshot ${name}`);\n throw err;\n }\n}\n\n/** a.b.c.d/len -> len */\nfunction prefixLenOf(subnet: string): number {\n return Number(subnet.split(\"/\")[1]);\n}\n\n/**\n * `kvbox new --from <snapshot>`: a warm box. The snapshot's memory and overlay come back exactly as\n * frozen, processes included, under a new name, IP and MAC. The guest itself still remembers the\n * source box's identity, so its tap stays off the bridge until kvbox-agent (reached over vsock, not\n * the network) has applied the new one and set the clock. Sub-second: the memory file is mapped,\n * not read, and the overlay copy is sparse.\n */\nasync function restoreMachine(from: string, req: CreateMachineRequest, cfg: Config, p: Paths): Promise<Machine> {\n const snap = await readSnap(from, p);\n if (req.size !== undefined) {\n throw new KvboxError(`--size cannot be combined with --from: a restored box has the snapshot's size (${from}: ${snap.vcpu} vCPU, ${snap.memMib} MiB)`);\n }\n assertAssets(cfg);\n if (!existsSync(p.baseImage(snap.base))) {\n throw new KvboxError(`snapshot ${from} stacks on base image ${snap.base}, which is gone from ${p.assets}`);\n }\n\n const existing = await readAllMeta(p);\n const name = pickName(req.name, new Set(existing.map((m) => m.name)));\n const ip = nextFreeIp(cfg.subnet, [...existing.map((m) => m.ip), cfg.gateway]);\n const mac = macFor(ip);\n const m = p.machine(name);\n const s = p.snapshot(from);\n\n await ensureHostNetwork(cfg);\n await mkdir(m.dir, { recursive: true, mode: 0o700 });\n let tapCreated = false;\n let pid: number | undefined;\n try {\n await run([\"cp\", \"--sparse=always\", \"--reflink=auto\", s.overlay, m.overlay]);\n // The box's memory lineage starts at the snapshot's image: its first snapshot is a diff merged onto it.\n await link(s.mem, m.memBase);\n const tap = await createTap(name, cfg, { detached: true });\n tapCreated = true;\n const spec: LaunchSpec = { name, ip, mac, vcpu: snap.vcpu, memMib: snap.memMib, base: snap.base };\n pid = await loadSnapshot(spec, from, tap, cfg, p);\n const fc = new FirecrackerClient(m.sock);\n try {\n await fc.resume();\n } finally {\n await fc.close();\n }\n await introduce(spec, m.vsock, cfg, from);\n await attachTap(name, cfg);\n const meta: MachineMeta = { ...spec, pid, createdAt: new Date().toISOString(), source: `snapshot:${from}`, memSnapshots: 1 };\n await writeMachineMeta(meta, p);\n return toMachine(meta, p);\n } catch (err) {\n if (pid !== undefined) killQuietly(pid);\n if (tapCreated) await deleteTap(name, cfg).catch(() => undefined);\n await rm(m.dir, { recursive: true, force: true });\n throw err;\n }\n}\n\n/**\n * Hand the restored guest its identity through kvbox-agent. The agent is already running (it was\n * in memory at the snapshot), but the vsock path to it comes up with the VM, so refused connections\n * are retried for a moment; an agent that accepts and stays silent is not.\n */\nasync function introduce(spec: LaunchSpec, vsock: string, cfg: Config, from: string): Promise<void> {\n const id = { name: spec.name, ip: spec.ip, prefixLen: prefixLenOf(cfg.subnet), gateway: cfg.gateway, mac: spec.mac, time: Math.floor(Date.now() / 1000) };\n const deadline = Date.now() + 3000;\n for (;;) {\n try {\n await setIdentity(vsock, id);\n return;\n } catch (err) {\n const msg = (err as Error).message;\n const transient = /unreachable|refused|before the guest accepted/.test(msg);\n if (!transient || Date.now() >= deadline) {\n throw new KvboxError(`${msg}\\n ${tooOldToRestore(from)}`);\n }\n await sleep(100);\n }\n }\n}\n\n/** Clean guest shutdown (Ctrl+Alt+Del), SIGKILL after `graceMs`; tap removed; disk and meta kept. */\nasync function shutdown(meta: MachineMeta, cfg: Config, p: Paths, graceMs: number): Promise<void> {\n const pid = meta.pid;\n if (pidAlive(pid)) {\n const fc = new FirecrackerClient(p.machine(meta.name).sock);\n try {\n await fc.sendCtrlAltDel();\n } catch {\n process.kill(pid!, \"SIGTERM\");\n } finally {\n await fc.close();\n }\n if (!(await waitFor(() => !pidAlive(pid), graceMs, 100))) {\n try {\n process.kill(pid!, \"SIGKILL\");\n } catch {\n /* exited meanwhile */\n }\n await waitFor(() => !pidAlive(pid), 1000, 50);\n }\n }\n await deleteTap(meta.name, cfg);\n await rm(p.machine(meta.name).sock, { force: true });\n await rm(p.machine(meta.name).vsock, { force: true });\n}\n\nexport async function stopMachine(name: string, p: Paths = paths()): Promise<Machine> {\n const meta = await readMeta(name, p);\n const cfg = await loadConfig(p);\n if (!pidAlive(meta.pid)) throw new KvboxError(`box ${name} is already stopped`);\n await shutdown(meta, cfg, p, 10_000);\n // A stopped box boots from scratch next time, so its memory lineage (see state.ts memSnapshots) starts over.\n await rm(p.machine(name).memBase, { force: true });\n const stopped: MachineMeta = { ...meta, pid: null, memSnapshots: undefined };\n await writeMachineMeta(stopped, p);\n return toMachine(stopped, p);\n}\n\nexport async function startMachine(name: string, p: Paths = paths()): Promise<Machine> {\n const meta = await readMeta(name, p);\n const cfg = await loadConfig(p);\n if (pidAlive(meta.pid)) throw new KvboxError(`box ${name} is already running`);\n assertAssets(cfg);\n const pubkeyB64 = await readPubkeyB64(p);\n await ensureHostNetwork(cfg);\n const tap = await createTap(name, cfg);\n try {\n const pid = await launch(meta, tap, cfg, pubkeyB64, p);\n const started: MachineMeta = { ...meta, pid };\n await writeMachineMeta(started, p);\n return toMachine(started, p);\n } catch (err) {\n await deleteTap(name, cfg).catch(() => undefined);\n throw err;\n }\n}\n\nasync function readMeta(name: string, p: Paths): Promise<MachineMeta> {\n try {\n return await readMachineMeta(name, p);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") throw new NotFoundError(`box ${name}`);\n throw err;\n }\n}\n\nexport async function destroyMachine(name: string, p: Paths = paths()): Promise<void> {\n const meta = await readMeta(name, p);\n const cfg = await loadConfig(p);\n await shutdown(meta, cfg, p, 2000);\n await rm(p.machine(name).dir, { recursive: true, force: true });\n}\n","/**\n * Client for kvbox-agent, the small service every box runs (kvbox-images, /usr/local/sbin/kvbox-agent).\n * It listens on a vsock port, and Firecracker exposes that as a Unix socket next to the box's API\n * socket: connect, send `CONNECT <port>\\n`, get `OK <n>\\n` back once the guest accepted, then the\n * stream is the guest's. The agent speaks one JSON object per line, one request per connection.\n * Vsock does not touch the box's network, so this works whatever the box did to its own eth0.\n */\nimport { connect } from \"node:net\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\n\n/** The vsock port kvbox-agent listens on; fixed in the image. */\nexport const AGENT_PORT = 52;\n\nexport interface Identity {\n name: string;\n ip: string;\n prefixLen: number;\n gateway: string;\n mac: string;\n /** Unix seconds for the guest's clock, which stopped at the snapshot. */\n time: number;\n}\n\ntype AgentReply = { ok: true; [k: string]: unknown } | { ok: false; error: string };\n\n/** One request/reply exchange with the agent behind `udsPath`. Rejects on connection errors, timeout or `ok: false`. */\nexport async function agentCall(udsPath: string, req: Record<string, unknown>, timeoutMs = 5000): Promise<Record<string, unknown>> {\n const reply = await new Promise<string>((resolve, reject) => {\n const sock = connect(udsPath);\n let buf = \"\";\n let handshaken = false;\n const fail = (err: Error) => {\n sock.destroy();\n reject(err);\n };\n sock.setTimeout(timeoutMs, () => fail(new KvboxError(`kvbox-agent did not answer within ${timeoutMs} ms`)));\n sock.once(\"error\", (err) => fail(new KvboxError(`kvbox-agent unreachable: ${err.message}`)));\n sock.once(\"connect\", () => sock.write(`CONNECT ${AGENT_PORT}\\n`));\n sock.on(\"data\", (chunk) => {\n buf += chunk.toString(\"utf8\");\n let nl: number;\n while ((nl = buf.indexOf(\"\\n\")) !== -1) {\n const line = buf.slice(0, nl);\n buf = buf.slice(nl + 1);\n if (!handshaken) {\n if (!line.startsWith(\"OK \")) return fail(new KvboxError(`vsock connect refused: ${line}`));\n handshaken = true;\n sock.write(JSON.stringify(req) + \"\\n\");\n } else {\n sock.end();\n return resolve(line);\n }\n }\n });\n sock.once(\"close\", () => {\n if (!handshaken) fail(new KvboxError(\"vsock connection closed before the guest accepted\"));\n else fail(new KvboxError(\"kvbox-agent closed the connection without a reply\"));\n });\n });\n let parsed: AgentReply;\n try {\n parsed = JSON.parse(reply) as AgentReply;\n } catch {\n throw new KvboxError(`kvbox-agent sent something that is not JSON: ${reply}`);\n }\n if (!parsed.ok) throw new KvboxError(`kvbox-agent: ${parsed.error}`);\n return parsed;\n}\n\nexport function ping(udsPath: string, timeoutMs?: number) {\n return agentCall(udsPath, { op: \"ping\" }, timeoutMs);\n}\n\n/** Tell a restored box who it is now; it renames itself, re-addresses eth0 and sets its clock. */\nexport function setIdentity(udsPath: string, id: Identity, timeoutMs?: number) {\n return agentCall(udsPath, { op: \"identity\", ...id }, timeoutMs);\n}\n","/**\n * Client for one Firecracker process's API socket. Ten-odd endpoints, all\n * PUT/PATCH with JSON bodies, so a thin wrapper over undici beats an SDK.\n */\nimport { Agent, request } from \"undici\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\n\nexport class FirecrackerClient {\n private readonly agent: Agent;\n\n constructor(readonly socketPath: string) {\n this.agent = new Agent({ connect: { socketPath } });\n }\n\n private async call(method: \"GET\" | \"PUT\" | \"PATCH\", path: string, body?: unknown): Promise<unknown> {\n const res = await request(`http://localhost${path}`, {\n dispatcher: this.agent,\n method,\n headers: body === undefined ? {} : { \"content-type\": \"application/json\" },\n body: body === undefined ? null : JSON.stringify(body),\n });\n const text = await res.body.text();\n if (res.statusCode >= 300) {\n throw new KvboxError(`firecracker ${method} ${path} -> ${res.statusCode}: ${text}`);\n }\n return text ? JSON.parse(text) : undefined;\n }\n\n bootSource(kernelImagePath: string, bootArgs: string) {\n return this.call(\"PUT\", \"/boot-source\", { kernel_image_path: kernelImagePath, boot_args: bootArgs });\n }\n\n /**\n * /dev/vda. Firecracker adds `root=/dev/vda` plus `ro` or `rw` to the boot args to match.\n * Read-only for the shared base image; read-write only for pre-overlay boxes with their own copy.\n */\n rootDrive(pathOnHost: string, readOnly: boolean) {\n return this.drive(\"rootfs\", pathOnHost, { root: true, readOnly });\n }\n\n /** The box's own writable disk, /dev/vdb: the guest stacks it on the base as an overlay. */\n overlayDrive(pathOnHost: string) {\n return this.drive(\"overlay\", pathOnHost, { root: false, readOnly: false });\n }\n\n private drive(id: string, pathOnHost: string, opts: { root: boolean; readOnly: boolean }) {\n return this.call(\"PUT\", `/drives/${id}`, {\n drive_id: id,\n path_on_host: pathOnHost,\n is_root_device: opts.root,\n is_read_only: opts.readOnly,\n // \"Unsafe\" (the default) acks guest flushes without doing anything, so the last journal\n // commit of a clean shutdown can be lost when the guest resets and Firecracker exits.\n // Writeback makes a guest flush a real fsync; a box's writes must survive `kvbox stop`.\n cache_type: \"Writeback\",\n });\n }\n\n /** Swap the file behind a drive while the VM runs or is paused; the guest is told the config changed. */\n patchDrivePath(id: string, pathOnHost: string) {\n return this.call(\"PATCH\", `/drives/${id}`, { drive_id: id, path_on_host: pathOnHost });\n }\n\n /**\n * The host's control channel into the box: Firecracker listens on `udsPath`, a connection there\n * followed by `CONNECT <port>\\n` reaches whatever listens on that vsock port in the guest (kvbox-agent).\n */\n vsock(guestCid: number, udsPath: string) {\n return this.call(\"PUT\", \"/vsock\", { guest_cid: guestCid, uds_path: udsPath });\n }\n\n machineConfig(vcpuCount: number, memSizeMib: number) {\n // Dirty page tracking lets a snapshot write only the pages the guest touched since the last one\n // (a \"Diff\" snapshot) instead of dumping all of guest memory: sub-second instead of ~10 s frozen.\n return this.call(\"PUT\", \"/machine-config\", { vcpu_count: vcpuCount, mem_size_mib: memSizeMib, track_dirty_pages: true });\n }\n\n networkInterface(ifaceId: string, hostDevName: string, guestMac: string) {\n return this.call(\"PUT\", `/network-interfaces/${ifaceId}`, {\n iface_id: ifaceId,\n host_dev_name: hostDevName,\n guest_mac: guestMac,\n });\n }\n\n start() {\n return this.call(\"PUT\", \"/actions\", { action_type: \"InstanceStart\" });\n }\n\n /** Ask the guest to shut down cleanly (systemd handles Ctrl+Alt+Del as poweroff on Firecracker). */\n sendCtrlAltDel() {\n return this.call(\"PUT\", \"/actions\", { action_type: \"SendCtrlAltDel\" });\n }\n\n pause() {\n return this.call(\"PATCH\", \"/vm\", { state: \"Paused\" });\n }\n\n resume() {\n return this.call(\"PATCH\", \"/vm\", { state: \"Resumed\" });\n }\n\n /** `track_dirty_pages` is what matters: a box from an older server runs without it. */\n async machineConfigInfo(): Promise<{ vcpu_count: number; mem_size_mib: number; track_dirty_pages: boolean }> {\n return (await this.call(\"GET\", \"/machine-config\")) as { vcpu_count: number; mem_size_mib: number; track_dirty_pages: boolean };\n }\n\n /**\n * Full: all of guest memory, dense (seconds for a 4 GB box). Diff: only pages dirtied since the last\n * snapshot (or since boot), written sparse; needs dirty page tracking and resets its bitmap.\n */\n snapshotCreate(snapshotPath: string, memFilePath: string, type: \"Full\" | \"Diff\" = \"Full\") {\n return this.call(\"PUT\", \"/snapshot/create\", {\n snapshot_type: type,\n snapshot_path: snapshotPath,\n mem_file_path: memFilePath,\n });\n }\n\n /**\n * Restore a snapshot into this (fresh) process. The memory file is mapped privately: the guest's\n * writes never reach the snapshot. The vmstate carries the source box's tap and vsock paths; the\n * overrides point them at this box's. Drive paths are not overridable here: see patchDrivePath.\n */\n snapshotLoad(opts: {\n snapshotPath: string;\n memFilePath: string;\n tap: { ifaceId: string; hostDevName: string };\n vsockPath: string;\n /** Required for diff snapshots later: the flag is not part of the vmstate. */\n trackDirtyPages: boolean;\n resume: boolean;\n }) {\n return this.call(\"PUT\", \"/snapshot/load\", {\n snapshot_path: opts.snapshotPath,\n mem_backend: { backend_type: \"File\", backend_path: opts.memFilePath },\n network_overrides: [{ iface_id: opts.tap.ifaceId, host_dev_name: opts.tap.hostDevName }],\n vsock_override: { uds_path: opts.vsockPath },\n track_dirty_pages: opts.trackDirtyPages,\n resume_vm: opts.resume,\n });\n }\n\n info() {\n return this.call(\"GET\", \"/\");\n }\n\n async close() {\n await this.agent.close();\n }\n}\n","import { Hono } from \"hono\";\nimport { CreateSnapshotRequest } from \"@kvbox/shared/api\";\nimport { deleteSnapshot, listSnapshots, saveSnapshot } from \"../core/snapshots.js\";\n\nexport function snapshotRoutes() {\n const r = new Hono();\n r.get(\"/\", async (c) => c.json(await listSnapshots()));\n r.post(\"/\", async (c) => {\n const body = CreateSnapshotRequest.parse(await c.req.json());\n return c.json(await saveSnapshot(body), 201);\n });\n r.delete(\"/:name\", async (c) => {\n await deleteSnapshot(c.req.param(\"name\"));\n return c.body(null, 204);\n });\n return r;\n}\n","/**\n * Snapshots: a running box frozen into `snapshots/<name>/` as vmstate + mem (a complete memory image)\n * + a copy of the box's overlay. The base image is referenced by version, not copied, so a snapshot costs\n * what the guest touched (memory pages + overlay blocks), not the box's size.\n *\n * Memory is captured incrementally. Boxes run with dirty page tracking, so Firecracker can write only\n * the pages dirtied since the last snapshot (a \"Diff\": sub-second, sparse) instead of dumping all of\n * guest memory (~10 s frozen for 4 GB). A diff is only a complete image when merged onto the previous\n * one, so each box keeps `mem.base`, a hard link to its last snapshot's `mem`, and the merge happens\n * after the box is already running again. See state.ts `memSnapshots` for the bookkeeping.\n */\nimport { existsSync } from \"node:fs\";\nimport { link, mkdir, readdir, rename, rm, stat } from \"node:fs/promises\";\nimport { KvboxError, NotFoundError } from \"@kvbox/shared/errors\";\nimport type { CreateSnapshotRequest, Snapshot } from \"@kvbox/shared/api\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\nimport { loadConfig } from \"./config.js\";\nimport { run } from \"./exec.js\";\nimport { FirecrackerClient } from \"./firecracker.js\";\nimport {\n listSnapshotNames,\n pidAlive,\n readMachineMeta,\n readSnapshotMeta,\n writeMachineMeta,\n writeSnapshotMeta,\n type MachineMeta,\n type SnapshotMeta,\n} from \"./state.js\";\n\n/** Snapshot names are directory names shown in tables: letters, digits, dots, dashes, underscores. */\nconst NAME_RE = /^[a-z0-9][a-z0-9._-]{0,63}$/;\n\nfunction toSnapshot(meta: SnapshotMeta): Snapshot {\n return {\n name: meta.name,\n source: meta.source,\n base: meta.base,\n vcpu: meta.vcpu,\n memMib: meta.memMib,\n sizeBytes: meta.sizeBytes,\n createdAt: meta.createdAt,\n };\n}\n\nexport async function listSnapshots(p: Paths = paths()): Promise<Snapshot[]> {\n const out: Snapshot[] = [];\n for (const name of await listSnapshotNames(p)) {\n try {\n out.push(toSnapshot(await readSnapshotMeta(name, p)));\n } catch (err) {\n console.error(`warning: skipping snapshots/${name}: ${(err as Error).message}`);\n }\n }\n return out;\n}\n\n/** Bytes the snapshot really occupies: its files are sparse, so allocated blocks, not sizes. */\nasync function usedBytes(dir: string): Promise<number> {\n let total = 0;\n for (const entry of await readdir(dir)) {\n total += (await stat(`${dir}/${entry}`)).blocks * 512;\n }\n return total;\n}\n\nasync function readBox(name: string, p: Paths): Promise<MachineMeta> {\n try {\n return await readMachineMeta(name, p);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") throw new NotFoundError(`box ${name}`);\n throw err;\n }\n}\n\nexport async function saveSnapshot(req: CreateSnapshotRequest, p: Paths = paths()): Promise<Snapshot> {\n if (!NAME_RE.test(req.name)) {\n throw new KvboxError(`invalid snapshot name \"${req.name}\": 1-64 chars, lowercase letters, digits, '.', '_' and '-', starting with a letter or digit`);\n }\n const box = await readBox(req.box, p);\n if (box.base === undefined) {\n throw new KvboxError(`box ${req.box} was made before overlays and runs on its own disk copy; snapshots need a box made by this version of kvbox (kvbox new)`);\n }\n if (!pidAlive(box.pid)) {\n throw new KvboxError(`box ${req.box} is not running; a snapshot freezes a running box (kvbox start ${req.box} first)`);\n }\n const s = p.snapshot(req.name);\n if (existsSync(s.dir)) throw new KvboxError(`snapshot ${req.name} already exists`);\n const cfg = await loadConfig(p);\n const m = p.machine(box.name);\n\n await mkdir(s.dir, { recursive: true, mode: 0o700 });\n const fc = new FirecrackerClient(m.sock);\n let lineageTouched = false;\n try {\n const tracked = (await fc.machineConfigInfo()).track_dirty_pages;\n const since = box.memSnapshots ?? 0;\n // A diff is standalone right after boot, or once merged onto the previous image. Otherwise (a box\n // from an older server without tracking, or a lineage broken by an earlier failure) dump everything.\n const mode: \"Diff\" | \"Full\" = tracked && (since === 0 || existsSync(m.memBase)) ? \"Diff\" : \"Full\";\n\n // The guest is frozen for the whole capture so memory and overlay describe the same instant.\n let failure: unknown;\n await fc.pause();\n try {\n await fc.snapshotCreate(s.vmstate, s.mem, mode);\n lineageTouched = tracked; // Firecracker reset its dirty bitmap: the box's next diff is relative to this image\n await run([\"cp\", \"--sparse=always\", \"--reflink=auto\", m.overlay, s.overlay]);\n } catch (err) {\n failure = err;\n } finally {\n await fc.resume();\n }\n if (lineageTouched) {\n // Recorded before anything else can fail: memSnapshots > 0 without mem.base reads as a broken\n // lineage, and the next snapshot falls back to a full dump instead of a diff missing pages.\n await writeMachineMeta({ ...box, memSnapshots: since + 1 }, p);\n }\n if (failure !== undefined) throw failure;\n\n if (mode === \"Full\") {\n // A full dump is dense; pages the guest never touched are zeros, so punch them out.\n await run([\"fallocate\", \"--dig-holes\", s.mem]);\n } else if (since > 0) {\n await mergeOntoPrevious(m.memBase, s.mem, cfg.snapshotEditor ?? p.snapshotEditor);\n }\n if (tracked) {\n await rm(m.memBase, { force: true });\n await link(s.mem, m.memBase);\n }\n\n const meta: SnapshotMeta = {\n name: req.name,\n source: box.name,\n base: box.base,\n vcpu: box.vcpu,\n memMib: box.memMib,\n sizeBytes: await usedBytes(s.dir),\n createdAt: new Date().toISOString(),\n };\n await writeSnapshotMeta(meta, p);\n return toSnapshot(meta);\n } catch (err) {\n // The diff that was just discarded took pages with it: never let the next diff build on the old image.\n if (lineageTouched) await rm(m.memBase, { force: true }).catch(() => undefined);\n await rm(s.dir, { recursive: true, force: true });\n throw err;\n } finally {\n await fc.close();\n }\n}\n\n/**\n * Turn the diff at `diffFile` into a complete image: copy the previous image and apply the diff's pages\n * over it. Holes in the diff are untouched pages; a page dirtied to zeros is data and overwrites.\n */\nasync function mergeOntoPrevious(previous: string, diffFile: string, editor: string): Promise<void> {\n if (!existsSync(editor)) throw new KvboxError(`snapshot-editor missing at ${editor}; rerun install-server.sh`);\n const merged = `${diffFile}.merged`;\n await run([\"cp\", \"--sparse=always\", \"--reflink=auto\", previous, merged]);\n await run([editor, \"edit-memory\", \"rebase\", \"--memory-path\", merged, \"--diff-path\", diffFile]);\n await rename(merged, diffFile);\n}\n\nexport async function deleteSnapshot(name: string, p: Paths = paths()): Promise<void> {\n if (!existsSync(p.snapshot(name).dir)) throw new NotFoundError(`snapshot ${name}`);\n await rm(p.snapshot(name).dir, { recursive: true, force: true });\n}\n"],"mappings":"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","names":["rm","writeFile","readFile","writeFile","z","z","readFile","writeFile","Hono","require","Hono","z","z","existsSync","mkdir","readFile","writeFile","bootArgs","existsSync","writeFile","readFile","m","mkdir","Hono","Hono","existsSync","link","mkdir","readdir","rm","NAME_RE","readdir","existsSync","mkdir","rm","link","Hono","Hono","rm","writeFile","shutdown"]}
1
+ {"version":3,"sources":["../src/index.ts","../../shared/src/errors.ts","../../shared/src/paths.ts","../src/core/config.ts","../../shared/src/sizes.ts","../src/core/network.ts","../src/core/exec.ts","../src/listen.ts","../src/core/state.ts","../src/app.ts","../../shared/src/version.ts","../src/version.ts","../src/routes/capacity.ts","../src/core/capacity.ts","../src/routes/machines.ts","../../shared/src/api.ts","../src/core/machines.ts","../src/core/agent.ts","../src/core/firecracker.ts","../src/routes/snapshots.ts","../src/core/snapshots.ts"],"sourcesContent":["/**\n * kvbox-server: the host daemon. `kvbox-server` (or `kvbox-server start`) serves\n * the kvbox API on ~/.kvbox/server.sock in the foreground; the CLI's\n * `kvbox server start` spawns it detached. M2 adds `register`.\n */\nimport { spawnSync } from \"node:child_process\";\nimport { Command } from \"commander\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { paths } from \"@kvbox/shared/paths\";\nimport { loadConfig } from \"./core/config.js\";\nimport { ensureHostNetwork, netSetupScript } from \"./core/network.js\";\nimport { listen } from \"./listen.js\";\nimport { VERSION } from \"./version.js\";\n\nconst program = new Command(\"kvbox-server\")\n .description(\"kvbox host daemon: owns Firecracker and ~/.kvbox, serves the kvbox API\")\n .version(VERSION, \"-v, --version\")\n .showHelpAfterError();\n\nprogram\n .command(\"start\", { isDefault: true })\n .description(\"serve the API on the local Unix socket (foreground)\")\n .option(\"--socket <path>\", \"socket to listen on (default: $KVBOX_HOME/server.sock)\")\n .action(async (opts: { socket?: string }) => {\n const { socketPath } = await listen(opts.socket ? { socketPath: opts.socket } : {});\n console.log(`kvbox-server ${VERSION} listening on ${socketPath} (pid ${process.pid})`);\n // The bridge vanishes on host reboot; recreate it. Not fatal: ls/status must still work.\n try {\n const cfg = await loadConfig(paths());\n const state = await ensureHostNetwork(cfg);\n console.log(`host network: bridge ${cfg.bridge} ${state}`);\n } catch (err) {\n console.error(`warning: host network not ready (${(err as Error).message}); run: kvbox-server net up`);\n }\n });\n\nprogram\n .command(\"net <action>\")\n .description(\"host network: up | down | status (bridge, forwarding, NAT; uses sudo)\")\n .action(async (action: string) => {\n if (![\"up\", \"down\", \"status\"].includes(action)) throw new KvboxError(\"net: expected up, down or status\");\n const cfg = await loadConfig(paths());\n const res = spawnSync(netSetupScript(), [action], {\n stdio: \"inherit\",\n env: { ...process.env, KVBOX_BRIDGE: cfg.bridge, KVBOX_SUBNET: cfg.subnet, KVBOX_GATEWAY: cfg.gateway },\n });\n process.exit(res.status ?? 1);\n });\n\ntry {\n await program.parseAsync(process.argv);\n} catch (err) {\n if (err instanceof KvboxError) {\n console.error(`error: ${err.message}`);\n process.exit(err.exitCode);\n }\n throw err;\n}\n","/** Errors with an exit code; the entry point prints `message` and exits with `exitCode`. */\nexport class KvboxError extends Error {\n constructor(\n message: string,\n public readonly exitCode: number = 1,\n ) {\n super(message);\n this.name = \"KvboxError\";\n }\n}\n\nexport class NotImplementedError extends KvboxError {\n constructor(what: string) {\n super(`${what}: not implemented yet`, 2);\n this.name = \"NotImplementedError\";\n }\n}\n\n/** The named box/snapshot/host does not exist: HTTP 404, exit 1. */\nexport class NotFoundError extends KvboxError {\n constructor(what: string) {\n super(`${what}: not found`, 1);\n this.name = \"NotFoundError\";\n }\n}\n","/**\n * Host state layout. The filesystem is the database and `~/.kvbox` is its root.\n * This module is dependency-free so both the CLI (socket path, hosts.json)\n * and core (everything else) can use it without crossing the layer boundary.\n *\n * `KVBOX_HOME` overrides the root, mainly for tests.\n */\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport function kvboxHome(): string {\n return process.env[\"KVBOX_HOME\"] ?? join(homedir(), \".kvbox\");\n}\n\nexport function paths(home: string = kvboxHome()) {\n return {\n home,\n config: join(home, \"config.json\"),\n serverSock: join(home, \"server.sock\"),\n serverPid: join(home, \"server.pid\"),\n serverLog: join(home, \"server.log\"),\n hosts: join(home, \"hosts.json\"),\n ssh: join(home, \"ssh\"),\n sshKey: join(home, \"ssh\", \"id_ed25519\"),\n bin: join(home, \"bin\"),\n firecracker: join(home, \"bin\", \"firecracker\"),\n /** Firecracker's snapshot-editor, from the same release: merges a diff snapshot onto a full memory image. */\n snapshotEditor: join(home, \"bin\", \"snapshot-editor\"),\n assets: join(home, \"assets\"),\n kernel: join(home, \"assets\", \"vmlinux\"),\n /** Symlink to the current base image, assets/rootfs-<version>.ext4; boxes keep using the version they were made from. */\n rootfs: join(home, \"assets\", \"rootfs.ext4\"),\n baseImage: (version: string) => join(home, \"assets\", `rootfs-${version}.ext4`),\n machines: join(home, \"machines\"),\n snapshots: join(home, \"snapshots\"),\n machine: (name: string) => ({\n dir: join(home, \"machines\", name),\n meta: join(home, \"machines\", name, \"meta.json\"),\n /** The box's writable layer, stacked on the read-only base image inside the guest. */\n overlay: join(home, \"machines\", name, \"overlay.ext4\"),\n /** Boxes made before overlays: a full copy of the base image. Kept bootable, never created anymore. */\n disk: join(home, \"machines\", name, \"disk.ext4\"),\n /**\n * The box's memory as of its last snapshot (a hard link to that snapshot's `mem`, never modified).\n * The next snapshot is a diff of the pages dirtied since, merged onto this. Absent after a boot.\n */\n memBase: join(home, \"machines\", name, \"mem.base\"),\n sock: join(home, \"machines\", name, \"fc.sock\"),\n /** Firecracker's vsock endpoint: the host connects here to reach kvbox-agent inside the box (core/agent.ts). */\n vsock: join(home, \"machines\", name, \"vsock.sock\"),\n log: join(home, \"machines\", name, \"fc.log\"),\n }),\n snapshot: (name: string) => ({\n dir: join(home, \"snapshots\", name),\n meta: join(home, \"snapshots\", name, \"meta.json\"),\n vmstate: join(home, \"snapshots\", name, \"vmstate\"),\n mem: join(home, \"snapshots\", name, \"mem\"),\n /** Copy of the box's overlay at the moment of the snapshot; the base image is referenced by version in meta.json. */\n overlay: join(home, \"snapshots\", name, \"overlay.ext4\"),\n }),\n } as const;\n}\n\nexport type Paths = ReturnType<typeof paths>;\n","/** `~/.kvbox/config.json`: asset paths, subnet, default size. Written with defaults on first run. */\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { z } from \"zod\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\nimport { DEFAULT_SIZE, SIZE_NAMES } from \"@kvbox/shared/sizes\";\n\nexport const ConfigSchema = z.object({\n kernel: z.string(),\n rootfs: z.string(),\n firecracker: z.string(),\n snapshotEditor: z.string().optional(), // default: bin/snapshot-editor next to firecracker\n bridge: z.string().default(\"kvbox0\"),\n subnet: z.string().default(\"172.30.0.0/24\"),\n gateway: z.string().default(\"172.30.0.1\"),\n defaultSize: z.enum(SIZE_NAMES as [string, ...string[]]).default(DEFAULT_SIZE),\n});\nexport type Config = z.infer<typeof ConfigSchema>;\n\nexport function defaultConfig(p: Paths = paths()): Config {\n return ConfigSchema.parse({\n kernel: p.kernel,\n rootfs: p.rootfs,\n firecracker: p.firecracker,\n snapshotEditor: p.snapshotEditor,\n });\n}\n\nexport async function loadConfig(p: Paths = paths()): Promise<Config> {\n try {\n const raw = await readFile(p.config, \"utf8\");\n return ConfigSchema.parse(JSON.parse(raw));\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n const cfg = defaultConfig(p);\n await writeFile(p.config, JSON.stringify(cfg, null, 2) + \"\\n\");\n return cfg;\n }\n throw err;\n }\n}\n","/**\n * Fixed box sizes. Firecracker backs guest memory lazily and the disk is a sparse overlay on the\n * shared base image, so a box only costs what the guest actually touches.\n */\nexport const SIZES = {\n s: { vcpu: 2, memMib: 4096, diskGib: 8 },\n m: { vcpu: 4, memMib: 8192, diskGib: 16 },\n l: { vcpu: 8, memMib: 16384, diskGib: 32 },\n} as const;\n\nexport type SizeName = keyof typeof SIZES;\nexport const SIZE_NAMES = Object.keys(SIZES) as SizeName[];\nexport const DEFAULT_SIZE: SizeName = \"s\";\n\nexport function isSizeName(value: string): value is SizeName {\n return value in SIZES;\n}\n\n/**\n * \"16GB\", \"16G\", \"16\", \"4096MB\", \"4096M\", \"0.5GB\" -> MiB. A bare number is GB: that is how\n * people say it (\"16gb\", \"4 vcpu 16gb\"). Returns undefined when it is not a size.\n */\nexport function parseMib(text: string): number | undefined {\n const m = /^\\s*(\\d+(?:\\.\\d+)?)\\s*([gm]i?b?)?\\s*$/i.exec(text);\n if (!m) return undefined;\n const n = Number(m[1]);\n const unit = (m[2] ?? \"g\").toLowerCase();\n const mib = unit.startsWith(\"m\") ? n : n * 1024;\n return Number.isInteger(mib) && mib > 0 ? mib : undefined;\n}\n","/**\n * Host networking: bridge `kvbox0`, one tap `kv-<box>` per box, IP allocation\n * inside the subnet. Everything that needs root goes through one script,\n * `net-setup.sh`, which re-execs itself with `sudo -n` when run from here.\n * `install-server.sh` installs a root-owned copy at PRIVILEGED_SCRIPT plus a\n * sudoers rule for exactly that path; the package copy is the dev fallback.\n */\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport type { Config } from \"./config.js\";\nimport { run } from \"./exec.js\";\n\nexport const TAP_PREFIX = \"kv-\";\nexport const PRIVILEGED_SCRIPT = \"/usr/local/lib/kvbox/net-setup.sh\";\n\ntype NetConfig = Pick<Config, \"bridge\" | \"subnet\" | \"gateway\">;\n\nexport function tapName(box: string): string {\n // Linux interface names are limited to 15 characters.\n return `${TAP_PREFIX}${box}`.slice(0, 15);\n}\n\n/** The script to run: KVBOX_NET_SETUP override, the root-owned install, else the package copy (dist/ or src/core/). */\nexport function netSetupScript(): string {\n const override = process.env[\"KVBOX_NET_SETUP\"];\n if (override) return override;\n if (existsSync(PRIVILEGED_SCRIPT)) return PRIVILEGED_SCRIPT;\n for (const rel of [\"../scripts/net-setup.sh\", \"../../scripts/net-setup.sh\"]) {\n const candidate = fileURLToPath(new URL(rel, import.meta.url));\n if (existsSync(candidate)) return candidate;\n }\n throw new KvboxError(\"net-setup.sh not found next to kvbox-server\");\n}\n\nexport function bridgeExists(bridge: string): boolean {\n return existsSync(`/sys/class/net/${bridge}`);\n}\n\nfunction netRun(cfg: NetConfig, args: string[]) {\n return run([netSetupScript(), ...args], {\n env: { ...process.env, KVBOX_BRIDGE: cfg.bridge, KVBOX_SUBNET: cfg.subnet, KVBOX_GATEWAY: cfg.gateway },\n }).catch((err: Error) => {\n throw new KvboxError(\n `${err.message}\\n (root is needed for host networking; install-server.sh sets up a sudoers rule for ${PRIVILEGED_SCRIPT})`,\n );\n });\n}\n\n/** Run `net-setup.sh up` when the bridge is missing, which is the case after every host reboot. */\nexport async function ensureHostNetwork(cfg: NetConfig): Promise<\"present\" | \"created\"> {\n if (bridgeExists(cfg.bridge)) return \"present\";\n await netRun(cfg, [\"up\"]);\n return \"created\";\n}\n\n/**\n * Create the box's tap (owned by this user) and return its name. Plugged into the bridge unless\n * `detached`: a box restored from a snapshot still carries the source box's MAC and IP, so its tap\n * stays off the switch until kvbox-agent has given it its own (attachTap).\n */\nexport async function createTap(box: string, cfg: NetConfig, opts: { detached?: boolean } = {}): Promise<string> {\n const tap = tapName(box);\n await netRun(cfg, [\"tap\", \"add\", tap, ...(opts.detached ? [\"detached\"] : [])]);\n return tap;\n}\n\nexport async function attachTap(box: string, cfg: NetConfig): Promise<void> {\n await netRun(cfg, [\"tap\", \"attach\", tapName(box)]);\n}\n\nexport async function deleteTap(box: string, cfg: NetConfig): Promise<void> {\n await netRun(cfg, [\"tap\", \"del\", tapName(box)]);\n}\n\n// ── addresses ────────────────────────────────────────────────────────────────\nconst ipToInt = (ip: string) => ip.split(\".\").reduce((acc, o) => (acc << 8) + Number(o), 0) >>> 0;\nconst intToIp = (n: number) => [24, 16, 8, 0].map((s) => (n >>> s) & 255).join(\".\");\n\n/** Lowest free host address in `subnet` (a.b.c.d/len), skipping network, gateway (.1) and broadcast. */\nexport function nextFreeIp(subnet: string, inUse: readonly string[]): string {\n const [base, lenStr] = subnet.split(\"/\");\n const len = Number(lenStr);\n if (!base || !Number.isInteger(len) || len < 8 || len > 30) throw new KvboxError(`bad subnet: ${subnet}`);\n const mask = len === 0 ? 0 : (~0 << (32 - len)) >>> 0;\n const network = (ipToInt(base) & mask) >>> 0;\n const broadcast = (network | (~mask >>> 0)) >>> 0;\n const used = new Set(inUse.map(ipToInt));\n for (let n = network + 2; n < broadcast; n++) {\n if (!used.has(n)) return intToIp(n);\n }\n throw new KvboxError(`no free IP left in ${subnet}`);\n}\n\n/** Locally administered MAC derived from the IP: 06:00:<a>:<b>:<c>:<d>, unique per box and readable. */\nexport function macFor(ip: string): string {\n const hex = ip.split(\".\").map((o) => Number(o).toString(16).padStart(2, \"0\").toUpperCase());\n return [\"06\", \"00\", ...hex].join(\":\");\n}\n","/**\n * The one shell-out helper. Every `firecracker`, `ip`, `ssh`, `cp` call goes\n * through here: argv arrays only (never a shell string), the command is logged,\n * and stderr ends up in the thrown error.\n */\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\n\nconst execFileAsync = promisify(execFile);\n\nexport interface RunOptions {\n sudo?: boolean;\n cwd?: string;\n timeoutMs?: number;\n env?: NodeJS.ProcessEnv;\n /** Non-zero exit codes that are not failures (e2fsck: 1 = \"errors corrected\"). */\n okExitCodes?: readonly number[];\n}\n\nexport interface RunResult {\n stdout: string;\n stderr: string;\n}\n\nexport async function run(argv: readonly string[], opts: RunOptions = {}): Promise<RunResult> {\n const [cmd, ...args] = opts.sudo ? [\"sudo\", \"-n\", ...argv] : argv;\n if (!cmd) throw new KvboxError(\"run: empty argv\");\n if (process.env[\"KVBOX_DEBUG\"]) console.error(`[exec] ${[cmd, ...args].join(\" \")}`);\n try {\n const { stdout, stderr } = await execFileAsync(cmd, args, {\n cwd: opts.cwd,\n env: opts.env ?? process.env,\n timeout: opts.timeoutMs ?? 30_000,\n maxBuffer: 8 * 1024 * 1024,\n });\n return { stdout, stderr };\n } catch (err) {\n const e = err as NodeJS.ErrnoException & { stdout?: string; stderr?: string; code?: number | string };\n if (typeof e.code === \"number\" && opts.okExitCodes?.includes(e.code)) return { stdout: e.stdout ?? \"\", stderr: e.stderr ?? \"\" };\n const detail = (e.stderr ?? e.message ?? \"\").trim();\n throw new KvboxError(`${[cmd, ...args].join(\" \")} failed${detail ? `: ${detail}` : \"\"}`);\n }\n}\n","/** Bind the app to the local Unix socket and write the pid file. */\nimport { rm, writeFile } from \"node:fs/promises\";\nimport { createAdaptorServer } from \"@hono/node-server\";\nimport { ensureLayout } from \"./core/state.js\";\nimport { loadConfig } from \"./core/config.js\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { paths } from \"@kvbox/shared/paths\";\nimport { createApp } from \"./app.js\";\n\nexport interface ListenOptions {\n socketPath?: string;\n}\n\nexport async function listen(opts: ListenOptions = {}) {\n const p = await ensureLayout(paths());\n await loadConfig(p);\n const socketPath = opts.socketPath ?? p.serverSock;\n // Linux limits a Unix socket path (sun_path) to 108 bytes; bind() fails with EINVAL past it.\n if (Buffer.byteLength(socketPath) > 100) {\n throw new KvboxError(`socket path too long for a Unix socket (${socketPath}); set KVBOX_HOME to a shorter path`);\n }\n\n // A stale socket file from a crashed server blocks bind(); the pid file tells\n // `server status` whether anything is actually alive.\n await rm(socketPath, { force: true });\n\n const server = createAdaptorServer({ fetch: createApp().fetch });\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(socketPath, () => resolve());\n });\n await writeFile(p.serverPid, `${process.pid}\\n`);\n\n const shutdown = async () => {\n server.close();\n await rm(socketPath, { force: true });\n await rm(p.serverPid, { force: true });\n process.exit(0);\n };\n process.once(\"SIGINT\", () => void shutdown());\n process.once(\"SIGTERM\", () => void shutdown());\n\n return { socketPath, server };\n}\n","/**\n * The `~/.kvbox` layout and the per-box / per-snapshot `meta.json` files.\n * The server is the only writer; every read is validated with zod.\n */\nimport { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { z } from \"zod\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\n\nexport const MachineMetaSchema = z.object({\n name: z.string(),\n ip: z.string(),\n mac: z.string(),\n pid: z.number().int().nullable(), // null: stopped on purpose, disk kept\n vcpu: z.number().int(),\n memMib: z.number().int(),\n createdAt: z.string(),\n source: z.string(),\n /** Base image version (assets/rootfs-<version>.ext4) the box overlays. Absent: a pre-overlay box with its own disk.ext4. */\n base: z.string().optional(),\n /**\n * Snapshots taken since this VM started (boot or restore). Firecracker resets its dirty-page bitmap at\n * each one, so when this is > 0 the next diff is only standalone merged onto `mem.base`; if that file\n * is missing the lineage is broken and the next snapshot has to be a full dump. Absent: 0.\n */\n memSnapshots: z.number().int().optional(),\n});\nexport type MachineMeta = z.infer<typeof MachineMetaSchema>;\n\nexport const SnapshotMetaSchema = z.object({\n name: z.string(),\n source: z.string(),\n base: z.string(),\n vcpu: z.number().int(),\n memMib: z.number().int(),\n sizeBytes: z.number().int(),\n createdAt: z.string(),\n});\nexport type SnapshotMeta = z.infer<typeof SnapshotMetaSchema>;\n\n/** Create every directory of the layout. Idempotent; called by `kvbox server start`. */\nexport async function ensureLayout(p: Paths = paths()): Promise<Paths> {\n for (const dir of [p.home, p.ssh, p.bin, p.assets, p.machines, p.snapshots]) {\n await mkdir(dir, { recursive: true, mode: 0o700 });\n }\n return p;\n}\n\nasync function readJson<T>(file: string, schema: z.ZodType<T>): Promise<T> {\n return schema.parse(JSON.parse(await readFile(file, \"utf8\")));\n}\n\nasync function listDirs(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw err;\n }\n}\n\nexport async function readMachineMeta(name: string, p: Paths = paths()) {\n return readJson(p.machine(name).meta, MachineMetaSchema);\n}\n\nexport async function writeMachineMeta(meta: MachineMeta, p: Paths = paths()) {\n await mkdir(p.machine(meta.name).dir, { recursive: true });\n await writeFile(p.machine(meta.name).meta, JSON.stringify(meta, null, 2) + \"\\n\");\n}\n\nexport async function listMachineNames(p: Paths = paths()) {\n return listDirs(p.machines);\n}\n\nexport async function readSnapshotMeta(name: string, p: Paths = paths()) {\n return readJson(p.snapshot(name).meta, SnapshotMetaSchema);\n}\n\nexport async function writeSnapshotMeta(meta: SnapshotMeta, p: Paths = paths()) {\n await mkdir(p.snapshot(meta.name).dir, { recursive: true });\n await writeFile(p.snapshot(meta.name).meta, JSON.stringify(meta, null, 2) + \"\\n\");\n}\n\nexport async function listSnapshotNames(p: Paths = paths()) {\n return listDirs(p.snapshots);\n}\n\n/** True when a pid is alive (signal 0). */\nexport function pidAlive(pid: number | null): boolean {\n if (pid === null || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n return (err as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n","/**\n * The hono app behind `kvbox-server`. Served over `~/.kvbox/server.sock`\n * in M1; the same app goes behind HTTPS in M2.\n */\nimport { Hono } from \"hono\";\nimport { KvboxError, NotFoundError } from \"@kvbox/shared/errors\";\nimport { VERSION } from \"./version.js\";\nimport { capacityRoutes } from \"./routes/capacity.js\";\nimport { machineRoutes } from \"./routes/machines.js\";\nimport { snapshotRoutes } from \"./routes/snapshots.js\";\n\nexport function createApp() {\n const app = new Hono();\n\n app.get(\"/health\", (c) => c.json({ ok: true as const, version: VERSION, pid: process.pid }));\n app.route(\"/machines\", machineRoutes());\n app.route(\"/snapshots\", snapshotRoutes());\n app.route(\"/capacity\", capacityRoutes());\n\n app.notFound((c) => c.json({ error: `no route: ${c.req.method} ${c.req.path}` }, 404));\n app.onError((err, c) => {\n if (err instanceof NotFoundError) return c.json({ error: err.message }, 404);\n if (err instanceof KvboxError) {\n return c.json({ error: err.message }, err.exitCode === 2 ? 501 : 400);\n }\n console.error(err);\n return c.json({ error: err.message }, 500);\n });\n\n return app;\n}\n\nexport type App = ReturnType<typeof createApp>;\n","/**\n * Each binary's version comes from its own package.json: tsup injects\n * `__KVBOX_VERSION__` at build time; the dev path (tsx) reads the file.\n * Usage in a package: `versionOf(import.meta.url)` from its `src/version.ts`.\n */\nimport { createRequire } from \"node:module\";\n\nexport function versionOf(srcFileUrl: string, injected?: string): string {\n if (typeof injected === \"string\") return injected;\n try {\n const require = createRequire(srcFileUrl);\n return (require(\"../package.json\") as { version: string }).version;\n } catch {\n return \"0.0.0-dev\";\n }\n}\n","import { versionOf } from \"@kvbox/shared/version\";\n\ndeclare const __KVBOX_VERSION__: string | undefined;\n\nexport const VERSION: string = versionOf(import.meta.url, typeof __KVBOX_VERSION__ === \"string\" ? __KVBOX_VERSION__ : undefined);\n","import { Hono } from \"hono\";\nimport { capacity } from \"../core/capacity.js\";\n\nexport function capacityRoutes() {\n const r = new Hono();\n r.get(\"/\", async (c) => c.json(await capacity()));\n return r;\n}\n","/**\n * The capacity guard: `kvbox new` refuses when reserved RAM of running boxes\n * plus the new one exceeds host RAM minus 2 GB (hard), or reserved vCPUs exceed\n * 2x host cores (soft). `--force` skips it.\n */\nimport { NotImplementedError } from \"@kvbox/shared/errors\";\nimport type { Capacity } from \"@kvbox/shared/api\";\n\nexport const MEM_HEADROOM_MIB = 2048;\nexport const VCPU_OVERSUBSCRIPTION = 2;\n\nexport async function capacity(): Promise<Capacity> {\n throw new NotImplementedError(\"capacity.capacity\");\n}\n\nexport async function assertRoomFor(_vcpu: number, _memMib: number, _force: boolean): Promise<void> {\n throw new NotImplementedError(\"capacity.assertRoomFor\");\n}\n","import { Hono } from \"hono\";\nimport { CreateMachineRequest, RescaleMachineRequest } from \"@kvbox/shared/api\";\nimport { createMachine, destroyMachine, listMachines, rescaleMachine, startMachine, stopMachine, updateMachine } from \"../core/machines.js\";\n\nexport function machineRoutes() {\n const r = new Hono();\n r.get(\"/\", async (c) => c.json(await listMachines()));\n r.post(\"/\", async (c) => {\n const body = CreateMachineRequest.parse(await c.req.json().catch(() => ({})));\n return c.json(await createMachine(body), 201);\n });\n r.post(\"/:name/stop\", async (c) => c.json(await stopMachine(c.req.param(\"name\"))));\n r.post(\"/:name/start\", async (c) => c.json(await startMachine(c.req.param(\"name\"))));\n r.post(\"/:name/update\", async (c) => c.json(await updateMachine(c.req.param(\"name\"))));\n r.post(\"/:name/rescale\", async (c) => {\n const body = RescaleMachineRequest.parse(await c.req.json().catch(() => ({})));\n return c.json(await rescaleMachine(c.req.param(\"name\"), body));\n });\n r.delete(\"/:name\", async (c) => {\n await destroyMachine(c.req.param(\"name\"));\n return c.body(null, 204);\n });\n return r;\n}\n","/**\n * Wire shapes of the kvbox HTTP API, shared by the client (src/cli) and the\n * server (src/server). Validated with zod on both sides because the client\n * may be talking to an older or newer server.\n */\nimport { z } from \"zod\";\nimport { SIZE_NAMES } from \"./sizes.js\";\n\nexport const SizeSchema = z.enum(SIZE_NAMES as [string, ...string[]]);\n\nexport const MachineSchema = z.object({\n name: z.string(),\n ip: z.string(),\n mac: z.string(),\n pid: z.number().int().nullable(),\n vcpu: z.number().int(),\n memMib: z.number().int(),\n diskBytes: z.number().int(), // the box's own writable disk, as the guest sees it\n diskUsedBytes: z.number().int(), // what that sparse file really occupies on the host\n base: z.string().nullable(), // base image version the box runs on (null: pre-overlay box with its own copy)\n createdAt: z.string(),\n source: z.string(), // \"base\" or \"snapshot:<name>\"\n status: z.enum([\"running\", \"stopped\"]),\n});\nexport type Machine = z.infer<typeof MachineSchema>;\n\nexport const CreateMachineRequest = z.object({\n name: z.string().optional(),\n size: SizeSchema.optional(),\n from: z.string().optional(),\n force: z.boolean().optional(),\n});\nexport type CreateMachineRequest = z.infer<typeof CreateMachineRequest>;\n\n/** `kvbox rescale`: a preset and/or explicit values; explicit ones win. Anything omitted stays as it is. */\nexport const RescaleMachineRequest = z.object({\n size: SizeSchema.optional(),\n vcpu: z.number().int().min(1).max(64).optional(),\n memMib: z.number().int().min(256).optional(),\n diskGib: z.number().int().min(1).optional(),\n});\nexport type RescaleMachineRequest = z.infer<typeof RescaleMachineRequest>;\n\nexport const SnapshotSchema = z.object({\n name: z.string(),\n source: z.string(), // the box it was taken from\n base: z.string(), // base image version the overlay stacks on; a restore needs the same one\n vcpu: z.number().int(),\n memMib: z.number().int(),\n sizeBytes: z.number().int(), // what vmstate + mem + overlay really occupy on the host\n createdAt: z.string(),\n});\nexport type Snapshot = z.infer<typeof SnapshotSchema>;\n\nexport const CreateSnapshotRequest = z.object({\n box: z.string(),\n name: z.string(),\n});\nexport type CreateSnapshotRequest = z.infer<typeof CreateSnapshotRequest>;\n\nexport const CapacitySchema = z.object({\n hostMemMib: z.number().int(),\n hostCores: z.number().int(),\n reservedMemMib: z.number().int(),\n reservedVcpu: z.number().int(),\n running: z.number().int(),\n});\nexport type Capacity = z.infer<typeof CapacitySchema>;\n\nexport const HealthSchema = z.object({\n ok: z.literal(true),\n version: z.string(),\n pid: z.number().int(),\n});\nexport type Health = z.infer<typeof HealthSchema>;\n\nexport const ApiErrorSchema = z.object({\n error: z.string(),\n});\n","/**\n * Create, list and destroy boxes: what spikes #4 and #6 did by hand.\n * See architecture \"Process model\". The server is the only writer of ~/.kvbox/machines.\n */\nimport { spawn } from \"node:child_process\";\nimport { closeSync, existsSync, openSync, statSync } from \"node:fs\";\nimport { link, mkdir, readFile, realpath, rm, truncate, writeFile } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { KvboxError, NotFoundError } from \"@kvbox/shared/errors\";\nimport type { CreateMachineRequest, Machine, RescaleMachineRequest } from \"@kvbox/shared/api\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\nimport { SIZES, isSizeName } from \"@kvbox/shared/sizes\";\nimport { setIdentity } from \"./agent.js\";\nimport { loadConfig, type Config } from \"./config.js\";\nimport { run } from \"./exec.js\";\nimport { FirecrackerClient } from \"./firecracker.js\";\nimport { attachTap, createTap, deleteTap, ensureHostNetwork, macFor, nextFreeIp } from \"./network.js\";\nimport {\n listMachineNames,\n pidAlive,\n readMachineMeta,\n readSnapshotMeta,\n writeMachineMeta,\n type MachineMeta,\n type SnapshotMeta,\n} from \"./state.js\";\n\n/** Box names double as hostnames and tap suffixes (kv- + name ≤ 15 chars). */\nconst NAME_RE = /^[a-z0-9][a-z0-9-]{0,11}$/;\nconst AUTO_PREFIX = \"box\";\n/** Every box's vsock address. Firecracker's vsock is per process, so the number need not be unique on the host. */\nconst GUEST_CID = 3;\n/** The overlay drive's path as Firecracker sees it: relative to the box dir, see spawnFirecracker. */\nconst OVERLAY_REL = \"overlay.ext4\";\n\nfunction diskStats(disk: string): { diskBytes: number; diskUsedBytes: number } {\n try {\n const st = statSync(disk);\n return { diskBytes: st.size, diskUsedBytes: st.blocks * 512 };\n } catch {\n return { diskBytes: 0, diskUsedBytes: 0 };\n }\n}\n\n/** A box's own disk file: its overlay, or the full copy pre-overlay boxes were made with. */\nfunction ownDisk(meta: MachineMeta, p: Paths): string {\n const m = p.machine(meta.name);\n return meta.base === undefined ? m.disk : m.overlay;\n}\n\nfunction toMachine(meta: MachineMeta, p: Paths = paths()): Machine {\n const alive = pidAlive(meta.pid);\n return {\n name: meta.name,\n ip: meta.ip,\n mac: meta.mac,\n pid: alive ? meta.pid : null,\n vcpu: meta.vcpu,\n memMib: meta.memMib,\n ...diskStats(ownDisk(meta, p)),\n base: meta.base ?? null,\n createdAt: meta.createdAt,\n source: meta.source,\n status: alive ? \"running\" : \"stopped\",\n };\n}\n\nasync function readAllMeta(p: Paths): Promise<MachineMeta[]> {\n const metas: MachineMeta[] = [];\n for (const name of await listMachineNames(p)) {\n try {\n metas.push(await readMachineMeta(name, p));\n } catch (err) {\n console.error(`warning: skipping machines/${name}: ${(err as Error).message}`);\n }\n }\n return metas;\n}\n\nexport async function listMachines(p: Paths = paths()): Promise<Machine[]> {\n return (await readAllMeta(p)).map((m) => toMachine(m, p));\n}\n\nexport async function getMachine(name: string, p: Paths = paths()): Promise<Machine> {\n return toMachine(await readMeta(name, p), p);\n}\n\nfunction pickName(requested: string | undefined, taken: Set<string>): string {\n if (requested !== undefined) {\n if (!NAME_RE.test(requested)) {\n throw new KvboxError(`invalid box name \"${requested}\": 1-12 chars, lowercase letters, digits and '-', starting with a letter or digit`);\n }\n if (taken.has(requested)) throw new KvboxError(`box ${requested} already exists`);\n return requested;\n }\n for (let i = 1; ; i++) {\n const candidate = `${AUTO_PREFIX}${i}`;\n if (!taken.has(candidate)) return candidate;\n }\n}\n\nexport function bootArgs(name: string, ip: string, cfg: Config, pubkeyB64: string, mode: { overlay: boolean }): string {\n // Firecracker appends `pci=off root=/dev/vda` plus ro/rw itself. ip= is read by the guest\n // kernel, kvbox.name= / kvbox.sshkey= by kvbox-init on first boot (the kvbox-images contract).\n // With an overlay, /sbin/overlay-init in the image stacks the box's disk (/dev/vdb) on the\n // read-only base before systemd starts.\n const init = mode.overlay ? \" init=/sbin/overlay-init kvbox.overlay=/dev/vdb\" : \"\";\n const args = `console=ttyS0 reboot=k panic=1${init} ip=${ip}::${cfg.gateway}:255.255.255.0:${name}:eth0:off kvbox.name=${name} kvbox.sshkey=${pubkeyB64}`;\n return process.arch === \"arm64\" ? `keep_bootcon ${args}` : args;\n}\n\n/** `assets/rootfs-<version>.ext4` -> `<version>`; anything else is the layout from before overlays. */\nexport function baseVersionOf(file: string): string {\n const m = /^rootfs-(.+)\\.ext4$/.exec(basename(file));\n if (!m) throw new KvboxError(`base image ${file} is not versioned (expected assets/rootfs-<version>.ext4); run install-server.sh`);\n return m[1]!;\n}\n\n/** Follow config's rootfs symlink to the base image a new box should be made from. */\nasync function currentBase(cfg: Config, p: Paths): Promise<{ version: string; file: string }> {\n const file = await realpath(cfg.rootfs);\n const version = baseVersionOf(file);\n const expected = p.baseImage(version);\n if (file !== expected) throw new KvboxError(`base image ${cfg.rootfs} points outside ${p.assets} (${file})`);\n return { version, file };\n}\n\n/** The base image this box boots from; a pre-overlay box has none (its own disk copy is the root). */\nfunction baseFileFor(meta: Pick<MachineMeta, \"name\" | \"base\">, p: Paths): string | undefined {\n if (meta.base === undefined) return undefined;\n const file = p.baseImage(meta.base);\n if (!existsSync(file)) throw new KvboxError(`box ${meta.name} runs on base image ${meta.base}, which is gone from ${p.assets}`);\n return file;\n}\n\nconst overlayCapable = new Map<string, boolean>();\n\n/** A base image older than the overlay layout has no /sbin/overlay-init and would panic at boot. debugfs reads the ext4 without mounting it. */\nasync function assertOverlayCapable(baseFile: string, version: string): Promise<void> {\n let ok = overlayCapable.get(baseFile);\n if (ok === undefined) {\n const { stdout } = await run([\"debugfs\", \"-R\", \"stat /sbin/overlay-init\", baseFile]);\n ok = /Type:\\s+regular/.test(stdout);\n overlayCapable.set(baseFile, ok);\n }\n if (!ok) throw new KvboxError(`base image ${version} is too old for this server (no /sbin/overlay-init); rerun install-server.sh to get a newer one`);\n}\n\n/** The box's writable disk: a sparse ext4 of `gib` GiB, ready in milliseconds and occupying a few MB until written to. */\nexport async function createOverlay(file: string, gib: number): Promise<void> {\n await writeFile(file, \"\", { mode: 0o600 });\n await truncate(file, gib * 1024 ** 3);\n // -F: it is a file, not a block device. -m 0: no blocks held back for root, the whole disk is the box's.\n // Lazy init: the inode tables are zeroed by the guest kernel as it goes, so mkfs writes almost nothing.\n await run([\"mkfs.ext4\", \"-q\", \"-F\", \"-m\", \"0\", \"-L\", \"kvbox-box\", \"-E\", \"lazy_itable_init=1,lazy_journal_init=1\", file]);\n}\n\nasync function waitFor(pred: () => boolean, timeoutMs: number, stepMs = 50): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (pred()) return true;\n await sleep(stepMs);\n }\n return pred();\n}\n\nasync function tailOf(file: string, lines = 5): Promise<string> {\n try {\n return (await readFile(file, \"utf8\")).trim().split(\"\\n\").slice(-lines).join(\"\\n\");\n } catch {\n return \"\";\n }\n}\n\ninterface LaunchSpec {\n name: string;\n ip: string;\n mac: string;\n vcpu: number;\n memMib: number;\n base?: string | undefined;\n}\n\n/**\n * Spawn Firecracker detached for box `name` and wait for its API socket. Returns the pid; the\n * caller kills it on any later failure. Its working directory is the box dir and the overlay drive\n * is given as a relative path (OVERLAY_REL): a snapshot's vmstate stores drive paths verbatim, so a\n * relative one resolves to whichever box dir the snapshot is restored into.\n */\nasync function spawnFirecracker(name: string, cfg: Config, p: Paths): Promise<number> {\n const m = p.machine(name);\n await rm(m.sock, { force: true });\n await rm(m.vsock, { force: true });\n const logFd = openSync(m.log, \"a\");\n let child;\n try {\n child = spawn(cfg.firecracker, [\"--api-sock\", m.sock, \"--id\", name, \"--level\", \"Error\"], {\n cwd: m.dir,\n detached: true,\n stdio: [\"ignore\", logFd, logFd],\n });\n } finally {\n closeSync(logFd);\n }\n child.unref();\n const pid = child.pid;\n if (pid === undefined) throw new KvboxError(\"could not start firecracker\");\n if (!(await waitFor(() => existsSync(m.sock), 3000))) {\n killQuietly(pid);\n throw new KvboxError(`firecracker did not open its API socket; last log lines:\\n${await tailOf(m.log)}`);\n }\n return pid;\n}\n\nfunction killQuietly(pid: number): void {\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {\n /* already gone */\n }\n}\n\n/** Spawn Firecracker, configure it over its socket, InstanceStart. Returns the pid. Caller rolls back on throw. */\nasync function launch(spec: LaunchSpec, tap: string, cfg: Config, pubkeyB64: string, p: Paths): Promise<number> {\n const m = p.machine(spec.name);\n const baseFile = baseFileFor(spec, p);\n const pid = await spawnFirecracker(spec.name, cfg, p);\n try {\n const fc = new FirecrackerClient(m.sock);\n try {\n await fc.bootSource(cfg.kernel, bootArgs(spec.name, spec.ip, cfg, pubkeyB64, { overlay: baseFile !== undefined }));\n if (baseFile !== undefined) {\n await fc.rootDrive(baseFile, true);\n await fc.overlayDrive(OVERLAY_REL);\n } else {\n await fc.rootDrive(m.disk, false);\n }\n await fc.machineConfig(spec.vcpu, spec.memMib);\n await fc.networkInterface(\"eth0\", tap, spec.mac);\n await fc.vsock(GUEST_CID, m.vsock);\n await fc.start();\n } finally {\n await fc.close();\n }\n return pid;\n } catch (err) {\n killQuietly(pid);\n throw err;\n }\n}\n\n/**\n * Spawn Firecracker and restore the snapshot into it, still paused, with this box's tap and vsock\n * in place of the source box's. Drive paths cannot be overridden at load: a vmstate written by this\n * server names the overlay relatively and already resolves to this box's copy, while one from an\n * older server names the source box's file (which must still exist for the load to succeed) and is\n * re-pointed afterwards. Returns the pid; the caller resumes and rolls back on throw.\n */\nasync function loadSnapshot(spec: LaunchSpec, snapshotName: string, tap: string, cfg: Config, p: Paths): Promise<number> {\n const m = p.machine(spec.name);\n const s = p.snapshot(snapshotName);\n const pid = await spawnFirecracker(spec.name, cfg, p);\n try {\n const fc = new FirecrackerClient(m.sock);\n try {\n try {\n await fc.snapshotLoad({\n snapshotPath: s.vmstate,\n memFilePath: s.mem,\n tap: { ifaceId: \"eth0\", hostDevName: tap },\n vsockPath: m.vsock,\n trackDirtyPages: true,\n resume: false,\n });\n } catch (err) {\n // No vsock device in the vmstate: the source box predates kvbox-agent, so nothing inside could take the new identity.\n if (/Unknown Vsock Device/.test((err as Error).message)) throw new KvboxError(tooOldToRestore(snapshotName));\n throw err;\n }\n if (await namesOverlayAbsolutely(s.vmstate)) await fc.patchDrivePath(\"overlay\", m.overlay);\n } finally {\n await fc.close();\n }\n return pid;\n } catch (err) {\n killQuietly(pid);\n throw err;\n }\n}\n\nfunction tooOldToRestore(snapshot: string): string {\n return `snapshot ${snapshot} was taken from a box made before kvbox-agent existed (older base image) and cannot be restored: make a fresh box with this kvbox, set it up, and snapshot that one`;\n}\n\n/** The vmstate stores drive paths as plain strings; one with a directory in front is the pre-relative layout. */\nasync function namesOverlayAbsolutely(vmstate: string): Promise<boolean> {\n return (await readFile(vmstate)).includes(`/${OVERLAY_REL}`);\n}\n\nasync function readPubkeyB64(p: Paths): Promise<string> {\n try {\n return Buffer.from((await readFile(`${p.sshKey}.pub`, \"utf8\")).trim()).toString(\"base64\");\n } catch {\n throw new KvboxError(`SSH key missing at ${p.sshKey}.pub; run install-server.sh`);\n }\n}\n\nfunction assertAssets(cfg: Config): void {\n for (const [what, file] of [[\"kernel\", cfg.kernel], [\"base image\", cfg.rootfs], [\"firecracker\", cfg.firecracker]] as const) {\n if (!existsSync(file)) throw new KvboxError(`${what} missing at ${file}; run install-server.sh`);\n }\n}\n\nexport async function createMachine(req: CreateMachineRequest, p: Paths = paths()): Promise<Machine> {\n const cfg = await loadConfig(p);\n if (req.from !== undefined) return restoreMachine(req.from, req, cfg, p);\n const sizeName = req.size ?? cfg.defaultSize;\n if (!isSizeName(sizeName)) throw new KvboxError(`unknown size \"${sizeName}\"; use one of ${Object.keys(SIZES).join(\", \")}`);\n const size = SIZES[sizeName];\n assertAssets(cfg);\n const pubkeyB64 = await readPubkeyB64(p);\n\n const existing = await readAllMeta(p);\n const name = pickName(req.name, new Set(existing.map((m) => m.name)));\n const ip = nextFreeIp(cfg.subnet, [...existing.map((m) => m.ip), cfg.gateway]);\n const mac = macFor(ip);\n const m = p.machine(name);\n\n const base = await currentBase(cfg, p);\n await assertOverlayCapable(base.file, base.version);\n\n await ensureHostNetwork(cfg);\n await mkdir(m.dir, { recursive: true, mode: 0o700 });\n let tapCreated = false;\n try {\n // The base image is shared read-only by every box; only the box's own writes land in its overlay.\n await createOverlay(m.overlay, size.diskGib);\n const tap = await createTap(name, cfg);\n tapCreated = true;\n const spec: LaunchSpec = { name, ip, mac, vcpu: size.vcpu, memMib: size.memMib, base: base.version };\n const pid = await launch(spec, tap, cfg, pubkeyB64, p);\n const meta: MachineMeta = { ...spec, pid, createdAt: new Date().toISOString(), source: \"base\" };\n await writeMachineMeta(meta, p);\n return toMachine(meta, p);\n } catch (err) {\n // leave nothing half-made behind\n if (tapCreated) await deleteTap(name, cfg).catch(() => undefined);\n await rm(m.dir, { recursive: true, force: true });\n throw err;\n }\n}\n\n\nasync function readSnap(name: string, p: Paths): Promise<SnapshotMeta> {\n try {\n return await readSnapshotMeta(name, p);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") throw new NotFoundError(`snapshot ${name}`);\n throw err;\n }\n}\n\n/** a.b.c.d/len -> len */\nfunction prefixLenOf(subnet: string): number {\n return Number(subnet.split(\"/\")[1]);\n}\n\n/**\n * `kvbox new --from <snapshot>`: a warm box. The snapshot's memory and overlay come back exactly as\n * frozen, processes included, under a new name, IP and MAC. The guest itself still remembers the\n * source box's identity, so its tap stays off the bridge until kvbox-agent (reached over vsock, not\n * the network) has applied the new one and set the clock. Sub-second: the memory file is mapped,\n * not read, and the overlay copy is sparse.\n */\nasync function restoreMachine(from: string, req: CreateMachineRequest, cfg: Config, p: Paths): Promise<Machine> {\n const snap = await readSnap(from, p);\n if (req.size !== undefined) {\n throw new KvboxError(`--size cannot be combined with --from: a restored box has the snapshot's size (${from}: ${snap.vcpu} vCPU, ${snap.memMib} MiB)`);\n }\n assertAssets(cfg);\n if (!existsSync(p.baseImage(snap.base))) {\n throw new KvboxError(`snapshot ${from} stacks on base image ${snap.base}, which is gone from ${p.assets}`);\n }\n\n const existing = await readAllMeta(p);\n const name = pickName(req.name, new Set(existing.map((m) => m.name)));\n const ip = nextFreeIp(cfg.subnet, [...existing.map((m) => m.ip), cfg.gateway]);\n const mac = macFor(ip);\n const m = p.machine(name);\n const s = p.snapshot(from);\n\n await ensureHostNetwork(cfg);\n await mkdir(m.dir, { recursive: true, mode: 0o700 });\n let tapCreated = false;\n let pid: number | undefined;\n try {\n await run([\"cp\", \"--sparse=always\", \"--reflink=auto\", s.overlay, m.overlay]);\n // The box's memory lineage starts at the snapshot's image: its first snapshot is a diff merged onto it.\n await link(s.mem, m.memBase);\n const tap = await createTap(name, cfg, { detached: true });\n tapCreated = true;\n const spec: LaunchSpec = { name, ip, mac, vcpu: snap.vcpu, memMib: snap.memMib, base: snap.base };\n pid = await loadSnapshot(spec, from, tap, cfg, p);\n const fc = new FirecrackerClient(m.sock);\n try {\n await fc.resume();\n } finally {\n await fc.close();\n }\n await introduce(spec, m.vsock, cfg, from);\n await attachTap(name, cfg);\n const meta: MachineMeta = { ...spec, pid, createdAt: new Date().toISOString(), source: `snapshot:${from}`, memSnapshots: 1 };\n await writeMachineMeta(meta, p);\n return toMachine(meta, p);\n } catch (err) {\n if (pid !== undefined) killQuietly(pid);\n if (tapCreated) await deleteTap(name, cfg).catch(() => undefined);\n await rm(m.dir, { recursive: true, force: true });\n throw err;\n }\n}\n\n/**\n * Hand the restored guest its identity through kvbox-agent. The agent is already running (it was\n * in memory at the snapshot), but the vsock path to it comes up with the VM, so refused connections\n * are retried for a moment; an agent that accepts and stays silent is not.\n */\nasync function introduce(spec: LaunchSpec, vsock: string, cfg: Config, from: string): Promise<void> {\n const id = { name: spec.name, ip: spec.ip, prefixLen: prefixLenOf(cfg.subnet), gateway: cfg.gateway, mac: spec.mac, time: Math.floor(Date.now() / 1000) };\n const deadline = Date.now() + 3000;\n for (;;) {\n try {\n await setIdentity(vsock, id);\n return;\n } catch (err) {\n const msg = (err as Error).message;\n const transient = /unreachable|refused|before the guest accepted/.test(msg);\n if (!transient || Date.now() >= deadline) {\n throw new KvboxError(`${msg}\\n ${tooOldToRestore(from)}`);\n }\n await sleep(100);\n }\n }\n}\n\n/** Clean guest shutdown (Ctrl+Alt+Del), SIGKILL after `graceMs`; tap removed; disk and meta kept. */\nasync function shutdown(meta: MachineMeta, cfg: Config, p: Paths, graceMs: number): Promise<void> {\n const pid = meta.pid;\n if (pidAlive(pid)) {\n const fc = new FirecrackerClient(p.machine(meta.name).sock);\n try {\n await fc.sendCtrlAltDel();\n } catch {\n process.kill(pid!, \"SIGTERM\");\n } finally {\n await fc.close();\n }\n if (!(await waitFor(() => !pidAlive(pid), graceMs, 100))) {\n try {\n process.kill(pid!, \"SIGKILL\");\n } catch {\n /* exited meanwhile */\n }\n await waitFor(() => !pidAlive(pid), 1000, 50);\n }\n }\n await deleteTap(meta.name, cfg);\n await rm(p.machine(meta.name).sock, { force: true });\n await rm(p.machine(meta.name).vsock, { force: true });\n}\n\nexport async function stopMachine(name: string, p: Paths = paths()): Promise<Machine> {\n const meta = await readMeta(name, p);\n const cfg = await loadConfig(p);\n if (!pidAlive(meta.pid)) throw new KvboxError(`box ${name} is already stopped`);\n await shutdown(meta, cfg, p, 10_000);\n // A stopped box boots from scratch next time, so its memory lineage (see state.ts memSnapshots) starts over.\n await rm(p.machine(name).memBase, { force: true });\n const stopped: MachineMeta = { ...meta, pid: null, memSnapshots: undefined };\n await writeMachineMeta(stopped, p);\n return toMachine(stopped, p);\n}\n\nexport async function startMachine(name: string, p: Paths = paths()): Promise<Machine> {\n const meta = await readMeta(name, p);\n const cfg = await loadConfig(p);\n if (pidAlive(meta.pid)) throw new KvboxError(`box ${name} is already running`);\n assertAssets(cfg);\n const pubkeyB64 = await readPubkeyB64(p);\n await ensureHostNetwork(cfg);\n const tap = await createTap(name, cfg);\n try {\n const pid = await launch(meta, tap, cfg, pubkeyB64, p);\n const started: MachineMeta = { ...meta, pid };\n await writeMachineMeta(started, p);\n return toMachine(started, p);\n } catch (err) {\n await deleteTap(name, cfg).catch(() => undefined);\n throw err;\n }\n}\n\n/**\n * Change a box's shape or base. Both only take effect at boot (Firecracker fixes vCPU and memory\n * when the VM starts, the base is stacked by overlay-init), so a running box is shut down and\n * started again; a stopped one just gets its meta updated. `whileStopped` runs in between, for\n * work that needs the disk unmounted. Returns the box, running again if it was.\n */\nasync function applyAtNextBoot(\n meta: MachineMeta,\n changes: Partial<MachineMeta>,\n cfg: Config,\n p: Paths,\n whileStopped?: () => Promise<void>,\n): Promise<Machine> {\n const wasRunning = pidAlive(meta.pid);\n if (wasRunning) {\n await shutdown(meta, cfg, p, 10_000);\n await rm(p.machine(meta.name).memBase, { force: true });\n }\n const updated: MachineMeta = { ...meta, ...changes, pid: null, memSnapshots: undefined };\n await writeMachineMeta(updated, p);\n if (whileStopped) await whileStopped();\n return wasRunning ? startMachine(meta.name, p) : toMachine(updated, p);\n}\n\n/** `kvbox update <box>`: move the box onto the base image new boxes get. Its overlay (its own writes) stays. */\nexport async function updateMachine(name: string, p: Paths = paths()): Promise<Machine> {\n const meta = await readMeta(name, p);\n const cfg = await loadConfig(p);\n if (meta.base === undefined) {\n throw new KvboxError(`box ${name} was made before overlays and runs on its own disk copy; it cannot be moved to another base image`);\n }\n assertAssets(cfg);\n const base = await currentBase(cfg, p);\n if (base.version === meta.base) return toMachine(meta, p);\n await assertOverlayCapable(base.file, base.version);\n return applyAtNextBoot(meta, { base: base.version }, cfg, p);\n}\n\n/**\n * `kvbox rescale <box>`: new vCPU count, memory and/or disk. The disk can only grow: the overlay\n * file is extended and its ext4 resized while the box is down (e2fsck first, resize2fs refuses\n * a filesystem that was mounted since its last check).\n */\nexport async function rescaleMachine(name: string, req: RescaleMachineRequest, p: Paths = paths()): Promise<Machine> {\n const meta = await readMeta(name, p);\n const cfg = await loadConfig(p);\n const disk = ownDisk(meta, p);\n const currentDiskGib = Math.round(statSync(disk).size / 1024 ** 3);\n const preset = req.size !== undefined && isSizeName(req.size) ? SIZES[req.size] : undefined;\n const target = {\n vcpu: req.vcpu ?? preset?.vcpu ?? meta.vcpu,\n memMib: req.memMib ?? preset?.memMib ?? meta.memMib,\n diskGib: req.diskGib ?? preset?.diskGib ?? currentDiskGib,\n };\n if (target.diskGib < currentDiskGib) {\n throw new KvboxError(`box ${name} has a ${currentDiskGib} GB disk and a disk cannot shrink; ${target.diskGib} GB is smaller`);\n }\n const changes: Partial<MachineMeta> = {};\n if (target.vcpu !== meta.vcpu) changes.vcpu = target.vcpu;\n if (target.memMib !== meta.memMib) changes.memMib = target.memMib;\n const growTo = target.diskGib > currentDiskGib ? target.diskGib : undefined;\n if (Object.keys(changes).length === 0 && growTo === undefined) return toMachine(meta, p);\n return applyAtNextBoot(meta, changes, cfg, p, growTo === undefined ? undefined : () => growDisk(disk, growTo));\n}\n\n/** Extend a box's (unmounted) ext4 disk file to `gib` GiB. */\nexport async function growDisk(file: string, gib: number): Promise<void> {\n await truncate(file, gib * 1024 ** 3);\n await run([\"e2fsck\", \"-f\", \"-p\", file], { okExitCodes: [1] });\n await run([\"resize2fs\", file]);\n}\n\nasync function readMeta(name: string, p: Paths): Promise<MachineMeta> {\n try {\n return await readMachineMeta(name, p);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") throw new NotFoundError(`box ${name}`);\n throw err;\n }\n}\n\nexport async function destroyMachine(name: string, p: Paths = paths()): Promise<void> {\n const meta = await readMeta(name, p);\n const cfg = await loadConfig(p);\n await shutdown(meta, cfg, p, 2000);\n await rm(p.machine(name).dir, { recursive: true, force: true });\n}\n","/**\n * Client for kvbox-agent, the small service every box runs (kvbox-images, /usr/local/sbin/kvbox-agent).\n * It listens on a vsock port, and Firecracker exposes that as a Unix socket next to the box's API\n * socket: connect, send `CONNECT <port>\\n`, get `OK <n>\\n` back once the guest accepted, then the\n * stream is the guest's. The agent speaks one JSON object per line, one request per connection.\n * Vsock does not touch the box's network, so this works whatever the box did to its own eth0.\n */\nimport { connect } from \"node:net\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\n\n/** The vsock port kvbox-agent listens on; fixed in the image. */\nexport const AGENT_PORT = 52;\n\nexport interface Identity {\n name: string;\n ip: string;\n prefixLen: number;\n gateway: string;\n mac: string;\n /** Unix seconds for the guest's clock, which stopped at the snapshot. */\n time: number;\n}\n\ntype AgentReply = { ok: true; [k: string]: unknown } | { ok: false; error: string };\n\n/** One request/reply exchange with the agent behind `udsPath`. Rejects on connection errors, timeout or `ok: false`. */\nexport async function agentCall(udsPath: string, req: Record<string, unknown>, timeoutMs = 5000): Promise<Record<string, unknown>> {\n const reply = await new Promise<string>((resolve, reject) => {\n const sock = connect(udsPath);\n let buf = \"\";\n let handshaken = false;\n const fail = (err: Error) => {\n sock.destroy();\n reject(err);\n };\n sock.setTimeout(timeoutMs, () => fail(new KvboxError(`kvbox-agent did not answer within ${timeoutMs} ms`)));\n sock.once(\"error\", (err) => fail(new KvboxError(`kvbox-agent unreachable: ${err.message}`)));\n sock.once(\"connect\", () => sock.write(`CONNECT ${AGENT_PORT}\\n`));\n sock.on(\"data\", (chunk) => {\n buf += chunk.toString(\"utf8\");\n let nl: number;\n while ((nl = buf.indexOf(\"\\n\")) !== -1) {\n const line = buf.slice(0, nl);\n buf = buf.slice(nl + 1);\n if (!handshaken) {\n if (!line.startsWith(\"OK \")) return fail(new KvboxError(`vsock connect refused: ${line}`));\n handshaken = true;\n sock.write(JSON.stringify(req) + \"\\n\");\n } else {\n sock.end();\n return resolve(line);\n }\n }\n });\n sock.once(\"close\", () => {\n if (!handshaken) fail(new KvboxError(\"vsock connection closed before the guest accepted\"));\n else fail(new KvboxError(\"kvbox-agent closed the connection without a reply\"));\n });\n });\n let parsed: AgentReply;\n try {\n parsed = JSON.parse(reply) as AgentReply;\n } catch {\n throw new KvboxError(`kvbox-agent sent something that is not JSON: ${reply}`);\n }\n if (!parsed.ok) throw new KvboxError(`kvbox-agent: ${parsed.error}`);\n return parsed;\n}\n\nexport function ping(udsPath: string, timeoutMs?: number) {\n return agentCall(udsPath, { op: \"ping\" }, timeoutMs);\n}\n\n/** Tell a restored box who it is now; it renames itself, re-addresses eth0 and sets its clock. */\nexport function setIdentity(udsPath: string, id: Identity, timeoutMs?: number) {\n return agentCall(udsPath, { op: \"identity\", ...id }, timeoutMs);\n}\n","/**\n * Client for one Firecracker process's API socket. Ten-odd endpoints, all\n * PUT/PATCH with JSON bodies, so a thin wrapper over undici beats an SDK.\n */\nimport { Agent, request } from \"undici\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\n\nexport class FirecrackerClient {\n private readonly agent: Agent;\n\n constructor(readonly socketPath: string) {\n this.agent = new Agent({ connect: { socketPath } });\n }\n\n private async call(method: \"GET\" | \"PUT\" | \"PATCH\", path: string, body?: unknown): Promise<unknown> {\n const res = await request(`http://localhost${path}`, {\n dispatcher: this.agent,\n method,\n headers: body === undefined ? {} : { \"content-type\": \"application/json\" },\n body: body === undefined ? null : JSON.stringify(body),\n });\n const text = await res.body.text();\n if (res.statusCode >= 300) {\n throw new KvboxError(`firecracker ${method} ${path} -> ${res.statusCode}: ${text}`);\n }\n return text ? JSON.parse(text) : undefined;\n }\n\n bootSource(kernelImagePath: string, bootArgs: string) {\n return this.call(\"PUT\", \"/boot-source\", { kernel_image_path: kernelImagePath, boot_args: bootArgs });\n }\n\n /**\n * /dev/vda. Firecracker adds `root=/dev/vda` plus `ro` or `rw` to the boot args to match.\n * Read-only for the shared base image; read-write only for pre-overlay boxes with their own copy.\n */\n rootDrive(pathOnHost: string, readOnly: boolean) {\n return this.drive(\"rootfs\", pathOnHost, { root: true, readOnly });\n }\n\n /** The box's own writable disk, /dev/vdb: the guest stacks it on the base as an overlay. */\n overlayDrive(pathOnHost: string) {\n return this.drive(\"overlay\", pathOnHost, { root: false, readOnly: false });\n }\n\n private drive(id: string, pathOnHost: string, opts: { root: boolean; readOnly: boolean }) {\n return this.call(\"PUT\", `/drives/${id}`, {\n drive_id: id,\n path_on_host: pathOnHost,\n is_root_device: opts.root,\n is_read_only: opts.readOnly,\n // \"Unsafe\" (the default) acks guest flushes without doing anything, so the last journal\n // commit of a clean shutdown can be lost when the guest resets and Firecracker exits.\n // Writeback makes a guest flush a real fsync; a box's writes must survive `kvbox stop`.\n cache_type: \"Writeback\",\n });\n }\n\n /** Swap the file behind a drive while the VM runs or is paused; the guest is told the config changed. */\n patchDrivePath(id: string, pathOnHost: string) {\n return this.call(\"PATCH\", `/drives/${id}`, { drive_id: id, path_on_host: pathOnHost });\n }\n\n /**\n * The host's control channel into the box: Firecracker listens on `udsPath`, a connection there\n * followed by `CONNECT <port>\\n` reaches whatever listens on that vsock port in the guest (kvbox-agent).\n */\n vsock(guestCid: number, udsPath: string) {\n return this.call(\"PUT\", \"/vsock\", { guest_cid: guestCid, uds_path: udsPath });\n }\n\n machineConfig(vcpuCount: number, memSizeMib: number) {\n // Dirty page tracking lets a snapshot write only the pages the guest touched since the last one\n // (a \"Diff\" snapshot) instead of dumping all of guest memory: sub-second instead of ~10 s frozen.\n return this.call(\"PUT\", \"/machine-config\", { vcpu_count: vcpuCount, mem_size_mib: memSizeMib, track_dirty_pages: true });\n }\n\n networkInterface(ifaceId: string, hostDevName: string, guestMac: string) {\n return this.call(\"PUT\", `/network-interfaces/${ifaceId}`, {\n iface_id: ifaceId,\n host_dev_name: hostDevName,\n guest_mac: guestMac,\n });\n }\n\n start() {\n return this.call(\"PUT\", \"/actions\", { action_type: \"InstanceStart\" });\n }\n\n /** Ask the guest to shut down cleanly (systemd handles Ctrl+Alt+Del as poweroff on Firecracker). */\n sendCtrlAltDel() {\n return this.call(\"PUT\", \"/actions\", { action_type: \"SendCtrlAltDel\" });\n }\n\n pause() {\n return this.call(\"PATCH\", \"/vm\", { state: \"Paused\" });\n }\n\n resume() {\n return this.call(\"PATCH\", \"/vm\", { state: \"Resumed\" });\n }\n\n /** `track_dirty_pages` is what matters: a box from an older server runs without it. */\n async machineConfigInfo(): Promise<{ vcpu_count: number; mem_size_mib: number; track_dirty_pages: boolean }> {\n return (await this.call(\"GET\", \"/machine-config\")) as { vcpu_count: number; mem_size_mib: number; track_dirty_pages: boolean };\n }\n\n /**\n * Full: all of guest memory, dense (seconds for a 4 GB box). Diff: only pages dirtied since the last\n * snapshot (or since boot), written sparse; needs dirty page tracking and resets its bitmap.\n */\n snapshotCreate(snapshotPath: string, memFilePath: string, type: \"Full\" | \"Diff\" = \"Full\") {\n return this.call(\"PUT\", \"/snapshot/create\", {\n snapshot_type: type,\n snapshot_path: snapshotPath,\n mem_file_path: memFilePath,\n });\n }\n\n /**\n * Restore a snapshot into this (fresh) process. The memory file is mapped privately: the guest's\n * writes never reach the snapshot. The vmstate carries the source box's tap and vsock paths; the\n * overrides point them at this box's. Drive paths are not overridable here: see patchDrivePath.\n */\n snapshotLoad(opts: {\n snapshotPath: string;\n memFilePath: string;\n tap: { ifaceId: string; hostDevName: string };\n vsockPath: string;\n /** Required for diff snapshots later: the flag is not part of the vmstate. */\n trackDirtyPages: boolean;\n resume: boolean;\n }) {\n return this.call(\"PUT\", \"/snapshot/load\", {\n snapshot_path: opts.snapshotPath,\n mem_backend: { backend_type: \"File\", backend_path: opts.memFilePath },\n network_overrides: [{ iface_id: opts.tap.ifaceId, host_dev_name: opts.tap.hostDevName }],\n vsock_override: { uds_path: opts.vsockPath },\n track_dirty_pages: opts.trackDirtyPages,\n resume_vm: opts.resume,\n });\n }\n\n info() {\n return this.call(\"GET\", \"/\");\n }\n\n async close() {\n await this.agent.close();\n }\n}\n","import { Hono } from \"hono\";\nimport { CreateSnapshotRequest } from \"@kvbox/shared/api\";\nimport { deleteSnapshot, listSnapshots, saveSnapshot } from \"../core/snapshots.js\";\n\nexport function snapshotRoutes() {\n const r = new Hono();\n r.get(\"/\", async (c) => c.json(await listSnapshots()));\n r.post(\"/\", async (c) => {\n const body = CreateSnapshotRequest.parse(await c.req.json());\n return c.json(await saveSnapshot(body), 201);\n });\n r.delete(\"/:name\", async (c) => {\n await deleteSnapshot(c.req.param(\"name\"));\n return c.body(null, 204);\n });\n return r;\n}\n","/**\n * Snapshots: a running box frozen into `snapshots/<name>/` as vmstate + mem (a complete memory image)\n * + a copy of the box's overlay. The base image is referenced by version, not copied, so a snapshot costs\n * what the guest touched (memory pages + overlay blocks), not the box's size.\n *\n * Memory is captured incrementally. Boxes run with dirty page tracking, so Firecracker can write only\n * the pages dirtied since the last snapshot (a \"Diff\": sub-second, sparse) instead of dumping all of\n * guest memory (~10 s frozen for 4 GB). A diff is only a complete image when merged onto the previous\n * one, so each box keeps `mem.base`, a hard link to its last snapshot's `mem`, and the merge happens\n * after the box is already running again. See state.ts `memSnapshots` for the bookkeeping.\n */\nimport { existsSync } from \"node:fs\";\nimport { link, mkdir, readdir, rename, rm, stat } from \"node:fs/promises\";\nimport { KvboxError, NotFoundError } from \"@kvbox/shared/errors\";\nimport type { CreateSnapshotRequest, Snapshot } from \"@kvbox/shared/api\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\nimport { loadConfig } from \"./config.js\";\nimport { run } from \"./exec.js\";\nimport { FirecrackerClient } from \"./firecracker.js\";\nimport {\n listSnapshotNames,\n pidAlive,\n readMachineMeta,\n readSnapshotMeta,\n writeMachineMeta,\n writeSnapshotMeta,\n type MachineMeta,\n type SnapshotMeta,\n} from \"./state.js\";\n\n/** Snapshot names are directory names shown in tables: letters, digits, dots, dashes, underscores. */\nconst NAME_RE = /^[a-z0-9][a-z0-9._-]{0,63}$/;\n\nfunction toSnapshot(meta: SnapshotMeta): Snapshot {\n return {\n name: meta.name,\n source: meta.source,\n base: meta.base,\n vcpu: meta.vcpu,\n memMib: meta.memMib,\n sizeBytes: meta.sizeBytes,\n createdAt: meta.createdAt,\n };\n}\n\nexport async function listSnapshots(p: Paths = paths()): Promise<Snapshot[]> {\n const out: Snapshot[] = [];\n for (const name of await listSnapshotNames(p)) {\n try {\n out.push(toSnapshot(await readSnapshotMeta(name, p)));\n } catch (err) {\n console.error(`warning: skipping snapshots/${name}: ${(err as Error).message}`);\n }\n }\n return out;\n}\n\n/** Bytes the snapshot really occupies: its files are sparse, so allocated blocks, not sizes. */\nasync function usedBytes(dir: string): Promise<number> {\n let total = 0;\n for (const entry of await readdir(dir)) {\n total += (await stat(`${dir}/${entry}`)).blocks * 512;\n }\n return total;\n}\n\nasync function readBox(name: string, p: Paths): Promise<MachineMeta> {\n try {\n return await readMachineMeta(name, p);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") throw new NotFoundError(`box ${name}`);\n throw err;\n }\n}\n\nexport async function saveSnapshot(req: CreateSnapshotRequest, p: Paths = paths()): Promise<Snapshot> {\n if (!NAME_RE.test(req.name)) {\n throw new KvboxError(`invalid snapshot name \"${req.name}\": 1-64 chars, lowercase letters, digits, '.', '_' and '-', starting with a letter or digit`);\n }\n const box = await readBox(req.box, p);\n if (box.base === undefined) {\n throw new KvboxError(`box ${req.box} was made before overlays and runs on its own disk copy; snapshots need a box made by this version of kvbox (kvbox new)`);\n }\n if (!pidAlive(box.pid)) {\n throw new KvboxError(`box ${req.box} is not running; a snapshot freezes a running box (kvbox start ${req.box} first)`);\n }\n const s = p.snapshot(req.name);\n if (existsSync(s.dir)) throw new KvboxError(`snapshot ${req.name} already exists`);\n const cfg = await loadConfig(p);\n const m = p.machine(box.name);\n\n await mkdir(s.dir, { recursive: true, mode: 0o700 });\n const fc = new FirecrackerClient(m.sock);\n let lineageTouched = false;\n try {\n const tracked = (await fc.machineConfigInfo()).track_dirty_pages;\n const since = box.memSnapshots ?? 0;\n // A diff is standalone right after boot, or once merged onto the previous image. Otherwise (a box\n // from an older server without tracking, or a lineage broken by an earlier failure) dump everything.\n const mode: \"Diff\" | \"Full\" = tracked && (since === 0 || existsSync(m.memBase)) ? \"Diff\" : \"Full\";\n\n // The guest is frozen for the whole capture so memory and overlay describe the same instant.\n let failure: unknown;\n await fc.pause();\n try {\n await fc.snapshotCreate(s.vmstate, s.mem, mode);\n lineageTouched = tracked; // Firecracker reset its dirty bitmap: the box's next diff is relative to this image\n await run([\"cp\", \"--sparse=always\", \"--reflink=auto\", m.overlay, s.overlay]);\n } catch (err) {\n failure = err;\n } finally {\n await fc.resume();\n }\n if (lineageTouched) {\n // Recorded before anything else can fail: memSnapshots > 0 without mem.base reads as a broken\n // lineage, and the next snapshot falls back to a full dump instead of a diff missing pages.\n await writeMachineMeta({ ...box, memSnapshots: since + 1 }, p);\n }\n if (failure !== undefined) throw failure;\n\n if (mode === \"Full\") {\n // A full dump is dense; pages the guest never touched are zeros, so punch them out.\n await run([\"fallocate\", \"--dig-holes\", s.mem]);\n } else if (since > 0) {\n await mergeOntoPrevious(m.memBase, s.mem, cfg.snapshotEditor ?? p.snapshotEditor);\n }\n if (tracked) {\n await rm(m.memBase, { force: true });\n await link(s.mem, m.memBase);\n }\n\n const meta: SnapshotMeta = {\n name: req.name,\n source: box.name,\n base: box.base,\n vcpu: box.vcpu,\n memMib: box.memMib,\n sizeBytes: await usedBytes(s.dir),\n createdAt: new Date().toISOString(),\n };\n await writeSnapshotMeta(meta, p);\n return toSnapshot(meta);\n } catch (err) {\n // The diff that was just discarded took pages with it: never let the next diff build on the old image.\n if (lineageTouched) await rm(m.memBase, { force: true }).catch(() => undefined);\n await rm(s.dir, { recursive: true, force: true });\n throw err;\n } finally {\n await fc.close();\n }\n}\n\n/**\n * Turn the diff at `diffFile` into a complete image: copy the previous image and apply the diff's pages\n * over it. Holes in the diff are untouched pages; a page dirtied to zeros is data and overwrites.\n */\nasync function mergeOntoPrevious(previous: string, diffFile: string, editor: string): Promise<void> {\n if (!existsSync(editor)) throw new KvboxError(`snapshot-editor missing at ${editor}; rerun install-server.sh`);\n const merged = `${diffFile}.merged`;\n await run([\"cp\", \"--sparse=always\", \"--reflink=auto\", previous, merged]);\n await run([editor, \"edit-memory\", \"rebase\", \"--memory-path\", merged, \"--diff-path\", diffFile]);\n await rename(merged, diffFile);\n}\n\nexport async function deleteSnapshot(name: string, p: Paths = paths()): Promise<void> {\n if (!existsSync(p.snapshot(name).dir)) throw new NotFoundError(`snapshot ${name}`);\n await rm(p.snapshot(name).dir, { recursive: true, force: true });\n}\n"],"mappings":"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","names":["rm","writeFile","readFile","writeFile","z","z","readFile","writeFile","Hono","require","Hono","z","z","existsSync","mkdir","readFile","writeFile","bootArgs","existsSync","writeFile","readFile","m","mkdir","Hono","Hono","existsSync","link","mkdir","readdir","rm","NAME_RE","readdir","existsSync","mkdir","rm","link","Hono","Hono","rm","writeFile","shutdown"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghalex/kvbox-server",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "kvbox host daemon: owns Firecracker microVMs on a Linux host and serves the kvbox API. Managed with the @ghalex/kvbox CLI.",
5
5
  "type": "module",
6
6
  "license": "MIT",