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,113 @@
# bridge
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module is the package's flagship factory:
`createSandboxedVmPluginModule({ sandbox, manifest, registry })` →
`BridgedPlugin` — a frozen object whose `module` is a
`PluginModule`-shaped lifecycle bundle and whose `routes` is a
materialised `PipelineRoute[]` ready to hand to
`host.installPlugin({ module, manifest, routes, ... })`.
The factory drives the underlying sandbox's `start()` through the
idempotent lifecycle forwarder, asserts the sandbox registered at
least one route via the `bridge.registerRoute` capability, and wraps
every registered handler in a marshal-invoke-unmarshal closure so the
host's request pipeline can dispatch into the sandboxed plugin as if
it were a regular trusted plugin.
## Features
- Lifecycle delegation — `module.start()`, `module.stop()`,
`module.uninstall()` thread through the lifecycle forwarder so the
host's lifecycle driver sees consistent idempotent semantics.
- Route materialisation — every sandbox registration becomes a frozen
`PipelineRoute` with the plugin id, method (already upper-cased),
path, options (defaulted, overridable), wrapped handler, empty
params, and forwarded status map.
- Marshal closure per route — host `Request` → `SerializedRequest` →
sandbox handler → `SerializedResponse` → host `Response`.
- Empty-registry guard — sandboxes that registered no routes raise
`INVALID_PLUGIN_SURFACE` so the host never mounts an empty plugin.
- OTel attribution — each step (marshal, handler invocation,
unmarshal) increments the relevant counter on the bridge's OTel
bundle.
- Cause-chain preservation — sandbox throws surface as
`HANDLER_REJECTED` with the original error preserved as `cause`.
## Usage: Basic
```ts
import { createSandboxedVmPluginModule, createBridgeRouteRegistry }
from "@suaveplan/api-sandbox-vm-host-bridge";
import { createVmSandbox } from "@suaveplan/api-sandbox-vm";
const registry = createBridgeRouteRegistry();
const sandbox = createVmSandbox({
pluginId: "demo",
pluginModule: { kind: "source", identifier: "demo.mjs", source },
checker,
proxies: { fs, fetch, capabilities: { bridge: registry.capability } },
logger,
});
const bridged = await createSandboxedVmPluginModule({
sandbox,
manifest,
registry,
});
await host.installPlugin({
module: bridged.module,
manifest,
manifestHash,
specifier,
routes: bridged.routes,
});
```
## Usage: Advanced
Supply per-route option overrides keyed by `"METHOD /path"`:
```ts
const bridged = await createSandboxedVmPluginModule({
sandbox,
manifest,
registry,
routeOptions: {
"POST /upload": { streaming: true, auth: "tenant.write" },
"GET /healthz": { auth: null, csrf: false },
},
statusMap: { 200: 201 },
});
```
## API Reference
- `interface BridgedPluginModule<Caps>` — frozen lifecycle bundle.
- `interface BridgedPlugin<Caps>` — `module`, `routes`, `dispose`,
`lifecycle`.
- `interface CreateSandboxedVmPluginModuleOptions` — `sandbox`,
`manifest`, `registry`, `routeOptions?`, `statusMap?`.
- `createSandboxedVmPluginModule<Caps>(options):
Promise<BridgedPlugin<Caps>>` — async factory; runs
`lifecycle.start()` synchronously before returning.
## Implementation Notes
The factory deliberately freezes both the returned `BridgedPlugin` and
its nested `module` / `routes` so the host's lifecycle driver cannot
patch a route's handler after install. The wrapped handler captures
the OTel duration histogram across the whole marshal-invoke-unmarshal
cycle — this surfaces back-pressure under load as a single metric the
operator can alert on without instrumenting each sub-step
individually.
The `requires` generic on `BridgedPluginModule` is allowed to be empty
because the bridge owns the only capability the sandbox needs (`bridge`);
plugins that declare other capability requirements (db, secrets) thread
those through the sandbox via the host's existing capability map — the
bridge itself is unaware of them.