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,90 @@
# `server` (main-side)
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
The main-side server. Consumes inbound `log-batch` frames from a
worker-isolated plugin, applies redaction at the boundary, narrows the
wire-format levels (`trace` / `fatal`) down to the `LoggerLike` levels
(`debug` / `error`), and forwards each record to the host's main-side
`@suaveplan/logger` instance. Plugin pre-tagging is honoured by routing
through `logger.child(plugin)` when available, so every record reaches
the sink with structured `plugin` / `plugin_version` fields without
the worker having to know about the host logger's child-binding
semantics.
The server is best-effort, just like the worker-side client. Malformed
frames increment a counter, fire an `onInvalidFrame` hook, and surface
via `onError` — but they NEVER throw out of the listener. A single bad
record cannot bring down the port.
## Features
- Wire-frame validation via Zod (`parseLoggerProxyFrame`).
- Level narrowing (`trace → debug`, `fatal → error`) so downstream
sinks need not understand the broader level set.
- Optional redaction passthrough at the boundary.
- Child-logger caching per `PluginTag` (Map keyed by
`name@version` so caching survives structured-clone of the tag
object across the port boundary).
- Hard `maxBatchSize` cap (default 10_000 records/batch) that protects
the main logger from a hostile or buggy worker dumping unbounded
inbound traffic.
- Observation hooks: `onRecord` (post-redaction), `onError`, and
`onInvalidFrame`.
- `forwardedCount`, `invalidFrameCount`, `overflowDropCount` counters.
## Usage: Basic
```ts
import { createLoggerProxyServer } from "@suaveplan/api-logger-worker-proxy/main-side";
import { createLogger } from "@suaveplan/logger";
const mainLogger = createLogger({ level: "info" });
const server = createLoggerProxyServer(mainPort, mainLogger);
// ... worker emits log records over workerPort ...
server.close();
```
## Usage: Advanced
Pipe through host redaction and observe every record:
```ts
import { createLoggerProxyServer } from "@suaveplan/api-logger-worker-proxy/main-side";
import { maskKeys } from "@suaveplan/api-logger-worker-proxy/redaction-passthrough";
const server = createLoggerProxyServer(mainPort, mainLogger, {
redaction: {
ctxRedactor: maskKeys(["password", "token", "secret"]),
},
onRecord: (rec, plug) => audit.write(rec, plug),
onError: (err) => mainLogger.warn("logger-proxy error", { code: err.code }),
onInvalidFrame: (raw, cause) =>
mainLogger.warn("logger-proxy invalid frame", { raw, cause }),
maxBatchSize: 5_000,
});
```
## API Reference
- `createLoggerProxyServer(port, logger, options?): LoggerProxyServer`
— primary entry.
- `LoggerProxyServer.close()` — detach. Idempotent.
- `OnRecord(record, plugin)` — post-redaction, pre-dispatch hook.
- `OnInvalidFrame(input, error)` — fires on Zod parse failure.
## Implementation Notes
`logger.child` is optional on `LoggerLike`; when absent the server
merges `plugin` / `plugin_version` into the call-site `ctx` instead.
The child-logger cache is a `Map` keyed by `${name}@${version}` so
that workers reusing the same identity (the common case) hit the
cache even after structured-clone has produced a fresh object on the
receive side of the port. Sink
failures (the host logger throws while writing) are caught per-record
so a single bad record cannot stall the listener; the error surfaces
via `onError`.