Skip to content

Boat.Sandbox reference

Source: packages/boat/src/ConnectSandbox.ts

Work with one Sandbox declared in the stack, from a Worker, Function or any other host: run commands, read and write files, call its ports, stop, resume or snapshot it. The handle has the same operations as the sandboxes CreateSandbox returns, except fork and delete; its sandboxId is an Effect, read at runtime.

A declared sandbox stops after its autoStop. Calls into it then fail with SandboxNotRunning until you resume() it.

The host gets its own Boat API key, minted at deploy and revoked when the host is destroyed. The key reaches only this sandbox.

ConnectSandbox: Running commands in a dev box

Section titled “ConnectSandbox: Running commands in a dev box”
const devBox = yield* Boat.ConnectSandbox(DevBox);
return {
fetch: Effect.gen(function* () {
yield* devBox.resume({ autoStop: "10 minutes" });
const test = yield* devBox.exec("git pull && npm test", { cwd: "/home/user/repo" });
return yield* HttpServerResponse.json(test);
}),
};

ConnectSandbox: Calling a program in the sandbox

Section titled “ConnectSandbox: Calling a program in the sandbox”

Call port 3000

const port = yield* devBox.getTcpPort(3000);
const response = yield* port.fetch(HttpClientRequest.get("/health"));

Proxy the Worker’s request to port 3000

const port = yield* devBox.getTcpPort(3000);
return yield* port.fetch(yield* HttpServerRequest);
yield* devBox.stop();

Source: packages/boat/src/ConnectSandboxHttp.ts Kind: Layer · Provides: Boat.ConnectSandbox

HTTP implementation of ConnectSandbox: Boat’s REST API with a key that reaches only the bound sandbox. Works on any host.

Effect.gen(function* () {
const devBox = yield* Boat.ConnectSandbox(DevBox);
// ...
}).pipe(Effect.provide(Boat.ConnectSandboxHttp))

Source: packages/boat/src/CreateSandbox.ts

Create and manage Boat sandboxes from a Worker, Function or any other host.

Boat.CreateSandbox(snapshot) creates sandboxes from a snapshot declared in the stack; Boat.CreateSandbox() creates them from scratch, or from the from each call passes. Both return the same client, whose calls take Boat’s own parameters.

Sandboxes created at run time are labelled with the stack, stage and host (alchemy.stack, alchemy.stage, alchemy.id) and are not deleted when the stack is destroyed. List them by those labels to clean them up: sandboxes.list({ labels: { "alchemy.stack": "my-app", "alchemy.stage": "prod" } }). Labels you pass to create merge underneath; they never replace the alchemy.* ones.

The host gets its own Boat API key, minted at deploy and revoked when the host is destroyed. It may create sandboxes and work in them, and delete only the sandboxes it created; it can’t touch the account’s other sandboxes, environments, keys or billing.

One sandbox per request, deleted when the request ends

const sandboxes = yield* Boat.CreateSandbox();
// in fetch:
const sandbox = yield* Effect.acquireRelease(
sandboxes.create({ type: "small", noEnv: true, autoStop: "10 minutes" }),
(sandbox) => Effect.ignore(sandbox.delete()),
);
const result = yield* sandbox.exec("node --version");

From a snapshot declared in the stack

const sandboxes = yield* Boat.CreateSandbox(Golden);
const sandbox = yield* sandboxes.create();

A long-lived sandbox per task, found by label

const [existing] = yield* sandboxes.list({ labels: { task } });
const sandbox = existing
? yield* sandboxes.connect(existing.id)
: yield* sandboxes.create({ labels: { task }, autoStop: "30 minutes" });

exec runs to completion and returns { exitCode, stdout, stderr }; a non-zero exit is returned, not failed. A string runs in a shell, an array runs its arguments quoted.

A shell line, an argument vector, stdin and a timeout

const test = yield* sandbox.exec("npm test", { cwd: "/home/user/app" });
const version = yield* sandbox.exec(["node", "--version"]);
const sorted = yield* sandbox.exec("sort", { stdin: "b\na\n" });
const slow = yield* sandbox.exec("make", { timeout: "2 minutes" }); // Boat.ExecTimedOut

Start a server in the background and stream its output

const server = yield* sandbox.start("npm run dev", { cwd: "/home/user/app" });
yield* server.output.pipe(
Stream.take(5),
Stream.runForEach((chunk) => Effect.log(new TextDecoder().decode(chunk.data))),
);
const port = yield* sandbox.getTcpPort(3000);
return yield* port.fetch(yield* HttpServerRequest);
yield* sandbox.stop(); // stopping snapshots it
const copy = yield* sandbox.fork({ autoStop: "10 minutes" });
yield* sandbox.resume();

Source: packages/boat/src/CreateSandboxHttp.ts Kind: Layer · Provides: Boat.CreateSandbox

HTTP implementation of CreateSandbox: Boat’s REST API with the host’s own key. Works on any host.

Effect.gen(function* () {
const sandboxes = yield* Boat.CreateSandbox();
// ...
}).pipe(Effect.provide(Boat.CreateSandboxHttp))