Skip to content

Commit 17e84d4

Browse files
Merge pull request #2 from callumfrederiksen/codex/modify-message-parsing-logic-in-zodmessagehandler
2 parents 47ff49e + 116fc65 commit 17e84d4

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { describe, it, expect, vi } from "vitest";
2+
import { EventEmitter } from "node:events";
3+
import { ZodMessageHandler } from "./zodMessageHandler.js";
4+
import { z } from "zod";
5+
6+
describe("ZodMessageHandler.registerHandlers", () => {
7+
const schema = { TEST: z.object({ foo: z.string() }) } as const;
8+
9+
it("handles messages with an explicit payload field", async () => {
10+
const handler = vi.fn(async (payload: { foo: string }) => payload);
11+
const messageHandler = new ZodMessageHandler({ schema, messages: { TEST: handler } });
12+
const emitter = new EventEmitter();
13+
messageHandler.registerHandlers(emitter);
14+
15+
const ack = await new Promise((resolve) => {
16+
emitter.emit("TEST", { payload: { foo: "bar" }, version: "v1" }, resolve);
17+
});
18+
19+
expect(handler).toHaveBeenCalledWith({ foo: "bar" });
20+
expect(ack).toEqual({ foo: "bar" });
21+
});
22+
23+
it("handles messages without a payload field", async () => {
24+
const handler = vi.fn(async (payload: { foo: string }) => payload);
25+
const messageHandler = new ZodMessageHandler({ schema, messages: { TEST: handler } });
26+
const emitter = new EventEmitter();
27+
messageHandler.registerHandlers(emitter);
28+
29+
const ack = await new Promise((resolve) => {
30+
emitter.emit("TEST", { foo: "baz", version: "v1" }, resolve);
31+
});
32+
33+
expect(handler).toHaveBeenCalledWith({ foo: "baz" });
34+
expect(ack).toEqual({ foo: "baz" });
35+
});
36+
});

packages/core/src/v3/zodMessageHandler.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,19 @@ export class ZodMessageHandler<TMessageCatalog extends ZodMessageCatalogSchema>
179179

180180
let ack: Awaited<ReturnType<ZodMessageHandler<TMessageCatalog>["handleMessage"]>>;
181181

182-
// FIXME: this only works if the message doesn't have genuine payload prop
183-
if ("payload" in message) {
184-
ack = await this.handleMessage({ type: eventName, ...message });
182+
// Use runtime validation to detect payload presence
183+
const hasPayload =
184+
typeof message === "object" &&
185+
message !== null &&
186+
z.object({ payload: z.unknown() }).passthrough().safeParse(message).success;
187+
188+
if (hasPayload) {
189+
ack = await this.handleMessage({ type: eventName, ...(message as any) });
185190
} else {
186191
// Handle messages not sent by ZodMessageSender
187-
const { version, ...payload } = message;
192+
const messageObj =
193+
typeof message === "object" && message !== null ? (message as any) : {};
194+
const { version, ...payload } = messageObj;
188195
ack = await this.handleMessage({ type: eventName, version, payload });
189196
}
190197

0 commit comments

Comments
 (0)