Skip to content

Commit 47ff49e

Browse files
Merge pull request #1 from callumfrederiksen/codex/update-constructor-logic-and-add-validation-test
2 parents eee0fb2 + 89c04d3 commit 47ff49e

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

packages/core/src/v3/zodNamespace.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@ import {
55
ZodSocketMessageCatalogSchema,
66
ZodSocketMessageHandler,
77
ZodSocketMessageHandlers,
8+
GetSocketMessagesWithCallback,
89
} from "./zodSocket.js";
910
// @ts-ignore
1011
import type { DefaultEventsMap, EventsMap } from "socket.io/dist/typed-events";
1112
import { z } from "zod";
1213
import { SimpleStructuredLogger, StructuredLogger } from "./utils/structuredLogger.js";
1314

15+
type AssertNoCallbackSchemas<T extends ZodSocketMessageCatalogSchema> = [
16+
GetSocketMessagesWithCallback<T>,
17+
] extends [never]
18+
? {}
19+
: { __error__: GetSocketMessagesWithCallback<T> };
20+
1421
interface ExtendedError extends Error {
1522
data?: any;
1623
}
@@ -32,7 +39,7 @@ interface ZodNamespaceOptions<
3239
TServerMessages extends ZodSocketMessageCatalogSchema,
3340
TServerSideEvents extends EventsMap = DefaultEventsMap,
3441
TSocketData extends z.ZodObject<any, any, any> = any,
35-
> {
42+
> extends AssertNoCallbackSchemas<TServerMessages> {
3643
io: Server;
3744
name: string;
3845
clientMessages: TClientMessages;
@@ -108,7 +115,16 @@ export class ZodNamespace<
108115

109116
this.namespace = this.io.of(opts.name);
110117

111-
// FIXME: There's a bug here, this sender should not accept Socket schemas with callbacks
118+
const invalidMessages = Object.entries(opts.serverMessages)
119+
.filter(([, value]) => "callback" in value && value.callback)
120+
.map(([key]) => key);
121+
122+
if (invalidMessages.length > 0) {
123+
throw new Error(
124+
`serverMessages with callbacks are not supported: ${invalidMessages.join(", ")}`
125+
);
126+
}
127+
112128
this.sender = new ZodMessageSender({
113129
schema: opts.serverMessages,
114130
sender: async (message) => {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { describe, it, expect } from "vitest";
2+
import { ZodNamespace } from "../src/v3/zodNamespace.js";
3+
import type { Server } from "socket.io";
4+
import { z } from "zod";
5+
6+
const createStubServer = (): Server => {
7+
const namespace = {
8+
use: () => namespace,
9+
on: () => namespace,
10+
emit: () => {},
11+
fetchSockets: async () => [],
12+
} as any;
13+
return { of: () => namespace } as any;
14+
};
15+
16+
describe("ZodNamespace", () => {
17+
it("throws when serverMessages include callbacks", () => {
18+
const io = createStubServer();
19+
20+
const clientMessages = {} as const;
21+
const serverMessages = {
22+
TEST: {
23+
message: z.object({ version: z.literal("v1").default("v1") }),
24+
callback: z.void(),
25+
},
26+
} as const;
27+
28+
expect(
29+
() =>
30+
new ZodNamespace({
31+
io,
32+
name: "test",
33+
clientMessages,
34+
serverMessages,
35+
})
36+
).toThrowError(/callbacks are not supported/);
37+
});
38+
});

0 commit comments

Comments
 (0)