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,110 @@
|
||||
# Worker-proxy factory — `@suaveplan/api-auth-bearer-static`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The worker-proxy surface is the second of the two Stage-4 surfaces this
|
||||
adapter ships (`§5.2a`). It lets the host install the bearer-static
|
||||
resolver in the main process while the actual token table lives inside an
|
||||
isolated worker. The host's `SessionResolverChain` calls
|
||||
`resolve(request)` exactly as for the direct surface; under the hood, the
|
||||
proxy marshals the request across a `MessagePort` using
|
||||
`@suaveplan/api-worker-rpc`, the worker's resolver runs, and the
|
||||
`Principal | null` decision is returned to the host.
|
||||
|
||||
The proxy intentionally keeps the token table out of the host's address
|
||||
space — useful when the host is sandboxed and the worker holds privileged
|
||||
credentials, or when operators want a single auth daemon serving multiple
|
||||
host workers.
|
||||
|
||||
## Features
|
||||
|
||||
- Bidirectional RPC over a `MessagePort` (or any `PortLike`) — no
|
||||
process / address-space assumptions.
|
||||
- Idempotent `dispose()` — coalesces multiple calls and closes the
|
||||
underlying RPC client exactly once.
|
||||
- Header set, request method, URL, and (optional) `peerCertificate` cross
|
||||
the boundary; opaque body and abort signal are out of scope (resolution
|
||||
does not need them).
|
||||
- Server-side mount via `serveBearerStaticResolverOnPort` — owns the real
|
||||
resolver and the token table.
|
||||
- Passes the same `runAuthSessionConformance` harness as the direct
|
||||
surface.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
createBearerStaticResolverWorkerProxy,
|
||||
serveBearerStaticResolverOnPort,
|
||||
} from "@suaveplan/api-auth-bearer-static/proxy";
|
||||
import { createInProcessPortPair } from "@suaveplan/api-worker-rpc";
|
||||
|
||||
const { clientPort, serverPort } = createInProcessPortPair();
|
||||
|
||||
// Worker side — owns the real table.
|
||||
const server = serveBearerStaticResolverOnPort(serverPort, {
|
||||
tokens: [
|
||||
{
|
||||
token: "T1",
|
||||
principal: { id: "svc", scopes: [], claims: {} },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Host side — sees only a proxy.
|
||||
const proxy = createBearerStaticResolverWorkerProxy(clientPort);
|
||||
|
||||
const request = new Request("https://api/x", {
|
||||
headers: { Authorization: "Bearer T1" },
|
||||
});
|
||||
const principal = await proxy.resolve(request);
|
||||
|
||||
await proxy.dispose();
|
||||
server.close("done");
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { Worker, MessageChannel } from "node:worker_threads";
|
||||
import {
|
||||
createBearerStaticResolverWorkerProxy,
|
||||
} from "@suaveplan/api-auth-bearer-static/proxy";
|
||||
|
||||
// Real Node worker boundary. The worker script imports
|
||||
// `serveBearerStaticResolverOnPort` and calls it against its own port.
|
||||
const { port1, port2 } = new MessageChannel();
|
||||
const worker = new Worker("./auth-worker.mjs", { transferList: [port2] });
|
||||
|
||||
const resolver = createBearerStaticResolverWorkerProxy(port1 as never);
|
||||
|
||||
// Place in chain alongside direct adapters — host treats both uniformly.
|
||||
import { SessionResolverChain } from "@suaveplan/api-auth";
|
||||
const chain = new SessionResolverChain([resolver]);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `serveBearerStaticResolverOnPort(port: PortLike, options: BearerStaticResolverOptions): { close(reason?: string): void }`
|
||||
— mount the server-side handlers.
|
||||
- `createBearerStaticResolverWorkerProxy(port: PortLike): SessionResolver`
|
||||
— host-side proxy.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The marshalled envelope is `{url, method, headers, peerCertificate?}` —
|
||||
the minimal subset of `Request` that the bearer-static decision actually
|
||||
needs. `peerCertificate` is structured-clone-friendly because the host
|
||||
attaches whatever shape the listener surfaced; tests pass plain objects.
|
||||
The proxy never sends the request body, because token resolution does not
|
||||
consult it. Errors thrown by the server-side resolver (e.g. an unexpected
|
||||
runtime fault) propagate as the standard `WORKER_RPC` error envelope and
|
||||
surface in the host as a thrown `WorkerRpcError` — the host's resolver
|
||||
chain treats this as a fail-closed `RESOLVER_THREW` per the documented
|
||||
`api-auth` chain semantics. `dispose()` calls the remote `dispose` first
|
||||
to drain the server-side state, then closes the local client so the
|
||||
underlying port can be garbage-collected.
|
||||
Reference in New Issue
Block a user