Skip to content

Commit 3c3c426

Browse files
committed
fix: typings for messgeSchema() funciton
1 parent cf4f8e7 commit 3c3c426

File tree

3 files changed

+151
-24
lines changed

3 files changed

+151
-24
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bun-ws-router",
3-
"version": "0.0.1",
3+
"version": "0.0.2",
44
"description": "A simple and efficient WebSocket router for Bun with Zod-based message validation.",
55
"keywords": [
66
"bun",

schema.ts

Lines changed: 141 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* SPDX-FileCopyrightText: 2025-present Kriasoft */
22
/* SPDX-License-Identifier: MIT */
33

4-
import type { ZodObject, ZodRawShape, ZodTypeAny } from "zod";
4+
import type { ZodLiteral, ZodObject, ZodRawShape, ZodTypeAny } from "zod";
55
import { z } from "zod";
66

77
/**
@@ -23,37 +23,164 @@ export const MessageSchema = z.object({
2323
meta: MessageMetadataSchema,
2424
});
2525

26+
// -----------------------------------------------------------------------
27+
// Type Definitions
28+
// -----------------------------------------------------------------------
29+
30+
/**
31+
* Type for a message schema with no payload
32+
*/
33+
export type BaseMessageSchema<T extends string> = ZodObject<{
34+
type: ZodLiteral<T>;
35+
meta: typeof MessageMetadataSchema;
36+
}>;
37+
38+
/**
39+
* Type for a message schema with a payload
40+
*/
41+
export type PayloadMessageSchema<
42+
T extends string,
43+
P extends ZodTypeAny
44+
> = ZodObject<{
45+
type: ZodLiteral<T>;
46+
meta: typeof MessageMetadataSchema;
47+
payload: P;
48+
}>;
49+
50+
/**
51+
* Type for a message schema with a custom meta object
52+
*/
53+
export type MessageSchemaWithCustomMeta<
54+
T extends string,
55+
M extends ZodRawShape
56+
> = ZodObject<{
57+
type: ZodLiteral<T>;
58+
meta: ZodObject<typeof MessageMetadataSchema.shape & M>;
59+
}>;
60+
61+
/**
62+
* Type for a message schema with a payload and custom meta object
63+
*/
64+
export type PayloadMessageSchemaWithCustomMeta<
65+
T extends string,
66+
P extends ZodTypeAny,
67+
M extends ZodRawShape
68+
> = ZodObject<{
69+
type: ZodLiteral<T>;
70+
meta: ZodObject<typeof MessageMetadataSchema.shape & M>;
71+
payload: P;
72+
}>;
73+
74+
// -----------------------------------------------------------------------
75+
// Function Overloads
76+
// -----------------------------------------------------------------------
77+
78+
/**
79+
* Creates a message schema with a literal type but no payload or custom metadata
80+
*/
81+
export function messageSchema<T extends string>(
82+
messageType: T
83+
): BaseMessageSchema<T>;
84+
85+
/**
86+
* Creates a message schema with a literal type and a payload schema (object form)
87+
*/
88+
export function messageSchema<
89+
T extends string,
90+
P extends Record<string, ZodTypeAny>
91+
>(messageType: T, payload: P): PayloadMessageSchema<T, ZodObject<P>>;
92+
93+
/**
94+
* Creates a message schema with a literal type and a payload schema (ZodType form)
95+
*/
96+
export function messageSchema<T extends string, P extends ZodTypeAny>(
97+
messageType: T,
98+
payload: P
99+
): PayloadMessageSchema<T, P>;
100+
101+
/**
102+
* Creates a message schema with a literal type and custom metadata
103+
*/
104+
export function messageSchema<T extends string, M extends ZodRawShape>(
105+
messageType: T,
106+
payload: undefined,
107+
meta: ZodObject<M>
108+
): MessageSchemaWithCustomMeta<T, M>;
109+
110+
/**
111+
* Creates a message schema with a literal type, payload (object form), and custom metadata
112+
*/
113+
export function messageSchema<
114+
T extends string,
115+
P extends Record<string, ZodTypeAny>,
116+
M extends ZodRawShape
117+
>(
118+
messageType: T,
119+
payload: P,
120+
meta: ZodObject<M>
121+
): PayloadMessageSchemaWithCustomMeta<T, ZodObject<P>, M>;
122+
123+
/**
124+
* Creates a message schema with a literal type, payload (ZodType form), and custom metadata
125+
*/
126+
export function messageSchema<
127+
T extends string,
128+
P extends ZodTypeAny,
129+
M extends ZodRawShape
130+
>(
131+
messageType: T,
132+
payload: P,
133+
meta: ZodObject<M>
134+
): PayloadMessageSchemaWithCustomMeta<T, P, M>;
135+
136+
// -----------------------------------------------------------------------
137+
// Implementation
138+
// -----------------------------------------------------------------------
139+
26140
/**
27141
* A helper function to create specific WebSocket message schemas.
28142
* It extends the base `MessageSchema`, setting a literal type, adding a payload schema,
29143
* and optionally extending the metadata schema.
144+
*
145+
* Implementation for all overloads
30146
*/
31147
export function messageSchema<
32-
Payload extends Record<string, ZodTypeAny> | ZodTypeAny | undefined,
33-
Metadata extends ZodRawShape | undefined = undefined
148+
T extends string,
149+
P extends Record<string, ZodTypeAny> | ZodTypeAny | undefined = undefined,
150+
M extends ZodRawShape = {}
34151
>(
35-
messageType: string,
36-
schema?: Payload,
37-
meta?: Metadata extends ZodRawShape ? ZodObject<Metadata> : undefined
38-
) {
152+
messageType: T,
153+
payload?: P,
154+
meta?: M extends {} ? undefined : ZodObject<M>
155+
): P extends undefined
156+
? M extends {}
157+
? BaseMessageSchema<T>
158+
: MessageSchemaWithCustomMeta<T, M>
159+
: P extends Record<string, ZodTypeAny>
160+
? M extends {}
161+
? PayloadMessageSchema<T, ZodObject<P>>
162+
: PayloadMessageSchemaWithCustomMeta<T, ZodObject<P>, M>
163+
: M extends {}
164+
? PayloadMessageSchema<T, P & ZodTypeAny>
165+
: PayloadMessageSchemaWithCustomMeta<T, P & ZodTypeAny, M> {
39166
// Create base schema with type and meta
40167
const baseSchema = MessageSchema.extend({
41168
type: z.literal(messageType),
42169
meta: meta
43-
? MessageMetadataSchema.extend(meta.shape)
170+
? MessageMetadataSchema.extend((meta as ZodObject<any>).shape)
44171
: MessageMetadataSchema,
45172
});
46173

47174
// If no payload schema provided, return without payload
48-
if (schema === undefined) {
49-
return baseSchema;
175+
if (payload === undefined) {
176+
return baseSchema as any;
50177
}
51178

52179
// Add payload to schema based on input type
53180
return baseSchema.extend({
54181
payload:
55-
schema instanceof z.ZodType
56-
? schema
57-
: z.object(schema as Record<string, ZodTypeAny>),
58-
});
182+
payload instanceof z.ZodType
183+
? payload
184+
: z.object(payload as Record<string, ZodTypeAny>),
185+
}) as any;
59186
}

