Initial Commit
This commit is contained in:
75
packages/api-stack/api/api-plugin-sse/src/schemas/options.md
Normal file
75
packages/api-stack/api/api-plugin-sse/src/schemas/options.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# options
|
||||
|
||||
## Purpose
|
||||
|
||||
Zod schema validating `SsePluginOptions` at the factory boundary. `createSsePlugin` calls `SsePluginOptionsSchema.safeParse(options)` and raises `SseError(SSE_INVALID_INPUT)` with the `ZodError` as `cause` on failure. The schema also encodes the canonical defaults so the plugin descriptor's resolved config reflects every documented default value without the implementation hand-coding them.
|
||||
|
||||
## Features
|
||||
|
||||
- Strict object validation rejects unknown keys to catch typos like `heartBeatInterval`.
|
||||
- Defaults applied via Zod's `.default()` so the resolved type has every field non-optional.
|
||||
- Numeric fields constrained: positive integers for time/cap fields; non-negative integer for retention (zero disables replay).
|
||||
- `routePrefix` regex matches `/`, `/sse`, `/v1/sse`, rejecting trailing-slash and missing-leading-slash forms.
|
||||
- Runtime objects (`idGenerator`, `clock`, `logger`) validated structurally via `z.custom` so duck-typed implementations are accepted.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { SsePluginOptionsSchema } from "@suaveplan/api-plugin-sse/schemas/options";
|
||||
|
||||
const parsed = SsePluginOptionsSchema.parse({
|
||||
heartbeatIntervalMs: 15_000,
|
||||
maxConnectionsPerPrincipal: 4,
|
||||
});
|
||||
console.log(parsed.routePrefix); // "/sse" (defaulted)
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { SsePluginOptionsSchema } from "@suaveplan/api-plugin-sse/schemas/options";
|
||||
import { SSE_CODES, SseError } from "@suaveplan/api-plugin-sse/error-codes/error-codes";
|
||||
|
||||
function validateOrThrow(input: unknown) {
|
||||
const result = SsePluginOptionsSchema.safeParse(input);
|
||||
if (!result.success) {
|
||||
throw new SseError(SSE_CODES.INVALID_INPUT, "invalid SSE config", {
|
||||
cause: result.error,
|
||||
});
|
||||
}
|
||||
return result.data;
|
||||
}
|
||||
|
||||
// User-supplied logger duck-typed against LoggerLike — accepted.
|
||||
validateOrThrow({
|
||||
logger: {
|
||||
debug: console.debug,
|
||||
info: console.info,
|
||||
warn: console.warn,
|
||||
error: console.error,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `SsePluginOptionsSchema` — Zod object schema. Fields and defaults:
|
||||
- `heartbeatIntervalMs` — positive integer (default `30_000`).
|
||||
- `routePrefix` — string matching `^/[A-Za-z0-9\-_/]*[A-Za-z0-9\-_]$|^/$` (default `"/sse"`).
|
||||
- `attachDefaultRoute` — boolean (default `true`).
|
||||
- `retentionPerChannel` — non-negative integer (default `100`).
|
||||
- `maxConnectionsPerPrincipal` — positive integer (default `16`).
|
||||
- `maxTotalConnections` — positive integer (default `10_000`).
|
||||
- `queueHighWaterMark` — positive integer (default `256`).
|
||||
- `overflowPolicy` — `"drop-oldest" | "drop-newest"` (default `"drop-oldest"`).
|
||||
- `idGenerator` — optional `() => string`.
|
||||
- `clock` — optional `Clock` from `@suaveplan/types`.
|
||||
- `logger` — optional `LoggerLike` from `@suaveplan/types`.
|
||||
- `type SsePluginOptionsInput` — `z.input<typeof SsePluginOptionsSchema>` (caller-facing shape).
|
||||
- `type SsePluginOptionsResolved` — `z.output<typeof SsePluginOptionsSchema>` (post-default shape).
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The schema is `.strict()` — unknown keys produce a `ZodIssueCode.unrecognized_keys` issue. Intentionally strict so a typo doesn't silently fall back to a default.
|
||||
- The runtime-object validators do not require structural typing of every method — they sniff the presence of one canonical method (`logger.info`, `clock.now`) so callers can pass extended objects without rewriting them.
|
||||
- Defaults are intentionally generous for production use; tighten them in your `createSsePlugin` call if you run behind aggressive proxies or with constrained memory budgets.
|
||||
Reference in New Issue
Block a user