Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
# lifecycle
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module owns the idempotency wrapper around a `VmSandboxHandle`'s
`start` / `dispose` lifecycle. The host's lifecycle driver may invoke
these hooks multiple times (e.g. a hot-reload's stop+start pair, or a
test harness's deterministic shutdown sequence); the wrapper makes the
double-invocation case a silent no-op rather than a throw, and
reflects under-the-hood sandbox throws via the bridge's
`LIFECYCLE_FAILED` code so the host's error boundary sees a uniform
shape.
Splitting the wrapper into its own module keeps the bridge factory
small (no inline state machine) and gives the conformance harness a
direct seam for asserting idempotency without standing up the full
bridge.
## Features
- Idempotent `start` — second call returns without re-invoking
`sandbox.start()`.
- Idempotent `dispose` — second call returns without re-invoking
`sandbox.dispose()`.
- Forbidden start-after-dispose — calling `start()` after `dispose()`
raises `LIFECYCLE_FAILED` so the host can fail the hot-reload
cleanly rather than silently swallowing the request.
- Error wrapping — underlying sandbox throws surface as
`SandboxVmBridgeError` with `code: LIFECYCLE_FAILED` and the
original error preserved as `cause`.
- Inspection helpers — `hasStarted()` and `isDisposed()` for the
bridge's internal request-pipeline guard.
## Usage: Basic
```ts
import { createSandboxLifecycleForwarder } from "@suaveplan/api-sandbox-vm-host-bridge/lifecycle/lifecycle";
const forwarder = createSandboxLifecycleForwarder(sandbox);
await forwarder.start();
forwarder.dispose();
forwarder.dispose(); // no-op
```
## Usage: Advanced
```ts
import { createSandboxLifecycleForwarder } from "@suaveplan/api-sandbox-vm-host-bridge/lifecycle/lifecycle";
const forwarder = createSandboxLifecycleForwarder(sandbox);
try {
await forwarder.start();
} catch (err) {
// err.code === "SAND_VM_BRIDGE.LIFECYCLE_FAILED"
// err.cause is the original SandboxVmError
rollbackJournal.markFailed(err);
}
```
## API Reference
- `interface SandboxLifecycleForwarder` — `start()`, `dispose()`,
`hasStarted()`, `isDisposed()`.
- `createSandboxLifecycleForwarder(sandbox: VmSandboxHandle):
SandboxLifecycleForwarder` — factory; returns a frozen object.
## Implementation Notes
The internal `started` / `disposed` flags are kept in a closure rather
than on the returned object so the sandbox cannot mutate them via a
property-set on the forwarder. The forwarder itself is `Object.freeze`d
so consumers cannot patch `dispose` to skip the cleanup. Errors raised
inside `dispose()` are caught and rewrapped — the alternative (letting
them propagate raw) would mean the host's error boundary sees a mixed
shape (sometimes `SandboxVmError`, sometimes
`SandboxVmBridgeError`); the wrap keeps the boundary's branch arm
tight.