Skip to content

LocalSandboxProvider

A local sandbox provider keeps each sandbox in a directory on this machine and runs its processes as this machine’s processes. Nothing is isolated: a sandbox’s processes can read and write the whole machine and see its environment variables, so it suits development, tests, and agents you would trust on this machine anyway.

Each sandbox is a directory under the provider’s directory, named by its id, that holds its settings, the ports it exposes, in sandbox.json and the sandbox’s files in workspace, its working directory. Processes start in the working directory and resolve a relative cwd against it. File paths are this machine’s paths.

stop and destroy end the processes the provider started for the sandbox, through any Sandbox value for it, including those that outlived their scopes. A provider made again, as when the host restarts, does not know of processes an earlier one left running.

Since v0.1.0

The provider over options.directory, which it creates if it is missing.

Details

It needs Effect’s FileSystem, Path, Crypto, and ChildProcessSpawner services for this machine, as BunServices.layer or NodeServices.layer provide them.

Example (A provider for one piece of work, over a temporary directory)

import { LocalSandboxProvider } from "@amends-dev/sandbox-local"
import { BunServices } from "@effect/platform-bun"
import { Effect, FileSystem } from "effect"
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
const sandboxProvider = yield* LocalSandboxProvider.make({
directory: yield* fs.makeTempDirectoryScoped()
})
const sandbox = yield* sandboxProvider.createScoped()
return sandbox.workingDirectory
}).pipe(Effect.scoped, Effect.provide(BunServices.layer))

Signature

declare const make: (
options: Options
) => Effect.Effect<
{
readonly create: <E = never>(
options?: SandboxProvider.CreateOptions<E>
) => Effect.Effect<Sandbox.Sandbox["Service"], SandboxError.SandboxError | E>
readonly createScoped: <E = never>(
options?: SandboxProvider.CreateOptions<E>
) => Effect.Effect<Sandbox.Sandbox["Service"], SandboxError.SandboxError | E, Scope.Scope>
readonly resume: (id: Sandbox.SandboxId) => Effect.Effect<Sandbox.Sandbox["Service"], SandboxError.SandboxError>
},
PlatformError.PlatformError,
FileSystem.FileSystem | ChildProcessSpawner.ChildProcessSpawner | Path.Path | Crypto.Crypto
>

Source

Since v0.1.0

Provides the SandboxProvider service over options.directory, as make makes it, to a program that keeps its sandboxes on this machine.

Example (Sandboxes under a directory of the host’s)

import { SandboxProvider } from "@amends-dev/sandbox"
import { LocalSandboxProvider } from "@amends-dev/sandbox-local"
import { BunServices } from "@effect/platform-bun"
import { Effect, Layer } from "effect"
const sandboxes = LocalSandboxProvider.layer({ directory: "/var/lib/amends/sandboxes" }).pipe(
Layer.provide(BunServices.layer)
)
const program = Effect.gen(function* () {
const sandboxProvider = yield* SandboxProvider.SandboxProvider
const sandbox = yield* sandboxProvider.create()
return sandbox.id
}).pipe(Effect.provide(sandboxes))

Signature

declare const layer: (
options: Options
) => Layer.Layer<
SandboxProvider.SandboxProvider,
PlatformError.PlatformError,
FileSystem.FileSystem | ChildProcessSpawner.ChildProcessSpawner | Path.Path | Crypto.Crypto
>

Source

Since v0.1.0

Where the provider keeps its sandboxes.

Signature

export interface Options {
/** The directory that holds one directory per sandbox, created if it is missing. */
readonly directory: string
}

Source

Since v0.1.0