Initial Commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user