import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { createRequire } from "node:module"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { createJiti } from "jiti"; import { describe, expect, it } from "vitest"; import { WSOutboundMessageSchema as GeneratedWSOutboundMessageSchema } from "../../src/generated/validation/ws-outbound.aot.js"; interface GeneratedSchema { safeParse(input: unknown): { success: boolean; data?: unknown }; } const protocolRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); const generatedWSOutboundPath = resolve( protocolRoot, "src/generated/validation/ws-outbound.aot.ts", ); const require = createRequire(import.meta.url); async function compileInlineSchema(sourceSchema: string): Promise { const scratchRoot = resolve(protocolRoot, "../../.tmp"); await mkdir(scratchRoot, { recursive: true }); const tempDir = await mkdtemp(join(scratchRoot, "paseo-zod-aot-")); try { const sourcePath = join(tempDir, "schema.source.js"); const outputPath = join(tempDir, "schema.generated.ts"); await writeFile(join(tempDir, "package.json"), '{"type":"module"}\n'); await writeFile( sourcePath, [ 'import { z } from "zod";', 'import { compile } from "zod-aot";', sourceSchema, "export const Schema = compile(SourceSchema);", "", ].join("\n"), ); const zodAotEntry = require.resolve("zod-aot"); const zodAotRoot = resolve(dirname(zodAotEntry), ".."); const [{ discoverSchemas }, { compileSchemas }, { generateCompiledFileContent }] = await Promise.all([ import(pathToFileURL(resolve(zodAotRoot, "dist/discovery.js")).href), import(pathToFileURL(resolve(zodAotRoot, "dist/core/pipeline.js")).href), import(pathToFileURL(resolve(zodAotRoot, "dist/cli/emitter.js")).href), ]); const schemas = await discoverSchemas(sourcePath, { cacheBust: true }); const compiled = compileSchemas(schemas, { mode: "inline" }); const content = generateCompiledFileContent(compiled, "./schema.source.js", { zodCompat: false, }); await writeFile(outputPath, content); const jiti = createJiti(import.meta.url, { moduleCache: false }); const generated = await jiti.import(outputPath); return generated.Schema as GeneratedSchema; } finally { await rm(tempDir, { recursive: true, force: true }); } } describe("WS outbound zod-aot validation", () => { it("applies defaults inside discriminated-union branches", async () => { const schema = await compileInlineSchema(` const SourceSchema = z.discriminatedUnion("type", [ z.object({ type: z.literal("with_default"), enabled: z.boolean().default(true), }), z.object({ type: z.literal("without_default"), label: z.string(), }), ]); `); expect(schema.safeParse({ type: "with_default" })).toMatchObject({ success: true, data: { type: "with_default", enabled: true }, }); }); it("routes tool-call-like status unions through the current sequential item union", async () => { const schema = await compileInlineSchema(` const ToolCallItemSchema = z.discriminatedUnion("status", [ z.object({ type: z.literal("tool_call"), status: z.literal("running"), callId: z.string() }), z.object({ type: z.literal("tool_call"), status: z.literal("completed"), callId: z.string(), output: z.string() }), z.object({ type: z.literal("tool_call"), status: z.literal("failed"), callId: z.string(), error: z.string() }), z.object({ type: z.literal("tool_call"), status: z.literal("canceled"), callId: z.string() }), ]); const TimelineItemSchema = z.union([ z.object({ type: z.literal("assistant_message"), text: z.string() }), ToolCallItemSchema, ]); const SourceSchema = z.object({ item: TimelineItemSchema, }); `); expect( schema.safeParse({ item: { type: "tool_call", status: "running", callId: "run" } }), ).toMatchObject({ success: true, data: { item: { type: "tool_call", status: "running", callId: "run" } }, }); expect( schema.safeParse({ item: { type: "tool_call", status: "completed", callId: "done", output: "ok" }, }), ).toMatchObject({ success: true, data: { item: { type: "tool_call", status: "completed", callId: "done", output: "ok" } }, }); expect( schema.safeParse({ item: { type: "tool_call", status: "failed", callId: "fail", error: "boom" }, }), ).toMatchObject({ success: true, data: { item: { type: "tool_call", status: "failed", callId: "fail", error: "boom" } }, }); expect( schema.safeParse({ item: { type: "tool_call", status: "canceled", callId: "stop" } }), ).toMatchObject({ success: true, data: { item: { type: "tool_call", status: "canceled", callId: "stop" } }, }); }); it("accepts a minimal valid envelope and rejects a corrupted envelope", () => { expect(GeneratedWSOutboundMessageSchema.safeParse({ type: "pong" }).success).toBe(true); expect(GeneratedWSOutboundMessageSchema.safeParse({ type: "not_a_message" }).success).toBe( false, ); }); it("emits runtime imports with .js extensions", async () => { const generated = await readFile(generatedWSOutboundPath, "utf8"); expect(generated).toContain('from "../../validation/ws-outbound-schema-metadata.js"'); }); });