From b8053a12a6bf6cc1a142c3bcdce6ade341acbd05 Mon Sep 17 00:00:00 2001 From: Nathan Standiford Date: Fri, 22 Aug 2025 19:51:28 +0000 Subject: [PATCH 1/3] Adds `zod` v4 support for `serde`. #573 Adds `zod` v4.0.0 support while maintaining backwards compatibility with `v3` per the Zod guide: https://zod.dev/library-authors. --- package-lock.json | 66 ++++++++++++------- packages/restate-sdk-zod/README.md | 9 +++ packages/restate-sdk-zod/package.json | 9 ++- packages/restate-sdk-zod/src/serde_api.ts | 50 +++++++++----- .../restate-sdk-zod/test/serde_api.test.ts | 65 ++++++++++++++++++ 5 files changed, 155 insertions(+), 44 deletions(-) create mode 100644 packages/restate-sdk-zod/test/serde_api.test.ts diff --git a/package-lock.json b/package-lock.json index faf23636..18642616 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "root", - "version": "1.8.0", + "version": "1.8.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "root", - "version": "1.8.0", + "version": "1.8.3", "license": "MIT", "workspaces": [ "packages/restate-sdk-core", @@ -10228,7 +10228,9 @@ "version": "3.24.2", "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -10237,6 +10239,7 @@ "version": "3.24.3", "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.3.tgz", "integrity": "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A==", + "dev": true, "license": "ISC", "peerDependencies": { "zod": "^3.24.1" @@ -10244,11 +10247,11 @@ }, "packages/restate-e2e-services": { "name": "@restatedev/restate-e2e-services", - "version": "1.8.0", + "version": "1.8.3", "license": "MIT", "dependencies": { - "@restatedev/restate-sdk": "^1.8.0", - "@restatedev/restate-sdk-clients": "^1.8.0", + "@restatedev/restate-sdk": "^1.8.3", + "@restatedev/restate-sdk-clients": "^1.8.3", "heapdump": "^0.3.15", "uuid": "^9.0.0" }, @@ -10264,10 +10267,10 @@ }, "packages/restate-sdk": { "name": "@restatedev/restate-sdk", - "version": "1.8.0", + "version": "1.8.3", "license": "MIT", "dependencies": { - "@restatedev/restate-sdk-core": "^1.8.0" + "@restatedev/restate-sdk-core": "^1.8.3" }, "devDependencies": { "@types/aws-lambda": "^8.10.115" @@ -10278,10 +10281,10 @@ }, "packages/restate-sdk-clients": { "name": "@restatedev/restate-sdk-clients", - "version": "1.8.0", + "version": "1.8.3", "license": "MIT", "dependencies": { - "@restatedev/restate-sdk-core": "^1.8.0" + "@restatedev/restate-sdk-core": "^1.8.3" }, "engines": { "node": ">= 18.13" @@ -10289,10 +10292,10 @@ }, "packages/restate-sdk-cloudflare-workers": { "name": "@restatedev/restate-sdk-cloudflare-workers", - "version": "1.8.0", + "version": "1.8.3", "license": "MIT", "dependencies": { - "@restatedev/restate-sdk-core": "^1.8.0" + "@restatedev/restate-sdk-core": "^1.8.3" }, "devDependencies": { "@types/aws-lambda": "^8.10.115" @@ -10303,7 +10306,7 @@ }, "packages/restate-sdk-core": { "name": "@restatedev/restate-sdk-core", - "version": "1.8.0", + "version": "1.8.3", "license": "MIT", "engines": { "node": ">= 18.13" @@ -10311,14 +10314,14 @@ }, "packages/restate-sdk-examples": { "name": "@restatedev/restate-sdk-examples", - "version": "1.8.0", + "version": "1.8.3", "license": "MIT", "dependencies": { - "@restatedev/restate-sdk": "^1.8.0", - "@restatedev/restate-sdk-clients": "^1.8.0" + "@restatedev/restate-sdk": "^1.8.3", + "@restatedev/restate-sdk-clients": "^1.8.3" }, "devDependencies": { - "@restatedev/restate-sdk-testcontainers": "^1.8.0", + "@restatedev/restate-sdk-testcontainers": "^1.8.3", "tsx": "^4.15.7" }, "engines": { @@ -10327,11 +10330,11 @@ }, "packages/restate-sdk-testcontainers": { "name": "@restatedev/restate-sdk-testcontainers", - "version": "1.8.0", + "version": "1.8.3", "license": "MIT", "dependencies": { - "@restatedev/restate-sdk": "^1.8.0", - "@restatedev/restate-sdk-clients": "^1.8.0", + "@restatedev/restate-sdk": "^1.8.3", + "@restatedev/restate-sdk-clients": "^1.8.3", "apache-arrow": "^18.0.0", "testcontainers": "^10.24.1" }, @@ -10470,17 +10473,30 @@ }, "packages/restate-sdk-zod": { "name": "@restatedev/restate-sdk-zod", - "version": "1.8.0", + "version": "1.8.3", "license": "MIT", - "dependencies": { - "zod": "^3.24.1", - "zod-to-json-schema": "3.24.3" - }, "devDependencies": { - "@restatedev/restate-sdk-core": "^1.8.0" + "@restatedev/restate-sdk-core": "^1.8.3", + "vitest": "^3.0.9", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "3.24.3" }, "engines": { "node": ">= 18.13" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "3.24.3" + } + }, + "packages/restate-sdk-zod/node_modules/zod": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.0.17.tgz", + "integrity": "sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" } } } diff --git a/packages/restate-sdk-zod/README.md b/packages/restate-sdk-zod/README.md index 99cddda0..475c8318 100644 --- a/packages/restate-sdk-zod/README.md +++ b/packages/restate-sdk-zod/README.md @@ -55,6 +55,15 @@ To use this library, add the dependency to your project: ```shell npm install --save-dev @restatedev/restate-sdk-zod +npm install zod # optional if zod isn't already installed +``` + +# Zod v3 Users +As a minimum requirement, `zod` must be at `v3.25.0`. Also, `zod-to-json-schema` is required. +Add the following additional dependencies to your project: + +```shell +npm install zod-to-json-schema zod@^3.25.0 ``` ## Versions diff --git a/packages/restate-sdk-zod/package.json b/packages/restate-sdk-zod/package.json index 94971f4d..bc05611f 100644 --- a/packages/restate-sdk-zod/package.json +++ b/packages/restate-sdk-zod/package.json @@ -34,10 +34,13 @@ "dist" ], "devDependencies": { - "@restatedev/restate-sdk-core": "^1.8.3" + "@restatedev/restate-sdk-core": "^1.8.3", + "vitest": "^3.0.9", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "3.24.3" }, - "dependencies": { - "zod": "^3.24.1", + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "3.24.3" }, "scripts": { diff --git a/packages/restate-sdk-zod/src/serde_api.ts b/packages/restate-sdk-zod/src/serde_api.ts index ca4e5393..e5366771 100644 --- a/packages/restate-sdk-zod/src/serde_api.ts +++ b/packages/restate-sdk-zod/src/serde_api.ts @@ -17,51 +17,69 @@ import type { Serde } from "@restatedev/restate-sdk-core"; -import { z, ZodVoid } from "zod"; +import * as z3 from "zod/v3"; +import * as z4 from "zod/v4/core"; import { zodToJsonSchema } from "zod-to-json-schema"; export type { Serde } from "@restatedev/restate-sdk-core"; -class ZodSerde implements Serde> { +type ZodType = z3.ZodTypeAny | z4.$ZodType; +type output = T extends z3.ZodTypeAny ? z3.infer : z4.infer; + +class ZodSerde implements Serde> { contentType? = "application/json"; jsonSchema?: object | undefined; constructor(private readonly schema: T) { - this.jsonSchema = zodToJsonSchema(schema); - if (schema instanceof ZodVoid || schema instanceof z.ZodUndefined) { - this.contentType = undefined; - } + if ("_zod" in schema) { + this.jsonSchema = z4.toJSONSchema(schema); + } else if (schema instanceof z3.ZodType) { + // zod3 fallback + this.jsonSchema = zodToJsonSchema(schema as never); + } else { + this.jsonSchema = undefined; + } + + if (schema instanceof z3.ZodVoid + || schema instanceof z3.ZodUndefined + || schema instanceof z4.$ZodVoid + || schema instanceof z4.$ZodUndefined) { + this.contentType = undefined; + } } - serialize(value: T): Uint8Array { + serialize(value: output): Uint8Array { if (value === undefined) { return new Uint8Array(0); } return new TextEncoder().encode(JSON.stringify(value)); } - deserialize(data: Uint8Array): T { + deserialize(data: Uint8Array): output { const js = data.length === 0 ? undefined : JSON.parse(new TextDecoder().decode(data)); - - const res = this.schema.safeParse(js); - if (res.success) { - return res.data; + if ('safeParse' in this.schema && typeof this.schema.safeParse === 'function') { + const res = this.schema.safeParse(js); + if (res.success) { + return res.data; + } + throw res.error; + } else { + throw new TypeError("Unsupported data type. Expected 'safeParse'."); } - throw res.error; } } export namespace serde { /** - * A Zod based serde. + * A Zod-based serde. * - * @param schema the zod type + * @param zodType the zod type * @returns a serde that will validate the data with the zod schema */ - export const zod = (zodType: T): Serde> => { + export const zod = (zodType: T): Serde> => { return new ZodSerde(zodType); }; } diff --git a/packages/restate-sdk-zod/test/serde_api.test.ts b/packages/restate-sdk-zod/test/serde_api.test.ts new file mode 100644 index 00000000..5c811cce --- /dev/null +++ b/packages/restate-sdk-zod/test/serde_api.test.ts @@ -0,0 +1,65 @@ +import { describe, expect, it } from "vitest"; +import * as z3 from "zod/v3"; +import * as z4 from "zod/v4"; +import { serde } from "../src/serde_api.js"; +import { zodToJsonSchema } from "zod-to-json-schema"; + +const validData = { + id: 1, + name: "test", + isActive: true, +} +const validDataSerialized = new TextEncoder().encode(JSON.stringify(validData)); +const invalidData = { + id: -1, // not positive + name: "a", // less than 3 characters + isActive: "not a boolean", +} +const invalidDataSerialized = new TextEncoder().encode(JSON.stringify(invalidData)); + + +const z3Schema = z3.object({ + id: z3.number().int().positive(), + name: z3.string().min(3, { message: "Name must be at least 3 characters long" }), + isActive: z3.boolean(), +}); +const z3Serde = serde.zod(z3Schema); +const z3JsonSchema = zodToJsonSchema(z3Schema as never); + +const z4Schema = z4.object({ + id: z4.number().int().positive(), + name: z4.string().min(3, { message: "Name must be at least 3 characters long" }), + isActive: z4.boolean(), +}); +const z4Serde = serde.zod(z4Schema); +const z4JsonSchema = z4.toJSONSchema(z4Schema); + +describe('serde_api', () => { + describe.each([ + {ver: 'v3', srd: z3Serde, jsonSchema: z3JsonSchema}, + {ver: 'v4', srd: z4Serde, jsonSchema: z4JsonSchema}, + ])("zod $ver", ({ srd, jsonSchema }) => { + describe('constructor', () => { + it('converts a valid schema to json', () => { + expect(srd.jsonSchema).not.to.be.null; + expect(srd.jsonSchema).to.deep.equal(jsonSchema); + }); + }) + describe('serialize', () => { + it('serializes a valid object', () => { + expect(srd.serialize(validData)).to.deep.equal(validDataSerialized); + }); + it('gives an empty response for undefined', () => { + expect(srd.serialize(undefined)).to.be.empty; + }) + }) + describe('deserialize', () => { + it('deserializes a valid object', () => { + expect(srd.deserialize(validDataSerialized)).to.deep.equal(validData); + }); + it('throws an error on an invalid object', () => { + expect(() => srd.deserialize(invalidDataSerialized)).throws(); + }); + }); + }); +}); \ No newline at end of file From f4447eb1cdc0c4b48b6fe65a20e05762f3f74e05 Mon Sep 17 00:00:00 2001 From: Nathan Standiford Date: Wed, 27 Aug 2025 22:38:32 +0000 Subject: [PATCH 2/3] Fixed test errors by bumping zod dep to v4. --- package-lock.json | 31 ++++++++-------------- package.json | 3 ++- packages/restate-sdk-examples/package.json | 5 ++-- packages/restate-sdk-zod/README.md | 4 +-- packages/restate-sdk-zod/package.json | 4 +-- 5 files changed, 20 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 18642616..e886d29a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,8 @@ "typescript": "^5.4.5", "vitest": "^3.0.9", "wasm-pack": "^0.0.0", - "wasm-pack-inline": "^0.1.2" + "wasm-pack-inline": "^0.1.2", + "zod": "^4.1.4" }, "engines": { "node": ">= 18.13" @@ -10225,20 +10226,19 @@ } }, "node_modules/zod": { - "version": "3.24.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", - "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.4.tgz", + "integrity": "sha512-2YqJuWkU6IIK9qcE4k1lLLhyZ6zFw7XVRdQGpV97jEIZwTrscUw+DY31Xczd8nwaoksyJUIxCojZXwckJovWxA==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zod-to-json-schema": { - "version": "3.24.3", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.3.tgz", - "integrity": "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A==", + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", + "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", "dev": true, "license": "ISC", "peerDependencies": { @@ -10321,6 +10321,7 @@ "@restatedev/restate-sdk-clients": "^1.8.3" }, "devDependencies": { + "@restatedev/restate-sdk-core": "^1.8.3", "@restatedev/restate-sdk-testcontainers": "^1.8.3", "tsx": "^4.15.7" }, @@ -10479,24 +10480,14 @@ "@restatedev/restate-sdk-core": "^1.8.3", "vitest": "^3.0.9", "zod": "^3.25.0 || ^4.0.0", - "zod-to-json-schema": "3.24.3" + "zod-to-json-schema": "^3.24.6" }, "engines": { "node": ">= 18.13" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0", - "zod-to-json-schema": "3.24.3" - } - }, - "packages/restate-sdk-zod/node_modules/zod": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.0.17.tgz", - "integrity": "sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "zod-to-json-schema": "^3.24.6" } } } diff --git a/package.json b/package.json index 058cc70d..edeb8cd7 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,8 @@ "typescript": "^5.4.5", "vitest": "^3.0.9", "wasm-pack": "^0.0.0", - "wasm-pack-inline": "^0.1.2" + "wasm-pack-inline": "^0.1.2", + "zod": "^4.1.4" }, "engines": { "node": ">= 18.13" diff --git a/packages/restate-sdk-examples/package.json b/packages/restate-sdk-examples/package.json index b7e97c74..94f5cc37 100644 --- a/packages/restate-sdk-examples/package.json +++ b/packages/restate-sdk-examples/package.json @@ -40,8 +40,9 @@ "@restatedev/restate-sdk-clients": "^1.8.3" }, "devDependencies": { - "tsx": "^4.15.7", - "@restatedev/restate-sdk-testcontainers": "^1.8.3" + "@restatedev/restate-sdk-core": "^1.8.3", + "@restatedev/restate-sdk-testcontainers": "^1.8.3", + "tsx": "^4.15.7" }, "engines": { "node": ">= 18.13" diff --git a/packages/restate-sdk-zod/README.md b/packages/restate-sdk-zod/README.md index 475c8318..ef5cca5d 100644 --- a/packages/restate-sdk-zod/README.md +++ b/packages/restate-sdk-zod/README.md @@ -59,8 +59,8 @@ npm install zod # optional if zod isn't already installed ``` # Zod v3 Users -As a minimum requirement, `zod` must be at `v3.25.0`. Also, `zod-to-json-schema` is required. -Add the following additional dependencies to your project: +As a minimum requirement, `zod` must be at `v3.25.0`. This is a non-breaking release for existing `zod v3` users. +Also, `zod-to-json-schema` is required. Add the following additional dependencies to your project: ```shell npm install zod-to-json-schema zod@^3.25.0 diff --git a/packages/restate-sdk-zod/package.json b/packages/restate-sdk-zod/package.json index bc05611f..9afeea04 100644 --- a/packages/restate-sdk-zod/package.json +++ b/packages/restate-sdk-zod/package.json @@ -37,11 +37,11 @@ "@restatedev/restate-sdk-core": "^1.8.3", "vitest": "^3.0.9", "zod": "^3.25.0 || ^4.0.0", - "zod-to-json-schema": "3.24.3" + "zod-to-json-schema": "^3.24.6" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0", - "zod-to-json-schema": "3.24.3" + "zod-to-json-schema": "^3.24.6" }, "scripts": { "api:extract": "api-extractor run --local", From 6b861f1c27c717bb9dc72e4242eb89de3a1cb34a Mon Sep 17 00:00:00 2001 From: Nathan Standiford Date: Thu, 28 Aug 2025 18:45:51 +0000 Subject: [PATCH 3/3] Support for v3 Zod objects. --- packages/restate-sdk-zod/src/serde_api.ts | 17 ++- .../restate-sdk-zod/test/serde_api.test.ts | 103 ++++++++++++------ 2 files changed, 85 insertions(+), 35 deletions(-) diff --git a/packages/restate-sdk-zod/src/serde_api.ts b/packages/restate-sdk-zod/src/serde_api.ts index e5366771..7b043240 100644 --- a/packages/restate-sdk-zod/src/serde_api.ts +++ b/packages/restate-sdk-zod/src/serde_api.ts @@ -23,10 +23,17 @@ import { zodToJsonSchema } from "zod-to-json-schema"; export type { Serde } from "@restatedev/restate-sdk-core"; -type ZodType = z3.ZodTypeAny | z4.$ZodType; -type output = T extends z3.ZodTypeAny ? z3.infer : z4.infer; +export type V3ZodObjectOrWrapped = + | z3.ZodObject + | z3.ZodEffects>; -class ZodSerde implements Serde> { +type ZodType = z3.ZodTypeAny | z4.$ZodType +type ZodObject = V3ZodObjectOrWrapped | z4.$ZodObject + + +type output = T extends z3.ZodTypeAny | V3ZodObjectOrWrapped ? z3.infer : z4.infer; + +class ZodSerde implements Serde> { contentType? = "application/json"; jsonSchema?: object | undefined; @@ -48,6 +55,8 @@ class ZodSerde implements Serde> { } } + + serialize(value: output): Uint8Array { if (value === undefined) { return new Uint8Array(0); @@ -79,7 +88,7 @@ export namespace serde { * @param zodType the zod type * @returns a serde that will validate the data with the zod schema */ - export const zod = (zodType: T): Serde> => { + export const zod = (zodType: T): Serde> => { return new ZodSerde(zodType); }; } diff --git a/packages/restate-sdk-zod/test/serde_api.test.ts b/packages/restate-sdk-zod/test/serde_api.test.ts index 5c811cce..5b6d6683 100644 --- a/packages/restate-sdk-zod/test/serde_api.test.ts +++ b/packages/restate-sdk-zod/test/serde_api.test.ts @@ -1,44 +1,85 @@ -import { describe, expect, it } from "vitest"; +import {describe, expect, it} from "vitest"; import * as z3 from "zod/v3"; import * as z4 from "zod/v4"; import { serde } from "../src/serde_api.js"; import { zodToJsonSchema } from "zod-to-json-schema"; -const validData = { - id: 1, - name: "test", - isActive: true, -} -const validDataSerialized = new TextEncoder().encode(JSON.stringify(validData)); -const invalidData = { - id: -1, // not positive - name: "a", // less than 3 characters - isActive: "not a boolean", -} -const invalidDataSerialized = new TextEncoder().encode(JSON.stringify(invalidData)); +/* eslint-disable @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access */ -const z3Schema = z3.object({ - id: z3.number().int().positive(), - name: z3.string().min(3, { message: "Name must be at least 3 characters long" }), - isActive: z3.boolean(), -}); -const z3Serde = serde.zod(z3Schema); -const z3JsonSchema = zodToJsonSchema(z3Schema as never); +const typeTestData = { + name: "Type Test", + validData: { + id: 1, + name: "test", + isActive: true, + }, + invalidData: { + id: -1, // not positive + name: "a", // less than 3 characters + isActive: "not a boolean", + }, +}; + +const z3TypeTestData = { + ...typeTestData, + name: `v3 ${typeTestData.name}`, + zodSchema: z3.object({ + id: z3.number().int().positive(), + name: z3.string().min(3, { message: "Name must be at least 3 characters long" }), + isActive: z3.boolean(), + }), + jsonSchema: undefined, +}; +z3TypeTestData.jsonSchema = zodToJsonSchema(z3TypeTestData.zodSchema as never) + +const z4TypeTestData = { + ...typeTestData, + name: `v4 ${typeTestData.name}`, + zodSchema: z4.object({ + id: z4.number().int().positive(), + name: z4.string().min(3, { message: "Name must be at least 3 characters long" }), + isActive: z4.boolean(), + }), + jsonSchema: undefined, +}; +z4TypeTestData.jsonSchema = z4.toJSONSchema(z4TypeTestData.zodSchema); + + +const stringTestData = { + name: "stringTest", + validData: "just a string", + invalidData: -1, +}; + +const z3StringTestData = { + ...stringTestData, + name: `v3 ${stringTestData.name}`, + zodSchema: z3.string(), + jsonSchema: undefined, +}; +z3StringTestData.jsonSchema = zodToJsonSchema(z3StringTestData.zodSchema as never); + +const z4StringTestData = { + ...stringTestData, + name: `v4 ${stringTestData.name}`, + zodSchema: z4.string(), + jsonSchema: undefined, +}; +z4StringTestData.jsonSchema = z4.toJSONSchema(z4StringTestData.zodSchema); -const z4Schema = z4.object({ - id: z4.number().int().positive(), - name: z4.string().min(3, { message: "Name must be at least 3 characters long" }), - isActive: z4.boolean(), -}); -const z4Serde = serde.zod(z4Schema); -const z4JsonSchema = z4.toJSONSchema(z4Schema); describe('serde_api', () => { describe.each([ - {ver: 'v3', srd: z3Serde, jsonSchema: z3JsonSchema}, - {ver: 'v4', srd: z4Serde, jsonSchema: z4JsonSchema}, - ])("zod $ver", ({ srd, jsonSchema }) => { + z3TypeTestData, + z4TypeTestData, + z3StringTestData, + z4StringTestData, + ])("zod $name", ({ zodSchema, jsonSchema, validData, invalidData }) => { + const validDataSerialized = new TextEncoder().encode(JSON.stringify(validData)); + const invalidDataSerialized = new TextEncoder().encode(JSON.stringify(invalidData)) + const srd = serde.zod(zodSchema); + describe('constructor', () => { it('converts a valid schema to json', () => { expect(srd.jsonSchema).not.to.be.null; @@ -55,7 +96,7 @@ describe('serde_api', () => { }) describe('deserialize', () => { it('deserializes a valid object', () => { - expect(srd.deserialize(validDataSerialized)).to.deep.equal(validData); + expect(srd.deserialize(new TextEncoder().encode(JSON.stringify(validData)))).to.deep.equal(validData); }); it('throws an error on an invalid object', () => { expect(() => srd.deserialize(invalidDataSerialized)).throws();