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,68 @@
# Handler Bridge
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module owns the shared wire schemas, the worker-side
`HandlerRegistry`, and the `runWithTimeout` helper used by both ends of
the proxy. The bridge is the only place that decides how a registered
cron/queued handler is exercised on the worker side; isolating it keeps
the client and server modules small and lets the same logic be unit
tested without spinning up a `MessageChannel`. Schemas use `zod` so any
bad payload that crosses the boundary fails fast at the parse step
rather than producing an obscure runtime error downstream.
## Features
- `registerJobRequestSchema` / `runJobRequestSchema` — Zod-validated
wire formats for registration and dispatch frames.
- `HandlerRegistry` — type-safe storage of cron + queued closures with
idempotent set / run / clear semantics and a `sizes` accessor.
- `runWithTimeout` — runs a closure with an optional millisecond budget
and wraps every failure into a typed `JobsProxyError` (`HANDLER_THREW`
or `JOB_TIMEOUT`).
## Usage: Basic
```ts
import { HandlerRegistry } from "@suaveplan/api-jobs-worker-proxy/handler-bridge";
const reg = new HandlerRegistry();
reg.setCron("daily-rotate", async () => rotate());
await reg.runCron("daily-rotate");
```
## Usage: Advanced
```ts
import { runWithTimeout } from "@suaveplan/api-jobs-worker-proxy/handler-bridge";
await runWithTimeout(
() => longRunningExport(),
"export-csv",
30_000,
); // throws JobsProxyError("JOBS_PROXY.JOB_TIMEOUT") after 30s
```
## API Reference
- `registerJobRequestSchema: ZodType<RegisterJobRequest>` — wire schema.
- `runJobRequestSchema: ZodType<RunJobRequest>` — wire schema.
- `HandlerRegistry` — `setCron`, `setQueued`, `hasCron`, `hasQueued`,
`runCron`, `runQueued`, `clear`, `sizes`.
- `runWithTimeout(fn, name, timeoutMs)` — runs `fn`, wraps failures.
## Implementation Notes
`runWithTimeout` uses `Promise.race` between the handler invocation and
a timeout-rejecting promise. The timeout branch always installs a timer
(non-nullable) when `timeoutMs > 0`; the finally-clear is unconditional
once that branch is entered. A `0` budget skips the race entirely and
falls back to a direct `await` so successful handlers do not pay the
extra microtask cost. `HandlerRegistry.setCron`/`setQueued` return a
boolean indicating whether the name already existed, allowing callers to
detect (and warn on) duplicate registrations without forbidding the
replacement.