defineSandbox({ backend }) (#13) takes a SandboxBackendFactory — (context: { workDir, ports }) => SandboxProvider — and the Docker backend supplies one as docker({ image }). The three backends added in #12 supply none, so they are only reachable through their create*Sandbox constructors and cannot be named in a definition.
The adaptation is three lines for Docker and is not mechanical for any of these, which is why #12 left it out rather than deciding it inside a merge:
- microsandbox takes
ports as a ReadonlyMap<number, number> — guest to host, both sides explicit, and portEndpoint refuses a port the map does not carry. A factory receives readonly number[]. Mapping each port to itself is the obvious reading and is still a decision: it gives up the ability to publish a guest port on a different host port, which is the reason the map is explicit on both sides.
- just-bash publishes no ports at all —
portEndpoint throws JustBashPortsUnavailableError, because there is no host process to listen on one. resolveSandbox rejects an empty ports array on the grounds that a bridged harness is reached over a published port. So a justBash() factory would either have to accept ports it cannot honour, or the definition layer needs a way to say "this backend hosts no bridge" — which is a question about defineSandbox, not about the backend.
- local runs host processes on the caller's own machine with no isolation, so
workDir from a placement means something different here than it does for a container: it is a real directory on the caller's filesystem, under a root the backend owns. Whether a placement's workDir should be honoured verbatim or resolved beneath that root is the decision.
Each of these is a small API question with a defensible answer; none of them should be settled as a side effect of landing the backends.
defineSandbox({ backend })(#13) takes aSandboxBackendFactory—(context: { workDir, ports }) => SandboxProvider— and the Docker backend supplies one asdocker({ image }). The three backends added in #12 supply none, so they are only reachable through theircreate*Sandboxconstructors and cannot be named in a definition.The adaptation is three lines for Docker and is not mechanical for any of these, which is why #12 left it out rather than deciding it inside a merge:
portsas aReadonlyMap<number, number>— guest to host, both sides explicit, andportEndpointrefuses a port the map does not carry. A factory receivesreadonly number[]. Mapping each port to itself is the obvious reading and is still a decision: it gives up the ability to publish a guest port on a different host port, which is the reason the map is explicit on both sides.portEndpointthrowsJustBashPortsUnavailableError, because there is no host process to listen on one.resolveSandboxrejects an emptyportsarray on the grounds that a bridged harness is reached over a published port. So ajustBash()factory would either have to accept ports it cannot honour, or the definition layer needs a way to say "this backend hosts no bridge" — which is a question aboutdefineSandbox, not about the backend.workDirfrom a placement means something different here than it does for a container: it is a real directory on the caller's filesystem, under a root the backend owns. Whether a placement'sworkDirshould be honoured verbatim or resolved beneath that root is the decision.Each of these is a small API question with a defensible answer; none of them should be settled as a side effect of landing the backends.