@ws-kit/zod
Version:
Zod validator adapter for WS-Kit with runtime schema validation and full TypeScript inference
174 lines • 7.35 kB
TypeScript
/**
* Runtime envelope builders for message schemas.
* Provides two forms: object-oriented (primary) and positional (compact).
*
* Both return strict Zod root objects with non-enumerable hints for the router
* and per-schema options (validateOutgoing, strict) for granular control.
*
* Users can compose schemas before wrapping to preserve type safety:
* const JoinPayload = z.object({roomId: z.string()}).transform(...);
* const Join = message({ type: "JOIN", payload: JoinPayload, options: {...} });
*/
import { type SchemaOpts } from "@ws-kit/core/internal";
import { z, type ZodDefault, type ZodLiteral, type ZodObject, type ZodOptional, type ZodRawShape, type ZodType } from "zod";
import type { BrandedSchema } from "./types.js";
/**
* Symbol for Zod payload schema (validator-specific).
* Stores the Zod schema for the payload field.
*/
export declare const ZOD_PAYLOAD: unique symbol;
/**
* Standard meta fields that are always allowed.
* Users can extend with additional required or optional fields.
*/
declare const STANDARD_META_FIELDS: {
timestamp: z.ZodOptional<z.ZodNumber>;
correlationId: z.ZodOptional<z.ZodString>;
};
/**
* Helper type to infer actual types from ZodRawShape or ZodObject.
* Converts each Zod schema in a shape to its inferred type.
*
* @internal
*/
type InferPayloadShape<P extends ZodRawShape | ZodObject<any> | undefined> = P extends undefined ? never : P extends ZodRawShape ? {
[K in keyof P]: P[K] extends ZodType<infer U> ? U : never;
} : P extends ZodObject<any> ? z.infer<P> : never;
/**
* Helper to construct the Zod shape for the message root object.
* This ensures z.infer<typeof Message> returns the correct structure.
*/
type MessageZodShape<T extends string, P extends ZodRawShape | ZodObject<any> | undefined, M extends ZodRawShape | undefined> = {
type: ZodLiteral<T>;
meta: ZodDefault<ZodOptional<ZodObject<M extends ZodRawShape ? Omit<typeof STANDARD_META_FIELDS, keyof M> & M : typeof STANDARD_META_FIELDS>>>;
} & (P extends undefined ? {} : {
payload: P extends ZodObject<any> ? P : P extends ZodRawShape ? ZodObject<P> : never;
});
/**
* Creates a strict Zod root message schema.
* Supports two forms: object-oriented (primary) and positional (compact).
*
* Object form (recommended for clarity and extensibility):
* ```typescript
* const Join = message({
* type: "USER_JOIN",
* payload: z.object({ roomId: z.string() }),
* options: { strict: true }
* });
* ```
*
* Positional form (for small, one-off schemas):
* ```typescript
* const Ping = message("PING");
* const Join = message("USER_JOIN", { roomId: z.string() });
* ```
*/
export declare function message<const T extends string, P extends ZodRawShape | ZodObject<any> | undefined = undefined, M extends ZodRawShape | undefined = undefined>(spec: {
type: T;
payload?: P;
meta?: M;
options?: SchemaOpts;
}): ZodObject<MessageZodShape<T, P, M>> & BrandedSchema<T, P extends undefined ? never : InferPayloadShape<P>, never, M extends ZodRawShape ? {
[K in keyof M]: M[K] extends ZodType<infer U> ? U : never;
} : {}> & {
readonly messageType: T;
readonly __zod_payload: P;
readonly __descriptor: {
readonly messageType: T;
readonly kind: "event";
};
readonly __runtime: "ws-kit-schema";
};
export declare function message<const T extends string, P extends ZodRawShape | ZodObject<any> | undefined = undefined, M extends ZodRawShape | undefined = undefined>(type: T, payload?: P, metaShape?: M): ZodObject<MessageZodShape<T, P, M>> & BrandedSchema<T, P extends undefined ? never : InferPayloadShape<P>, never, M extends ZodRawShape ? {
[K in keyof M]: M[K] extends ZodType<infer U> ? U : never;
} : {}> & {
readonly messageType: T;
readonly __zod_payload: P;
readonly __descriptor: {
readonly messageType: T;
readonly kind: "event";
};
readonly __runtime: "ws-kit-schema";
};
/**
* Creates an RPC schema with separate request and response message definitions.
* Supports two forms: object-oriented (primary) and positional (compact).
*
* Object form (recommended for granular control):
* ```typescript
* const GetUser = rpc({
* req: {
* type: "GET_USER",
* payload: z.object({ id: z.string() })
* },
* res: {
* type: "USER",
* payload: z.object({ id: z.string(), name: z.string() }),
* options: { validateOutgoing: true }
* }
* });
* ```
*
* Positional form (for simple, compact contracts):
* ```typescript
* const GetUser = rpc(
* "GET_USER", { id: z.string() },
* "USER", { id: z.string(), name: z.string() }
* );
* ```
*/
export declare function rpc<const ReqT extends string, ReqP extends ZodRawShape | ZodObject<any> | undefined, ResT extends string, ResP extends ZodRawShape | ZodObject<any> | undefined, ReqM extends ZodRawShape | undefined = undefined, ResM extends ZodRawShape | undefined = undefined>(spec: {
req: {
type: ReqT;
payload?: ReqP;
meta?: ReqM;
options?: SchemaOpts;
};
res: {
type: ResT;
payload?: ResP;
meta?: ResM;
options?: SchemaOpts;
};
}): ZodObject<MessageZodShape<ReqT, ReqP, ReqM>> & BrandedSchema<ReqT, ReqP extends undefined ? never : InferPayloadShape<ReqP>, ResP extends undefined ? never : InferPayloadShape<ResP>, ReqM extends ZodRawShape ? {
[K in keyof ReqM]: ReqM[K] extends ZodType<infer U> ? U : never;
} : {}> & {
readonly response: ZodObject<MessageZodShape<ResT, ResP, ResM>> & BrandedSchema<ResT, ResP extends undefined ? never : InferPayloadShape<ResP>, never, ResM extends ZodRawShape ? {
[K in keyof ResM]: ResM[K] extends ZodType<infer U> ? U : never;
} : {}> & {
readonly messageType: ResT;
readonly __zod_payload: ResP;
readonly __descriptor: {
readonly messageType: ResT;
readonly kind: "event";
};
readonly __runtime: "ws-kit-schema";
};
readonly messageType: ReqT;
readonly __zod_payload: ReqP;
readonly __descriptor: {
readonly messageType: ReqT;
readonly kind: "rpc";
};
readonly __runtime: "ws-kit-schema";
};
export declare function rpc<const ReqT extends string, ReqP extends ZodRawShape | ZodObject<any> | undefined, ResT extends string, ResP extends ZodRawShape | ZodObject<any> | undefined>(requestType: ReqT, requestPayload: ReqP, responseType: ResT, responsePayload: ResP): ZodObject<MessageZodShape<ReqT, ReqP, undefined>> & BrandedSchema<ReqT, ReqP extends undefined ? never : InferPayloadShape<ReqP>, ResP extends undefined ? never : InferPayloadShape<ResP>, {}> & {
readonly response: ZodObject<MessageZodShape<ResT, ResP, undefined>> & BrandedSchema<ResT, ResP extends undefined ? never : InferPayloadShape<ResP>, never, {}> & {
readonly messageType: ResT;
readonly __zod_payload: ResP;
readonly __descriptor: {
readonly messageType: ResT;
readonly kind: "event";
};
readonly __runtime: "ws-kit-schema";
};
readonly messageType: ReqT;
readonly __zod_payload: ReqP;
readonly __descriptor: {
readonly messageType: ReqT;
readonly kind: "rpc";
};
readonly __runtime: "ws-kit-schema";
};
export {};
//# sourceMappingURL=runtime.d.ts.map