Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
# @suaveplan/api-worker-rpc - MessagePort-based RPC protocol for worker-isolated API plugins. Provides Zod-validated wire frames, monotonic correlation ids, AbortSignal forwarding, streaming with backpressure, structured-clone safety guards, SuaveplanError reconstruction across the boundary, and paired client/server bindings. Universal; Stage-3 worker-proxy packages depend on this.
|
||||
|
||||
MessagePort-based RPC protocol for worker-isolated API plugins. Provides
|
||||
the shared protocol — Zod-validated wire frames, monotonic correlation
|
||||
ids, AbortSignal forwarding, streaming with backpressure, structured-
|
||||
clone safety guards, SuaveplanError reconstruction across the boundary,
|
||||
and paired client/server bindings — that every Stage-3 worker-proxy
|
||||
package builds on.
|
||||
|
||||
The package is universal: it depends only on a structural
|
||||
`PortLike` shape that matches both Node/Bun's `worker_threads`
|
||||
`MessagePort` and the Web platform's `MessagePort`. No platform
|
||||
globals are imported at module load.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [abort-forwarding](./src/abort-forwarding/abort-forwarding.md) — Wires caller-side `AbortSignal` instances across the `MessagePort` boundary so an in-flight RPC can be cancelled cooper…
|
||||
- [abort-forwarding](./src/abort-forwarding/abort-forwarding.md) — Wires caller-side `AbortSignal` instances across the `MessagePort` boundary so an in-flight RPC can be cancelled cooper…
|
||||
- [backpressure](./src/backpressure/backpressure.md) — Bounds memory growth on a busy RPC channel by exposing two primitives: the logical `CallBudget` for outstanding in-flig…
|
||||
- [backpressure](./src/backpressure/backpressure.md) — Bounds memory growth on a busy RPC channel by exposing two primitives: the logical `CallBudget` for outstanding in-flig…
|
||||
- [client](./src/client/client.md) — Caller-side binding for the worker-RPC protocol. `createRawWorkerRpcClient` returns a low-level object exposing `.call(…
|
||||
- [client](./src/client/client.md) — Caller-side binding for the worker-RPC protocol. `createRawWorkerRpcClient` returns a low-level object exposing `.call(…
|
||||
- [cloneable-guard](./src/client/cloneable-guard.md) — Walks a value (typically an RPC argument list or return value) and throws `WORKER_RPC.NOT_CLONEABLE` at the call site i…
|
||||
- [correlation](./src/correlation/correlation.md) — Provides the monotonic correlation-id generator and the in-memory pending-call registry that backs every outstanding RP…
|
||||
- [correlation](./src/correlation/correlation.md) — Provides the monotonic correlation-id generator and the in-memory pending-call registry that backs every outstanding RP…
|
||||
- [error-codes](./src/error-codes/error-codes.md) — Defines the stable `WORKER_RPC.*` code registry and the `WorkerRpcError` class. Every public failure path in `@suavepla…
|
||||
- [error-codes](./src/error-codes/error-codes.md) — Defines the stable `WORKER_RPC.*` code registry and the `WorkerRpcError` class. Every public failure path in `@suavepla…
|
||||
- [error-reconstruction](./src/error-reconstruction/error-reconstruction.md) — Translates thrown values into wire-safe `ErrorEnvelope`s and back into typed `Error` instances on the receiving side. `…
|
||||
- [error-reconstruction](./src/error-reconstruction/error-reconstruction.md) — Translates thrown values into wire-safe `ErrorEnvelope`s and back into typed `Error` instances on the receiving side. `…
|
||||
- [protocol](./src/protocol/protocol.md) — Defines the wire-format of every message that crosses a `MessagePort` between an `api-host` and an isolated/sandboxed p…
|
||||
- [protocol](./src/protocol/protocol.md) — Defines the wire-format of every message that crosses a `MessagePort` between an `api-host` and an isolated/sandboxed p…
|
||||
- [server](./src/server/server.md) — Worker-side binding for the RPC protocol. `serveWorkerRpc(port, handlers)` mounts a handlers object on a `MessagePort`,…
|
||||
- [server](./src/server/server.md) — Worker-side binding for the RPC protocol. `serveWorkerRpc(port, handlers)` mounts a handlers object on a `MessagePort`,…
|
||||
- [streaming](./src/streaming/streaming.md) — Caller-side primitives for consuming streaming RPC methods. The server publishes a `stream-chunk` frame per yielded val…
|
||||
- [streaming](./src/streaming/streaming.md) — Caller-side primitives for consuming streaming RPC methods. The server publishes a `stream-chunk` frame per yielded val…
|
||||
- [testing](./src/testing/testing.md) — Reusable conformance harness and an in-process paired-port factory used by every Stage-3 worker-proxy package's test su…
|
||||
- [conformance](./src/testing/conformance.md) — Builds a paired client/server harness over an in-process `MessageChannel` for conformance tests. The harness is intende…
|
||||
- [testing](./src/testing/testing.md) — Reusable conformance harness and an in-process paired-port factory used by every Stage-3 worker-proxy package's test su…
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Why
|
||||
|
||||
Per the api-plugin system design (§2.2 isolation tiers, §5.2a
|
||||
worker boundary), every capability adapter ships in two surfaces: a
|
||||
direct in-process binding for `trusted` plugins and a `MessagePort`-
|
||||
marshalled binding for `isolated` / `sandboxed` plugins. Hand-rolling
|
||||
that marshalling once per capability is how plugin frameworks accrete
|
||||
subtly-different RPC layers that diverge on cancellation, streaming,
|
||||
and error reconstruction. `api-worker-rpc` is the single shared
|
||||
protocol every worker-proxy package builds on; getting it right once
|
||||
means every capability — `db`, `events`, `secrets`, `jobs`, `logger`,
|
||||
future ones — gets cancellation, backpressure, streaming, and error
|
||||
reconstruction for free.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
bun add @suaveplan/api-worker-rpc
|
||||
```
|
||||
|
||||
## Quick start
|
||||
|
||||
```ts
|
||||
import { createWorkerRpcClient } from "@suaveplan/api-worker-rpc";
|
||||
import { serveWorkerRpc } from "@suaveplan/api-worker-rpc";
|
||||
import { createInProcessPortPair } from "@suaveplan/api-worker-rpc/testing";
|
||||
|
||||
interface Calc { add(a: number, b: number): number; }
|
||||
|
||||
const { clientPort, serverPort, close } = createInProcessPortPair();
|
||||
const server = serveWorkerRpc(serverPort, {
|
||||
add: ([a, b]) => (a as number) + (b as number),
|
||||
});
|
||||
const calc = createWorkerRpcClient<Calc>(clientPort);
|
||||
|
||||
console.log(await calc.add(2, 3)); // 5
|
||||
|
||||
calc.close();
|
||||
server.close();
|
||||
close();
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
- [`protocol`](./src/protocol/protocol.md) — Zod-validated wire frames
|
||||
(`request`, `response`, `cancel`, `progress`, `stream-open`,
|
||||
`stream-chunk`, `stream-end`, `stream-ack`, `hello`, `goodbye`)
|
||||
plus `parseFrame` and the `ErrorEnvelope` type.
|
||||
- [`correlation`](./src/correlation/correlation.md) — monotonic id
|
||||
generator + `PendingRegistry` (orphan detection, reuse detection,
|
||||
timeout eviction).
|
||||
- [`client`](./src/client/client.md) — `createWorkerRpcClient<T>` typed
|
||||
proxy and `createRawWorkerRpcClient` low-level binding.
|
||||
- [`client/cloneable-guard`](./src/client/cloneable-guard.md) —
|
||||
pre-send structured-clone safety walk.
|
||||
- [`server`](./src/server/server.md) — `serveWorkerRpc(port,
|
||||
handlers)` mounts handler maps with automatic streaming and
|
||||
cancel-via-`AbortController`.
|
||||
- [`streaming`](./src/streaming/streaming.md) — caller-side
|
||||
`streamRequest` returning an `AsyncIterable` + `StreamDispatcher`
|
||||
for inbound-frame routing.
|
||||
- [`abort-forwarding`](./src/abort-forwarding/abort-forwarding.md) —
|
||||
`attachAbortSignal`, `createRemoteAbort`, and the platform-independent
|
||||
`AbortError` class.
|
||||
- [`backpressure`](./src/backpressure/backpressure.md) —
|
||||
`CallBudget` (logical) and `BoundedQueue` (physical) with three
|
||||
policies.
|
||||
- [`error-reconstruction`](./src/error-reconstruction/error-reconstruction.md)
|
||||
— `errorToEnvelope` / `envelopeToError` with depth-bounded cause
|
||||
chains.
|
||||
- [`error-codes`](./src/error-codes/error-codes.md) — the
|
||||
`WORKER_RPC_CODES` registry and `WorkerRpcError` class.
|
||||
- [`testing`](./src/testing/testing.md) — `createInProcessPortPair`
|
||||
+ `runWorkerRpcConformance` harness.
|
||||
|
||||
## Error codes
|
||||
|
||||
Every code in `WORKER_RPC_CODES` is reachable from at least one
|
||||
production path:
|
||||
|
||||
| Code | Raised from |
|
||||
| --------------------------------- | ------------------------------------------- |
|
||||
| `WORKER_RPC.PORT_CLOSED` | `client.close()` reject; post-close send |
|
||||
| `WORKER_RPC.REQUEST_TIMEOUT` | per-call timeout eviction |
|
||||
| `WORKER_RPC.RESPONSE_TIMEOUT` | (reserved for response-only timeout policy) |
|
||||
| `WORKER_RPC.INVALID_FRAME` | malformed inbound frame |
|
||||
| `WORKER_RPC.UNKNOWN_METHOD` | server dispatch of missing handler |
|
||||
| `WORKER_RPC.CORRELATION_ID_REUSED`| double-register on same id |
|
||||
| `WORKER_RPC.STREAM_BACKPRESSURE_EXCEEDED` | reserved for stream-explicit overflow |
|
||||
| `WORKER_RPC.HANDLER_THREW` | server-side stream handler not iterable |
|
||||
| `WORKER_RPC.CANCELLED` | registry cancel |
|
||||
| `WORKER_RPC.VERSION_MISMATCH` | inbound `v !== PROTOCOL_VERSION` |
|
||||
| `WORKER_RPC.ORPHAN_RESPONSE` | `settle()` on unknown id |
|
||||
| `WORKER_RPC.NOT_CLONEABLE` | `assertCloneable` pre-send walk |
|
||||
| `WORKER_RPC.REMOTE_THROW` | wrapping foreign throws on the wire |
|
||||
| `WORKER_RPC.BACKPRESSURE` | `CallBudget` or fail-mode `BoundedQueue` |
|
||||
|
||||
## Verification
|
||||
|
||||
- 100% test coverage gated in CI (`bunx turbo test:coverage --filter=@suaveplan/api-worker-rpc`).
|
||||
- Full lint+typecheck+test+build gate per package rules.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
Reference in New Issue
Block a user