types.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
/* SPDX-License-Identifier: MIT */
33

44
import type { HeadersInit, Server, ServerWebSocket } from "bun";
5-
import { z, ZodLiteral, type ZodRawShape } from "zod";
5+
import type { ZodObject, ZodType, ZodTypeAny } from "zod";
6+
import { z, ZodLiteral } from "zod";
67
import { MessageMetadataSchema } from "./schema";
78

89
export type WebSocketRouterOptions = {
@@ -22,7 +23,7 @@ export type UpgradeOptions<T> = {
2223
export type SendFunction = <Schema extends MessageSchemaType>(
2324
schema: Schema,
2425
data: Schema["shape"] extends { payload: infer P }
25-
? P extends z.ZodTypeAny
26+
? P extends ZodTypeAny
2627
? z.infer<P>
2728
: unknown
2829
: unknown,
@@ -34,7 +35,7 @@ export type MessageContext<Schema extends MessageSchemaType, Data> = {
3435
meta: z.infer<Schema["shape"]["meta"]>;
3536
send: SendFunction;
3637
} & (Schema["shape"] extends { payload: infer P }
37-
? P extends z.ZodTypeAny
38+
? P extends ZodTypeAny
3839
? { payload: z.infer<P> }
3940
: {}
4041
: {});
@@ -43,12 +44,11 @@ export type MessageHandler<Schema extends MessageSchemaType, Data> = (
4344
context: MessageContext<Schema, Data>
4445
) => void | Promise<void>;
4546

46-
export type MessageSchemaType = z.ZodObject<
47-
{
48-
type: ZodLiteral<string>; // Must have a literal string type
49-
meta: typeof MessageMetadataSchema; // Must have compatible meta
50-
} & ZodRawShape // Allows for other fields like 'payload'
51-
>;
47+
export type MessageSchemaType = ZodObject<{
48+
type: ZodLiteral<string>; // Must have a literal string type
49+
meta: ZodType<z.infer<typeof MessageMetadataSchema>>;
50+
payload?: ZodTypeAny;
51+
}>;
5252

5353
export type MessageHandlerEntry = {
5454
schema: MessageSchemaType;

0 commit comments

Comments
 (0)