Files
skills/docs/api-stack/api/api-logger-worker-proxy/src/protocol/protocol.md
2026-05-29 08:20:56 +01:00

3.4 KiB

protocol

(no submodules)

Purpose

Defines the Zod-validated wire format for log frames travelling from a worker-isolated plugin to the main-process @suaveplan/logger. Frames are a small discriminated union — log-batch, goodbye, and control — so receivers branch on kind and reject malformed input cleanly via Zod parsing rather than ad-hoc shape checks.

The protocol is bidirectional: workers send log-batch and goodbye frames to the main, the main sends control frames (disable / enable) back to the worker so it can stop emitting after the main-side logger has been disposed (design doc §5.5 dispose-in-reverse).

Features

  • LOGGER_PROXY_PROTOCOL_VERSION — "1.0.0". Embedded in every frame via the v field; servers reject on mismatch.
  • LOG_LEVELS / LogLevel — trace | debug | info | warn | error | fatal. Wider than LoggerLike to allow forward-compatibility; the main-side server narrows down before dispatch.
  • PluginTag / pluginTagSchema — { name, version } attached to every batch.
  • WireLogRecord / logRecordSchema — single record: level, msg, ts, optional ctx map, optional trace (trace_id / span_id).
  • LogBatchFrame / logBatchFrameSchema — { kind: "log-batch", v, plugin, records: WireLogRecord[] } with min(1) records.
  • ControlFrame / controlFrameSchema — { kind: "control", v, action: "disable" | "enable" }.
  • parseLoggerProxyFrame(input) — validates and returns the discriminated union; throws ZodError on malformed input.

Usage: Basic

import {
    LOGGER_PROXY_PROTOCOL_VERSION,
    parseLoggerProxyFrame,
} from "@suaveplan/api-logger-worker-proxy/protocol";

const frame = parseLoggerProxyFrame({
    v: LOGGER_PROXY_PROTOCOL_VERSION,
    kind: "log-batch",
    plugin: { name: "demo", version: "0.1.0" },
    records: [
        {
            level: "info",
            msg: "hello",
            ts: new Date().toISOString(),
            ctx: { userId: 42 },
        },
    ],
});

Usage: Advanced

Switch over kind with exhaustive narrowing:

import { parseLoggerProxyFrame } from "@suaveplan/api-logger-worker-proxy/protocol";

function handle(input: unknown): void {
    const frame = parseLoggerProxyFrame(input);
    switch (frame.kind) {
        case "log-batch":
            for (const r of frame.records) dispatch(r, frame.plugin);
            break;
        case "control":
            applyControl(frame.action);
            break;
        case "goodbye":
            shutdown(frame.reason);
            break;
    }
}

API Reference

  • LOG_LEVELS: readonly LogLevel[] — exported tuple for enumeration.
  • logLevelSchema: ZodEnum<LogLevel> — re-use in downstream schemas.
  • logRecordSchema, logBatchFrameSchema, controlFrameSchema, logGoodbyeFrameSchema, loggerProxyFrameSchema — Zod schemas.
  • parseLoggerProxyFrame(input: unknown): LoggerProxyFrame — entry point for receivers. Throws on malformed input.

Implementation Notes

The schema accepts ctx as Record<string, unknown> to keep the proxy transparent to the application. Main-side redaction normalises sensitive fields before they reach the sink. ts is required so the main-side stays a pure forwarder; the worker stamps wall-clock time at record creation. Frames flow over MessagePort and survive structured-clone — keeping records as plain data (no Date, no classes) is intentional.