42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
import z from "zod";
|
|
|
|
/**
|
|
* Wire envelope for every WebSocket frame that flows between the host and a
|
|
* plugin. Unknown top-level keys are rejected so clients cannot smuggle
|
|
* fields past the host's validation gate.
|
|
*
|
|
* The shape is intentionally minimal:
|
|
* - `id` correlates request/response/ack frames.
|
|
* - `type` is the message discriminator (plugin-defined namespace).
|
|
* - `topic` names the subscription (optional for non-subscription frames).
|
|
* - `payload` is the opaque body — plugins narrow with their own Zod schema.
|
|
* - `ts` is an optional ISO-8601 producer timestamp.
|
|
*/
|
|
export const wsEnvelopeSchema = z
|
|
.object({
|
|
id: z.string().min(1),
|
|
type: z.string().min(1),
|
|
topic: z.string().min(1).optional(),
|
|
payload: z.unknown().optional(),
|
|
ts: z.string().min(1).optional(),
|
|
})
|
|
.strict();
|
|
|
|
export type WsEnvelope = z.infer<typeof wsEnvelopeSchema>;
|
|
|
|
/**
|
|
* Type-narrowing helper: returns `true` (and narrows `value` to
|
|
* `WsEnvelope`) when the candidate parses successfully.
|
|
*/
|
|
export function isWsEnvelope(value: unknown): value is WsEnvelope {
|
|
return wsEnvelopeSchema.safeParse(value).success;
|
|
}
|
|
|
|
/**
|
|
* Strict parser that throws the underlying `ZodError` on failure. Callers
|
|
* that prefer a typed thrown error should wrap with `WsError`.
|
|
*/
|
|
export function parseWsEnvelope(value: unknown): WsEnvelope {
|
|
return wsEnvelopeSchema.parse(value);
|
|
}
|