From 0e6384b3ee116649a2439d36e1dc9d530be56a76 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Fri, 1 May 2026 17:50:21 +0000 Subject: [PATCH] fix(docs): remove outdated base image bundle readme and consolidate hosted manifest documentation --- assets/base-images/readme.md | 34 -- changelog.md | 6 + readme.md | 830 +++++++++++++++++++---------------- ts/00_commitinfo_data.ts | 2 +- 4 files changed, 464 insertions(+), 408 deletions(-) delete mode 100644 assets/base-images/readme.md diff --git a/assets/base-images/readme.md b/assets/base-images/readme.md deleted file mode 100644 index 469b2c5..0000000 --- a/assets/base-images/readme.md +++ /dev/null @@ -1,34 +0,0 @@ -# SmartVM Base Image Bundles - -This directory documents the project-owned base image manifest format. The actual kernel and rootfs binaries should be hosted as release assets or in object storage, not committed to git. - -## Bundle Layout - -A hosted bundle should expose three files: - -```text -smartvm-minimal-v1-x86_64.manifest.json -vmlinux -rootfs.ext4 -``` - -The manifest is the only file shape `smartvm` needs to know. It points at the hosted kernel and rootfs artifacts and records checksums. - -## Manifest Fields - -- `schemaVersion`: currently `1` -- `bundleId`: stable cache key, using letters, numbers, dot, underscore, and dash only -- `arch`: `x86_64` or `aarch64` -- `firecrackerVersion`: Firecracker version validated with this bundle -- `rootfsType`: `ext4` or `squashfs` -- `rootfsIsReadOnly`: use `true` for squashfs or immutable rootfs images -- `bootArgs`: kernel boot args to use with the bundle -- `kernel`: hosted kernel artifact URL/path plus `sha256` for URL artifacts and optional `sizeBytes` -- `rootfs`: hosted rootfs artifact URL/path plus `sha256` for URL artifacts and optional `sizeBytes` -- `fileName`: optional plain output filename; path separators are rejected - -`sha256` is required for hosted URL artifacts. `sizeBytes` is optional but helps catch incomplete downloads. - -## Cache Behavior - -Downloaded bundles are cached under `/tmp/.smartvm/base-images` by default. The cache keeps two bundles unless `maxStoredBaseImages` is configured. Eviction is announced with `console.warn`. diff --git a/changelog.md b/changelog.md index 4ae45ec..4d63835 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,11 @@ # Changelog +## 2026-05-01 - 1.3.1 - fix(docs) +remove outdated base image bundle readme and consolidate hosted manifest documentation + +- Deletes the dedicated assets/base-images/readme.md documentation file +- Keeps hosted base image manifest guidance and example usage in the main project README + ## 2026-05-01 - 1.3.0 - feat(runtime) stage VM runtime artifacts and writable drives in per-VM ephemeral storage by default diff --git a/readme.md b/readme.md index 5607d32..9ffefbd 100644 --- a/readme.md +++ b/readme.md @@ -1,190 +1,341 @@ # @push.rocks/smartvm -A TypeScript module that wraps Amazon's [Firecracker VMM](https://firecracker-microvm.github.io/) to create, configure, and manage lightweight microVMs with a clean, type-safe API. +Run Firecracker microVMs from TypeScript without hand-rolling process management, Unix-socket HTTP calls, TAP devices, bridge setup, image caching, and cleanup. `@push.rocks/smartvm` gives you a typed orchestration layer for building tiny, fast, disk-light VM workflows on Linux/KVM. ## Issue Reporting and Security For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly. +## What It Does + +`smartvm` wraps the operational parts of Amazon Firecracker: + +- Downloads and caches Firecracker binaries. +- Resolves bootable Firecracker CI base-image bundles with `latest` and `lts` presets. +- Supports project-owned hosted base-image manifests with SHA256 verification. +- Creates and controls microVMs through Firecracker's HTTP-over-Unix-socket API. +- Converts TypeScript camelCase config into Firecracker's snake_case payloads. +- Creates TAP devices, a Linux bridge, static guest IP assignments, and NAT rules. +- Defaults VM runtime artifacts to tmpfs via `/dev/shm/.smartvm/runtime` when available. +- Stages writable drives into per-VM ephemeral storage by default so guest writes do not touch cached rootfs files. +- Cleans up Firecracker processes, sockets, TAPs, bridges, NAT rules, and staged drive copies. + +The design goal is close to a Cloudflare Workers/Deno-style filesystem model, adapted to Firecracker: immutable root image, explicit writable scratch, no accidental persistent state, and persistence only when you opt in. + ## Install ```bash -pnpm install @push.rocks/smartvm +pnpm add @push.rocks/smartvm ``` -> โšก **Prerequisites**: Firecracker requires a Linux host with KVM support (`/dev/kvm`). Networking features (TAP devices, bridges, NAT) require root privileges. +## Runtime Requirements -Runtime host requirements: +Firecracker is a Linux/KVM technology. The package is TypeScript, but the runtime host must provide the VM substrate. -- Linux with `/dev/kvm` available to the running process -- A Firecracker binary downloaded by `ensureBinary()` or supplied through `firecrackerBinaryPath` -- Root privileges for automatic bridge, TAP, IP forwarding, and iptables NAT setup -- Host tools available for networking: `ip`, `sysctl`, and `iptables` -- IPv4 CIDR subnets with prefix length `1-30`; the bridge uses the first usable address as gateway and guests start at the second usable address +| Requirement | Why it matters | +|---|---| +| Linux with `/dev/kvm` | Firecracker needs KVM acceleration. | +| Firecracker binary | Downloaded by `ensureBinary()` or supplied through `firecrackerBinaryPath`. | +| Root privileges for networking | TAP devices, bridges, IP forwarding, and iptables NAT require elevated privileges. | +| Host tools: `curl`, `tar`, `ip`, `sysctl`, `iptables` | Used for binary/image downloads and network setup. | +| Enough tmpfs memory | Writable VM drives are copied into `/dev/shm` by default when available. | ## Quick Start +This is the happy path: let `smartvm` download Firecracker, resolve a known-good base image, boot it, and clean it up. + ```typescript import { SmartVM } from '@push.rocks/smartvm'; -// 1. Create the orchestrator const smartvm = new SmartVM({ - dataDir: '/opt/smartvm', // where binaries, kernels, rootfs are cached - firecrackerVersion: 'v1.7.0', // or omit for latest - arch: 'x86_64', + // Optional. Defaults are intentionally disk-light. + dataDir: '/tmp/.smartvm', + runtimeDir: '/dev/shm/.smartvm/runtime', }); -// 2. Download Firecracker if not already present -await smartvm.ensureBinary(); +const baseImage = await smartvm.ensureBaseImage({ preset: 'latest' }); -// 3. Create a MicroVM const vm = await smartvm.createVM({ + id: 'hello-firecracker', bootSource: { - kernelImagePath: '/opt/smartvm/kernels/vmlinux', - bootArgs: 'console=ttyS0 reboot=k panic=1 pci=off', + kernelImagePath: baseImage.kernelImagePath, + bootArgs: baseImage.bootArgs, }, machineConfig: { - vcpuCount: 2, + vcpuCount: 1, memSizeMib: 256, }, drives: [ { driveId: 'rootfs', - pathOnHost: '/opt/smartvm/rootfs/ubuntu.ext4', + pathOnHost: baseImage.rootfsPath, isRootDevice: true, - isReadOnly: false, + isReadOnly: baseImage.rootfsIsReadOnly, }, ], - networkInterfaces: [ - { ifaceId: 'eth0' }, // TAP device and MAC auto-generated - ], }); -// 4. Start it ๐Ÿš€ -await vm.start(); - -// 5. Inspect -console.log(vm.state); // 'running' -console.log(await vm.getInfo()); // Firecracker instance info - -// 6. Pause / Resume -await vm.pause(); // state โ†’ 'paused' -await vm.resume(); // state โ†’ 'running' - -// 7. Stop and clean up -await vm.stop(); -await vm.cleanup(); -await smartvm.cleanup(); +try { + await vm.start(); + console.log(vm.state); // "running" + console.log(await vm.getVersion()); + console.log(await vm.getInfo()); +} finally { + if (vm.state === 'running' || vm.state === 'paused') { + await vm.stop(); + } + await vm.cleanup(); + await smartvm.cleanup(); +} ``` -## Architecture Overview +## Disk-Light Runtime Model -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ SmartVM โ”‚ โ† Top-level orchestrator -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ ImageManager โ”‚ โ”‚ NetworkManager โ”‚ โ”‚ -โ”‚ โ”‚ (binaries, โ”‚ โ”‚ (TAP, bridge, โ”‚ โ”‚ -โ”‚ โ”‚ kernels, โ”‚ โ”‚ NAT, IP alloc) โ”‚ โ”‚ -โ”‚ โ”‚ rootfs) โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ MicroVM โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ state: created โ†’ configuring โ†’ โ”‚ โ”‚ -โ”‚ โ”‚ running โ†’ paused โ†’ stopped โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ FirecrackerProcess โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ (child process management) โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ -โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ SocketClient โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ (HTTP over Unix socket) โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ -โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ VMConfig โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ (camelCase โ†’ snake_case) โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +By default, `smartvm` treats VMs as ephemeral execution units. + +| Path | Default | Persistence model | +|---|---|---| +| Firecracker binaries | `/tmp/.smartvm/bin` | Cached for reuse. | +| Base images | `/tmp/.smartvm/base-images` | Cached, retention-limited, verified before reuse. | +| VM sockets | `/dev/shm/.smartvm/runtime//firecracker.sock` | Per-VM tmpfs, deleted on cleanup. | +| Writable drives | `/dev/shm/.smartvm/runtime//drives/*` | Per-VM tmpfs copy, deleted on cleanup. | +| Read-only drives | Original path | Not copied unless `ephemeral: true`. | + +Writable drives are staged into the VM runtime directory before boot. Firecracker receives the staged path, so guest writes do not modify cached base images or source rootfs files. + +```typescript +const vm = await smartvm.createVM({ + bootSource: { kernelImagePath: baseImage.kernelImagePath, bootArgs: baseImage.bootArgs }, + machineConfig: { vcpuCount: 1, memSizeMib: 256 }, + drives: [ + { + driveId: 'rootfs', + pathOnHost: baseImage.rootfsPath, + isRootDevice: true, + isReadOnly: false, + // Default for writable drives: true + ephemeral: true, + }, + ], +}); ``` -Firecracker exposes a REST API over a Unix domain socket. This module handles all the plumbing: spawning the process, waiting for the socket, translating your TypeScript config into Firecracker's snake_case API payloads, managing TAP devices, and tearing everything down on exit. +Opt into persistence only when that is the point: -## API Reference +```typescript +const persistentVm = await smartvm.createVM({ + bootSource: { kernelImagePath: '/images/vmlinux', bootArgs: 'console=ttyS0 reboot=k panic=1 pci=off' }, + machineConfig: { vcpuCount: 2, memSizeMib: 512 }, + drives: [ + { + driveId: 'state', + pathOnHost: '/var/lib/my-vm/state.ext4', + isRootDevice: true, + isReadOnly: false, + ephemeral: false, + }, + ], +}); +``` -### `SmartVM` โ€” The Orchestrator +You can also disable writable-drive staging globally: -The entry point for everything. Manages binary downloads, VM creation, and global cleanup. +```typescript +const smartvm = new SmartVM({ + ephemeralWritableDrives: false, +}); +``` + +Best practice for high-volume VM starts: + +- Prefer `squashfs` or another read-only root filesystem. +- Put mutable scratch data on tmpfs-backed writable drives. +- Keep shared assets read-only by default. +- Use external services, object storage, databases, or explicit persistent drives for durable state. +- Use a dedicated `runtimeDir` on a real tmpfs if `/dev/shm` is too small or unavailable. + +## Architecture + +```text +SmartVM + ImageManager downloads/caches Firecracker binaries and manual images + BaseImageManager resolves known-good base-image bundles + NetworkManager creates TAP devices, bridge, NAT, and static guest network data + MicroVM + FirecrackerProcess starts/stops the VMM process + SocketClient talks HTTP over the Firecracker Unix socket + VMConfig validates and transforms TypeScript config +``` + +Firecracker exposes a REST API over a Unix domain socket. `smartvm` starts the child process, waits for readiness, sends pre-boot config in the right order, starts the instance, and tears down host resources when you are done. + +## SmartVM + +`SmartVM` is the top-level orchestrator. ```typescript import { SmartVM } from '@push.rocks/smartvm'; import type { ISmartVMOptions } from '@push.rocks/smartvm'; -const smartvm = new SmartVM({ - dataDir: '/tmp/.smartvm', // default: /tmp/.smartvm - firecrackerVersion: 'v1.7.0', // default: latest from GitHub - arch: 'x86_64', // default: x86_64 (also: aarch64) - firecrackerBinaryPath: '/usr/bin/firecracker', // optional: skip download - baseImageCacheDir: '/tmp/.smartvm/base-images', // default: /tmp/.smartvm/base-images - maxStoredBaseImages: 2, // default: keep at most 2 cached base image bundles - bridgeName: 'svbr0', // default: svbr0 - subnet: '172.30.0.0/24', // default: 172.30.0.0/24 -}); +const options: ISmartVMOptions = { + dataDir: '/tmp/.smartvm', + runtimeDir: '/dev/shm/.smartvm/runtime', + ephemeralWritableDrives: true, + firecrackerVersion: 'v1.7.0', + arch: 'x86_64', + firecrackerBinaryPath: '/usr/bin/firecracker', + bridgeName: 'svbr0', + subnet: '172.30.0.0/24', + baseImageCacheDir: '/tmp/.smartvm/base-images', + maxStoredBaseImages: 2, + baseImageManifestUrl: 'https://assets.example.com/smartvm/manifest.json', + baseImageManifestPath: './assets/base-images/local.manifest.json', +}; + +const smartvm = new SmartVM(options); ``` -| Method | Description | +| API | Description | |---|---| -| `ensureBinary()` | Downloads Firecracker from GitHub if not cached. Returns path to binary. | -| `ensureBaseImage(options)` | Downloads/caches a Firecracker CI base image bundle. Defaults to the `latest` preset. | -| `createVM(config)` | Creates a `MicroVM` instance (not yet started). Returns the VM. | -| `getVM(id)` | Look up an active VM by ID. | -| `listVMs()` | Returns an array of active VM IDs. | -| `vmCount` | Number of active VMs. | -| `stopAll()` | Stops all running/paused VMs in parallel. | -| `cleanup()` | Stops all VMs, removes TAP devices and bridge. | +| `ensureBinary()` | Ensures the Firecracker binary exists and returns its path. | +| `ensureBaseImage(options)` | Resolves/downloads a base-image bundle and returns kernel/rootfs paths plus boot args. | +| `createVM(config)` | Creates a `MicroVM` instance. It does not boot until `vm.start()`. | +| `getRuntimeDir()` | Returns the active runtime directory used for per-VM tmpfs artifacts. | +| `getVM(id)` | Looks up an active VM by ID. | +| `listVMs()` | Lists active VM IDs. | +| `vmCount` | Number of tracked VMs. | +| `removeVM(id)` | Removes a VM from the internal tracking map. | +| `stopAll()` | Stops every running or paused VM. | +| `cleanup()` | Cleans up all tracked VMs and networking resources. | -### `MicroVM` โ€” VM Lifecycle +## Base Images -Each VM follows a strict state machine: **created โ†’ configuring โ†’ running โ†’ paused โ†’ stopped**. +`BaseImageManager` gives you fast bootable image discovery without committing giant rootfs files to git. + +```typescript +const baseImage = await smartvm.ensureBaseImage(); // preset: "latest" +const ltsBaseImage = await smartvm.ensureBaseImage({ preset: 'lts' }); +const freshBaseImage = await smartvm.ensureBaseImage({ preset: 'latest', forceDownload: true }); +``` + +Presets: + +| Preset | Behavior | +|---|---| +| `latest` | Resolves the latest Firecracker release and matching CI demo artifacts. | +| `lts` | Uses the pinned Firecracker CI train `v1.7` / Firecracker `v1.7.0`. | +| `hosted` | Uses a project-owned manifest. Requires `manifestUrl`, `manifestPath`, or manager-level hosted manifest options. | + +The resolver prefers read-only `squashfs` rootfs artifacts when Firecracker CI exposes them, falling back to `ext4` when needed. + +```typescript +import { BaseImageManager } from '@push.rocks/smartvm'; + +const baseImageManager = new BaseImageManager({ + arch: 'x86_64', + cacheDir: '/tmp/.smartvm/base-images', + maxStoredBaseImages: 4, + hostedManifestPath: './assets/base-images/smartvm-minimal.manifest.json', +}); + +console.log(baseImageManager.getCacheDir()); +console.log(baseImageManager.getMaxStoredBaseImages()); + +const hosted = await baseImageManager.ensureBaseImage({ preset: 'hosted' }); +const evictedBundleIds = await baseImageManager.pruneBaseImageCache(hosted.bundleId); +``` + +`IBaseImageBundle` contains: + +- `kernelImagePath` +- `rootfsPath` +- `rootfsType` +- `rootfsIsReadOnly` +- `bootArgs` +- `firecrackerVersion` +- `checksums` +- `sizes` +- source metadata + +Cache behavior: + +- Default cache directory: `/tmp/.smartvm/base-images` +- Default retention: `2` bundles +- Older bundles are evicted with a `console.warn` when retention is exceeded +- Cached artifacts are checked for size and SHA256 before reuse +- Hosted URL artifacts require SHA256 hashes +- Hosted local-path artifacts may omit SHA256, but hashes are still recorded in the cached manifest + +Hosted manifest example: + +The repository ships an example at `assets/base-images/smartvm-minimal.manifest.example.json`. + +```json +{ + "schemaVersion": 1, + "bundleId": "smartvm-minimal-v1-x86_64", + "name": "SmartVM minimal x86_64 bundle", + "arch": "x86_64", + "firecrackerVersion": "v1.15.1", + "rootfsType": "squashfs", + "rootfsIsReadOnly": true, + "bootArgs": "console=ttyS0 reboot=k panic=1 pci=off ro rootfstype=squashfs", + "kernel": { + "url": "https://assets.example.com/smartvm/vmlinux", + "fileName": "vmlinux", + "sha256": "0000000000000000000000000000000000000000000000000000000000000000", + "sizeBytes": 12345678 + }, + "rootfs": { + "url": "https://assets.example.com/smartvm/rootfs.squashfs", + "fileName": "rootfs.squashfs", + "sha256": "0000000000000000000000000000000000000000000000000000000000000000", + "sizeBytes": 12345678 + } +} +``` + +## MicroVM Lifecycle + +`MicroVM` is a single Firecracker instance with a strict state machine: + +```text +created -> configuring -> running -> paused -> stopped + \-> error +``` ```typescript const vm = await smartvm.createVM({ - id: 'my-vm', // optional, auto-generated UUID if omitted + id: 'api-worker-1', bootSource: { - kernelImagePath: '/path/to/vmlinux', - bootArgs: 'console=ttyS0 reboot=k panic=1', - initrdPath: '/path/to/initrd', // optional + kernelImagePath: baseImage.kernelImagePath, + bootArgs: baseImage.bootArgs, }, machineConfig: { - vcpuCount: 4, + vcpuCount: 2, memSizeMib: 512, smt: false, - cpuTemplate: 'T2', // optional: C3, T2, T2S, T2CL, T2A, V1N1 + cpuTemplate: 'T2', trackDirtyPages: true, }, drives: [ { driveId: 'rootfs', - pathOnHost: '/path/to/rootfs.ext4', + pathOnHost: baseImage.rootfsPath, isRootDevice: true, - isReadOnly: false, - cacheType: 'Unsafe', // or 'Writeback' + isReadOnly: baseImage.rootfsIsReadOnly, + cacheType: 'Unsafe', + ephemeral: true, rateLimiter: { bandwidth: { size: 100_000_000, refillTime: 1_000_000_000 }, ops: { size: 1000, refillTime: 1_000_000_000 }, }, }, ], - networkInterfaces: [ - { - ifaceId: 'eth0', - // hostDevName and guestMac auto-generated if omitted - }, - ], + networkInterfaces: [{ ifaceId: 'eth0' }], vsock: { guestCid: 3, - udsPath: '/tmp/vsock.sock', + udsPath: '/dev/shm/api-worker-1.vsock', }, balloon: { amountMib: 128, @@ -195,290 +346,184 @@ const vm = await smartvm.createVM({ version: 'V2', networkInterfaces: ['eth0'], }, - logger: { - logPath: '/tmp/firecracker.log', - level: 'Debug', - showLogOrigin: true, - }, - metrics: { - metricsPath: '/tmp/firecracker-metrics.fifo', - }, }); + +await vm.start(); +await vm.pause(); +await vm.resume(); +await vm.stop(); +await vm.cleanup(); ``` -| Method | Valid States | Description | +| API | Valid state | Description | |---|---|---| -| `start()` | `created` | Spawns Firecracker, applies config, boots the VM | -| `pause()` | `running` | Pauses VM execution | -| `resume()` | `paused` | Resumes a paused VM | -| `stop()` | `running`, `paused` | Graceful shutdown (Ctrl+Alt+Del), then force kill | -| `cleanup()` | any | Full cleanup: kill process, remove socket, remove TAPs | -| `getInfo()` | any (after start) | Returns Firecracker instance info | -| `getVersion()` | any (after start) | Returns Firecracker version | -| `createSnapshot(params)` | `paused` | Create a VM snapshot | -| `loadSnapshot(params)` | `created`, `configuring` | Load a VM from snapshot | -| `setMetadata(data)` | `running`, `paused` | Set MMDS metadata | -| `getMetadata()` | `running`, `paused` | Get MMDS metadata | -| `updateDrive(id, path)` | `running`, `paused` | Hot-update a drive path | -| `updateBalloon(mib)` | `running`, `paused` | Resize the balloon device | -| `getTapDevices()` | any | Returns TAP devices associated with this VM | +| `start()` | `created` | Stages ephemeral drives, starts Firecracker, applies config, boots the VM. | +| `pause()` | `running` | Pauses execution. | +| `resume()` | `paused` | Resumes execution. | +| `stop()` | `running`, `paused` | Sends Ctrl+Alt+Del, waits briefly, then stops the process. | +| `cleanup()` | any | Stops process, deletes sockets/runtime dir, removes auto-created TAPs. | +| `getInfo()` | after start | Returns Firecracker instance info. | +| `getVersion()` | after start | Returns Firecracker version info. | +| `setMetadata(data)` | `running`, `paused` | Writes MMDS metadata. | +| `getMetadata()` | `running`, `paused` | Reads MMDS metadata. | +| `updateDrive(id, path)` | `running`, `paused` | Hot-updates a drive path. | +| `updateNetworkInterface(id, update)` | `running`, `paused` | Updates network interface config such as rate limiters. | +| `updateBalloon(mib)` | `running`, `paused` | Resizes the balloon device. | +| `createSnapshot(params)` | `paused` | Creates a Firecracker snapshot. | +| `loadSnapshot(params)` | `created`, `configuring` | Low-level Firecracker snapshot-load call; requires an initialized socket client. | +| `getTapDevices()` | any | Returns TAP devices created automatically by this VM. | +| `getVMConfig()` | any | Returns the internal `VMConfig` instance. | +| `getRuntimeDir()` | any | Returns the per-VM runtime directory after it has been created. | -### `ImageManager` โ€” Binary & Image Management +Snapshot caveat: diff snapshots require dirty-page tracking to be enabled before boot through `machineConfig.trackDirtyPages`. Snapshot restore is currently exposed as a low-level API; full restore orchestration should be built around the Firecracker process/config lifecycle intentionally. -Handles downloading and caching Firecracker binaries, kernels, and rootfs images. +## Networking + +`NetworkManager` creates host-side networking primitives. It does not run DHCP inside the guest. Your guest image must configure its interface itself, or you must pass static `ip=` kernel boot arguments. + +Automatic mode: ```typescript -const imageManager = smartvm.imageManager; - -// Auto-download the latest Firecracker release -const version = await imageManager.getLatestVersion(); // e.g. 'v1.7.0' -const binaryPath = await imageManager.downloadFirecracker(version); - -// Download kernel and rootfs images -const kernelPath = await imageManager.downloadKernel( - 'https://example.com/vmlinux-5.10', - 'vmlinux-5.10', -); -const rootfsPath = await imageManager.downloadRootfs( - 'https://example.com/ubuntu-22.04.ext4', - 'ubuntu-22.04.ext4', -); - -// Create a blank rootfs or clone an existing one -const blankPath = await imageManager.createBlankRootfs('scratch.ext4', 1024); -const clonePath = await imageManager.cloneRootfs(rootfsPath, 'ubuntu-clone.ext4'); -``` - -**Data directory layout:** - -``` -/tmp/.smartvm/ - bin//firecracker - bin//jailer - kernels/ - rootfs/ - -/dev/shm/.smartvm/runtime// - firecracker.sock - drives/- -``` - -Runtime files default to `/dev/shm/.smartvm/runtime` on Linux when available, so sockets and per-VM writable drive copies live on tmpfs and are removed during cleanup. Set `runtimeDir` to override this. - -**Ephemeral drives:** - -- Writable drives are copied into the per-VM runtime directory before boot by default -- Firecracker receives the staged tmpfs path, so guest writes do not modify cached/base rootfs files -- Per-VM staged drive files are deleted by `vm.cleanup()` / `smartvm.cleanup()` -- Read-only drives are not copied unless `ephemeral: true` is set on the drive -- Set `ephemeral: false` on a drive, or `ephemeralWritableDrives: false` on `SmartVM`, only when persistence is explicitly required - -### `BaseImageManager` โ€” Base Images - -Downloads known base image bundles into a `/tmp` cache for integration tests and quick local smoke tests. The default preset is `latest`; `lts` maps to a pinned Firecracker CI train (`v1.7`) for a stable fallback. Hosted project-owned manifests are also supported for pinned Alpine/BusyBox-style bundles. - -```typescript -const baseImage = await smartvm.ensureBaseImage(); // same as { preset: 'latest' } - -const ltsBaseImage = await smartvm.ensureBaseImage({ preset: 'lts' }); - -const hostedBaseImage = await smartvm.ensureBaseImage({ - manifestUrl: 'https://assets.example.com/push.rocks/smartvm/base-images/smartvm-minimal-v1/x86_64/manifest.json', +const vm = await smartvm.createVM({ + bootSource: { kernelImagePath: baseImage.kernelImagePath, bootArgs: baseImage.bootArgs }, + machineConfig: { vcpuCount: 1, memSizeMib: 256 }, + drives: [{ driveId: 'rootfs', pathOnHost: baseImage.rootfsPath, isRootDevice: true, isReadOnly: baseImage.rootfsIsReadOnly }], + networkInterfaces: [{ ifaceId: 'eth0' }], }); +``` + +Static-kernel-args mode: + +```typescript +const tap = await smartvm.networkManager.createTapDevice('net-vm', 'eth0'); const vm = await smartvm.createVM({ + id: 'net-vm', bootSource: { kernelImagePath: baseImage.kernelImagePath, - bootArgs: baseImage.bootArgs, + bootArgs: `${baseImage.bootArgs} ${smartvm.networkManager.getGuestNetworkBootArgs(tap)}`, }, machineConfig: { vcpuCount: 1, memSizeMib: 256 }, - drives: [ + drives: [{ driveId: 'rootfs', pathOnHost: baseImage.rootfsPath, isRootDevice: true, isReadOnly: baseImage.rootfsIsReadOnly }], + networkInterfaces: [ { - driveId: 'rootfs', - pathOnHost: baseImage.rootfsPath, - isRootDevice: true, - isReadOnly: baseImage.rootfsIsReadOnly, + ifaceId: 'eth0', + hostDevName: tap.tapName, + guestMac: tap.mac, }, ], }); ``` -**Cache behavior:** +Networking behavior: -- Default cache directory: `/tmp/.smartvm/base-images` -- Default retention: at most `2` base image bundles -- Configure retention with `maxStoredBaseImages` -- Configure location with `baseImageCacheDir` -- When a new download causes the retention limit to be exceeded, older bundles are removed and a console warning is emitted -- Downloaded bundles include a local `manifest.json` with source URLs/keys, file paths, sizes, and computed SHA256 hashes +- Default bridge: `svbr0` +- Default subnet: `172.30.0.0/24` +- Subnet input is normalized to the network address +- Prefix length must be `1-30` +- Gateway uses the first usable address +- Guest IP allocation starts at the second usable address +- Allocation is sequential and not reused within the same `NetworkManager` instance +- MAC addresses are deterministic and locally administered (`02:xx:xx:xx:xx:xx`) +- TAP names are capped to Linux's 15-character IFNAMSIZ limit +- NAT masquerade uses the host default route interface +- Use a dedicated bridge name; `cleanup()` tears down the bridge configured by this manager -Example configuration: +## ImageManager + +`ImageManager` is the lower-level helper for Firecracker binaries and manually managed kernel/rootfs files. ```typescript -const smartvm = new SmartVM({ - baseImageCacheDir: '/tmp/.smartvm/base-images', - runtimeDir: '/dev/shm/.smartvm/runtime', - maxStoredBaseImages: 4, - baseImageManifestUrl: 'https://assets.example.com/push.rocks/smartvm/base-images/smartvm-minimal-v1/x86_64/manifest.json', -}); +const imageManager = smartvm.imageManager; + +await imageManager.ensureDirectories(); + +const latest = await imageManager.getLatestVersion(); +const firecrackerPath = await imageManager.downloadFirecracker(latest); + +const kernelPath = await imageManager.downloadKernel( + 'https://example.com/vmlinux', + 'vmlinux', +); + +const rootfsPath = await imageManager.downloadRootfs( + 'https://example.com/rootfs.ext4', + 'rootfs.ext4', +); + +const blankRootfs = await imageManager.createBlankRootfs('scratch.ext4', 1024); +const clonedRootfs = await imageManager.cloneRootfs(rootfsPath, 'vm-rootfs.ext4'); ``` -Hosted manifest format examples live in `assets/base-images/`. Hosted URL artifacts require SHA256 hashes; `smartvm` verifies them during download before returning the bundle paths. +Useful path helpers: -### `NetworkManager` โ€” Host Networking +- `getBinDir()` +- `getKernelsDir()` +- `getRootfsDir()` +- `getSocketsDir()` +- `getFirecrackerPath(version)` +- `getJailerPath(version)` +- `getSocketPath(vmId)` -Automatically manages TAP devices, a Linux bridge, and iptables NAT masquerade rules so VMs get internet access out of the box. +Note: `SmartVM.createVM()` uses `runtimeDir//firecracker.sock` for new VM sockets by default. `ImageManager.getSocketPath()` remains available for lower-level/custom flows. -```typescript -const networkManager = smartvm.networkManager; +## VMConfig -// Manually create a TAP device (usually handled by MicroVM.start()) -const tap = await networkManager.createTapDevice('vm-id', 'eth0'); -console.log(tap); -// { -// tapName: 'svvmideth0', -// guestIp: '172.30.0.2', -// gatewayIp: '172.30.0.1', -// subnetMask: '255.255.255.0', -// mac: '02:a3:b1:c4:d2:e5' -// } - -// Generate kernel boot args for the guest -const bootArgs = networkManager.getGuestNetworkBootArgs(tap); -// 'ip=172.30.0.2::172.30.0.1:255.255.255.0::eth0:off' -``` - -**Networking architecture:** -- Creates a Linux bridge (default: `svbr0`) with gateway at the first usable subnet address -- Each VM gets a TAP device attached to the bridge -- Sequential IP allocation from the second usable subnet address onwards -- Subnet input is normalized to the network address and allocation fails with `IP_EXHAUSTED` when no guest addresses remain -- iptables NAT masquerade for outbound internet -- Deterministic MAC generation (`02:xx:xx:xx:xx:xx` locally-administered) -- TAP names fit Linux's 15-char IFNAMSIZ limit - -### `VMConfig` โ€” Config Transformer - -Converts your camelCase TypeScript config into Firecracker's snake_case API payloads. Also validates configuration before boot. +`VMConfig` validates `IMicroVMConfig` and transforms it into Firecracker API payloads. ```typescript import { VMConfig } from '@push.rocks/smartvm'; const vmConfig = new VMConfig({ - bootSource: { kernelImagePath: '/path/to/vmlinux' }, + bootSource: { kernelImagePath: '/images/vmlinux', bootArgs: 'console=ttyS0 reboot=k panic=1 pci=off' }, machineConfig: { vcpuCount: 2, memSizeMib: 256 }, + drives: [{ driveId: 'rootfs', pathOnHost: '/images/rootfs.ext4', isRootDevice: true }], }); -// Validate -const result = vmConfig.validate(); -// { valid: true, errors: [] } +const validation = vmConfig.validate(); +if (!validation.valid) { + throw new Error(validation.errors.join('; ')); +} -// Generate API payloads -vmConfig.toBootSourcePayload(); -// { kernel_image_path: '/path/to/vmlinux' } - -vmConfig.toMachineConfigPayload(); -// { vcpu_count: 2, mem_size_mib: 256 } +console.log(vmConfig.toBootSourcePayload()); +console.log(vmConfig.toMachineConfigPayload()); +console.log(vmConfig.toDrivePayload(vmConfig.config.drives![0])); ``` -### `SocketClient` โ€” Low-Level HTTP Client +The constructor clones caller-provided config, so internal normalization does not mutate your original object. -Direct HTTP-over-Unix-socket communication with Firecracker. You typically don't need this directly โ€” `MicroVM` handles it โ€” but it's available if you want raw API access. +## SocketClient + +`SocketClient` is the raw Firecracker API client. Most users should go through `MicroVM`, but the low-level client is exported for tooling and diagnostics. ```typescript import { SocketClient } from '@push.rocks/smartvm'; -const client = new SocketClient({ socketPath: '/tmp/firecracker.sock' }); +const client = new SocketClient({ socketPath: '/dev/shm/.smartvm/runtime/vm/firecracker.sock' }); -const info = await client.get('/'); -const putResult = await client.put('/machine-config', { vcpu_count: 2, mem_size_mib: 256 }); -const patchResult = await client.patch('/vm', { state: 'Paused' }); +const version = await client.get('/version'); +const machineConfig = await client.put('/machine-config', { + vcpu_count: 1, + mem_size_mib: 256, +}); +const paused = await client.patch('/vm', { state: 'Paused' }); -// Check if socket is alive (polls with timeout) -const ready = await client.isReady(5000); +console.log(version.ok, version.statusCode, version.body); +console.log(machineConfig.ok, machineConfig.statusCode, machineConfig.body); +console.log(paused.ok, paused.statusCode, paused.body); ``` -### `SmartVMError` โ€” Error Handling +`SocketClient` returns `{ ok, statusCode, body }`. Non-2xx responses do not become `API_ERROR` until higher-level `MicroVM` helpers validate them. -All errors thrown by this module are `SmartVMError` instances with structured error codes. +## Metadata Service -```typescript -import { SmartVMError } from '@push.rocks/smartvm'; - -try { - await vm.start(); -} catch (err) { - if (err instanceof SmartVMError) { - console.log(err.code); // 'INVALID_CONFIG', 'SOCKET_TIMEOUT', 'API_ERROR', etc. - console.log(err.statusCode); // HTTP status from Firecracker (if applicable) - console.log(err.details); // Raw error body from Firecracker (if applicable) - } -} -``` - -**Error codes:** - -| Code | Description | -|---|---| -| `INVALID_STATE` | Operation not valid for current VM state | -| `INVALID_CONFIG` | Config validation failed | -| `SOCKET_TIMEOUT` | Firecracker socket didn't become ready | -| `API_TIMEOUT` | Firecracker API didn't respond in time | -| `SOCKET_REQUEST_FAILED` | HTTP request to socket failed | -| `API_ERROR` | Firecracker returned a non-2xx response | -| `BINARY_NOT_FOUND` | Firecracker binary not at expected path | -| `DOWNLOAD_FAILED` | Failed to download binary/kernel/rootfs | -| `VERSION_FETCH_FAILED` | Couldn't query GitHub for latest version | -| `BASE_IMAGE_RESOLVE_FAILED` | Failed to resolve Firecracker CI base image artifacts | -| `BASE_IMAGE_MANIFEST_FAILED` | Failed to load or use a hosted base image manifest | -| `BASE_IMAGE_PREPARE_FAILED` | Failed to download or prepare a base image bundle | -| `INVALID_BASE_IMAGE_MANIFEST` | Hosted base image manifest is invalid | -| `INVALID_BASE_IMAGE_CACHE_LIMIT` | Base image cache retention limit is invalid | -| `INVALID_SUBNET` | Subnet is not a supported IPv4 CIDR range | -| `INVALID_INTERFACE_NAME` | Bridge or TAP interface name is invalid | -| `IP_EXHAUSTED` | No guest IP addresses remain in the configured subnet | -| `BRIDGE_SETUP_FAILED` | Failed to create network bridge | -| `TAP_CREATE_FAILED` | Failed to create TAP device | -| `ROOTFS_CREATE_FAILED` | Failed to create blank rootfs | -| `ROOTFS_CLONE_FAILED` | Failed to clone rootfs image | -| `START_FAILED` | VM start sequence failed | -| `NO_CLIENT` | Socket client not initialized | - -## Snapshots - -Create and restore VM snapshots for fast cold-start or live migration: - -```typescript -// Pause first (required for snapshots) -await vm.pause(); - -// Create a snapshot -await vm.createSnapshot({ - snapshotPath: '/tmp/snapshot.bin', - memFilePath: '/tmp/snapshot-mem.bin', - snapshotType: 'Full', // or 'Diff' for incremental -}); - -// Later: restore from snapshot -const freshVm = await smartvm.createVM({ - bootSource: { kernelImagePath: '/path/to/vmlinux' }, - machineConfig: { vcpuCount: 2, memSizeMib: 256 }, -}); -await freshVm.loadSnapshot({ - snapshotPath: '/tmp/snapshot.bin', - memFilePath: '/tmp/snapshot-mem.bin', - resumeVm: true, -}); -``` - -## MMDS (Metadata Service) - -Pass metadata to your guest VM via Firecracker's Microvm Metadata Service: +Firecracker MMDS lets the host pass structured metadata to a running VM. ```typescript const vm = await smartvm.createVM({ - bootSource: { /* ... */ }, - machineConfig: { /* ... */ }, + bootSource: { kernelImagePath: baseImage.kernelImagePath, bootArgs: baseImage.bootArgs }, + machineConfig: { vcpuCount: 1, memSizeMib: 256 }, + drives: [{ driveId: 'rootfs', pathOnHost: baseImage.rootfsPath, isRootDevice: true, isReadOnly: baseImage.rootfsIsReadOnly }], networkInterfaces: [{ ifaceId: 'eth0' }], mmds: { version: 'V2', @@ -488,70 +533,109 @@ const vm = await smartvm.createVM({ await vm.start(); -// Set metadata from host await vm.setMetadata({ - instance: { id: 'my-instance', region: 'eu-central-1' }, - secrets: { apiKey: 'sk-...' }, + instance: { id: 'api-worker-1', region: 'local' }, + config: { mode: 'ephemeral' }, }); -// Guest can access via: curl http://169.254.169.254/latest/meta-data/ -const data = await vm.getMetadata(); +console.log(await vm.getMetadata()); ``` -## Graceful Cleanup +## Error Handling -The module registers cleanup handlers via `@push.rocks/smartexit` so resources are released even if your process crashes: - -- ๐Ÿ”Œ Firecracker child processes are killed -- ๐Ÿงน Unix socket files are removed -- ๐ŸŒ TAP devices are deleted -- ๐ŸŒ‰ Bridge and NAT rules are torn down - -You can also trigger cleanup manually: +All package-level failures use `SmartVMError` with structured codes. ```typescript -// Stop one VM -await vm.stop(); -await vm.cleanup(); +import { SmartVMError } from '@push.rocks/smartvm'; -// Stop all VMs and clean everything -await smartvm.stopAll(); -await smartvm.cleanup(); +try { + await vm.start(); +} catch (err) { + if (err instanceof SmartVMError) { + console.error(err.code); + console.error(err.statusCode); + console.error(err.details); + } + throw err; +} ``` +| Code | Meaning | +|---|---| +| `INVALID_STATE` | Operation is invalid for the current VM state. | +| `INVALID_CONFIG` | VM configuration failed validation. | +| `SOCKET_TIMEOUT` | Firecracker did not create its socket in time. | +| `API_TIMEOUT` | Firecracker API readiness check timed out. | +| `SOCKET_REQUEST_FAILED` | Unix-socket HTTP request failed. | +| `API_ERROR` | Firecracker returned a non-2xx response through a high-level VM call. | +| `BINARY_NOT_FOUND` | Custom Firecracker binary path does not exist. | +| `DOWNLOAD_FAILED` | Binary, kernel, or rootfs download failed. | +| `VERSION_FETCH_FAILED` | Latest Firecracker version lookup failed. | +| `BASE_IMAGE_RESOLVE_FAILED` | Firecracker CI base-image artifact resolution failed. | +| `BASE_IMAGE_MANIFEST_FAILED` | Hosted manifest could not be loaded or used. | +| `BASE_IMAGE_PREPARE_FAILED` | Base-image download/copy/verification failed. | +| `INVALID_BASE_IMAGE_MANIFEST` | Hosted manifest schema or artifact metadata is invalid. | +| `INVALID_BASE_IMAGE_CACHE_LIMIT` | Base-image retention limit is invalid. | +| `INVALID_SUBNET` | Subnet is not a supported IPv4 CIDR. | +| `INVALID_INTERFACE_NAME` | Bridge or TAP name is invalid. | +| `IP_EXHAUSTED` | No guest IPs remain in the configured subnet. | +| `BRIDGE_SETUP_FAILED` | Bridge/NAT setup failed. | +| `TAP_CREATE_FAILED` | TAP creation failed. | +| `ROOTFS_CREATE_FAILED` | Blank rootfs creation failed. | +| `ROOTFS_CLONE_FAILED` | Rootfs clone failed. | +| `START_FAILED` | VM start sequence failed. | +| `NO_CLIENT` | Socket client is not initialized. | + ## Testing -The default test suite is unit-level and safe to run without KVM or root privileges: +Default tests are safe on machines without KVM or root privileges: ```bash pnpm test pnpm run build ``` -These tests cover config validation, Firecracker payload generation, lifecycle guard errors, VM tracking, and subnet/IP allocation. They do not boot a real microVM. +The default suite covers config validation, payload generation, lifecycle guards, base-image cache behavior, hosted manifest validation, VM tracking, ephemeral drive staging, and subnet/IP behavior. -Real Firecracker boot testing should be run on a Linux/KVM host with the runtime requirements above. At minimum, verify `ensureBinary()`, `createVM()`, `start()`, `getInfo()`, `stop()`, and `cleanup()` against a known-good kernel and rootfs image before relying on a new host setup. - -An opt-in integration test scaffold is included and skipped by default: +Opt into real Firecracker boot tests on a Linux/KVM host: ```bash SMARTVM_RUN_INTEGRATION=true pnpm test ``` +Accepted truthy values for `SMARTVM_RUN_INTEGRATION`: `1`, `true`, `yes`. + Useful integration-test environment variables: -- `SMARTVM_BASE_IMAGE_PRESET`: `latest` or `lts` (default: `latest`) -- `SMARTVM_BASE_IMAGE_MANIFEST_URL`: use a hosted/project-owned base image manifest instead of a preset -- `SMARTVM_BASE_IMAGE_MANIFEST_PATH`: use a local base image manifest instead of a preset -- `SMARTVM_BASE_IMAGE_CACHE_DIR`: override `/tmp/.smartvm/base-images` -- `SMARTVM_MAX_STORED_BASE_IMAGES`: override the default retention limit of `2` -- `SMARTVM_FIRECRACKER_VERSION`: override the Firecracker binary version; otherwise the base image's recommended version is used -- `SMARTVM_ARCH`: `x86_64` or `aarch64`; defaults from the host architecture -- `SMARTVM_INTEGRATION_DATA_DIR`: override the Firecracker binary/socket data directory +| Variable | Purpose | +|---|---| +| `SMARTVM_BASE_IMAGE_PRESET` | `latest` or `lts`; default is `latest`. | +| `SMARTVM_BASE_IMAGE_MANIFEST_URL` | Hosted/project-owned base-image manifest URL. | +| `SMARTVM_BASE_IMAGE_MANIFEST_PATH` | Local hosted manifest path. | +| `SMARTVM_BASE_IMAGE_CACHE_DIR` | Override `/tmp/.smartvm/base-images`. | +| `SMARTVM_MAX_STORED_BASE_IMAGES` | Override default retention of `2`. | +| `SMARTVM_FIRECRACKER_VERSION` | Override the Firecracker binary version. | +| `SMARTVM_ARCH` | `x86_64` or `aarch64`; defaults from host architecture. | +| `SMARTVM_INTEGRATION_DATA_DIR` | Override the Firecracker binary data directory used by integration tests. | -## TypeScript Interfaces +## TypeScript Surface -All configuration interfaces are fully exported for type-safe usage: +Main exports: + +```typescript +export { + SmartVM, + MicroVM, + NetworkManager, + FirecrackerProcess, + BaseImageManager, + ImageManager, + SocketClient, + VMConfig, +}; +``` + +Important exported types: ```typescript import type { @@ -603,7 +687,7 @@ Use of these trademarks must comply with Task Venture Capital GmbH's Trademark G ### Company Information -Task Venture Capital GmbH +Task Venture Capital GmbH Registered at District Court Bremen HRB 35230 HB, Germany For any legal inquiries or further information, please contact us via email at hello@task.vc. diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 67bd3ee..953d0e9 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@push.rocks/smartvm', - version: '1.3.0', + version: '1.3.1', description: 'A TypeScript module wrapping Amazon Firecracker VMM for managing lightweight microVMs' }