Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"react-virtualized-auto-sizer": "^1.0.20",
"react-window": "^1.8.10",
"stainless": "workspace:*",
"zod": "^3.25.76",
"zod": "^4.3.6",
"zustand": "^4.4.7"
},
"devDependencies": {
Expand Down
4 changes: 3 additions & 1 deletion packages/client/src/codegen/generate-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ function nestEndpoints(
}

function zodToString(schema: ZodTypeAny) {
const { node } = zodToTs(schema, undefined, { nativeEnums: "union" });
// zod-to-ts v1 API: zodToTs(schema, identifier?, options?)
// Cast to any because zod/v3 types are structurally compatible at runtime
const { node } = zodToTs(schema as any, undefined, { nativeEnums: "union" });
const nodeString = printNode(node);
// This happens with large, lazily loaded zod types
return nodeString.replace(/\bIdentifier\b/g, "unknown");
Expand Down
2 changes: 1 addition & 1 deletion packages/prisma/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"dependencies": {
"lodash": "^4.17.21",
"stainless": "workspace:*",
"zod": "^3.25.76"
"zod": "^4.3.6"
},
"peerDependencies": {
"prisma": "^4.0.0"
Expand Down
8 changes: 5 additions & 3 deletions packages/prisma/src/prismaPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import {
import { includeSubPaths } from "./includeUtils";
import { isPlainObject } from "lodash";

declare module "zod" {
interface ZodType<Output, Def extends ZodTypeDef, Input = Output> {
// Module augmentation for zod/v3 (stainless re-exports zod/v3 types)
declare module "zod/v3" {
interface ZodType<Output, Def extends z.ZodTypeDef, Input = Output> {
/**
* Transforms the output value to fetch the Prisma model whose primary
* key is the input value. Throws if the primary key wasn't found.
Expand Down Expand Up @@ -79,7 +80,8 @@ z.ZodType.prototype.prismaModelLoader = function prismaModelLoader<
}
);
// tsc -b is generating spurious errors here...
return (result as any).openapi({ effectType: "input" }) as typeof result;
// Removed .openapi() call - zod-openapi v5 uses .meta() which isn't available in zod/v3
return result;
};

z.ZodType.prototype.prismaModel = function prismaModel<
Expand Down
4 changes: 2 additions & 2 deletions packages/stainless/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
"lodash": "^4.17.21",
"qs": "^6.11.2",
"ts-node": "^10.9.1",
"zod": "^3.25.76",
"zod-openapi": "github:stainless-api/zod-openapi#2.8.0",
"zod": "^4.3.6",
"zod-openapi": "^5.4.6",
"zod-validation-error": "^4.0.1"
}
}
7 changes: 5 additions & 2 deletions packages/stainless/src/openapiSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {
ZodOpenApiOperationObject,
ZodOpenApiPathsObject,
createDocument,
oas31,
} from "zod-openapi";
import type { OpenAPIObject } from "zod-openapi/lib-types/openapi3-ts/dist/oas31";
type OpenAPIObject = oas31.OpenAPIObject;
import { snakeCase } from "lodash";

function allModels(
Expand Down Expand Up @@ -87,7 +88,9 @@ export async function openapiSpec(
},
servers: [{ url: "v1" }],
components: {
schemas: models,
// Cast to any because zod/v3 types are structurally compatible with zod/v4
// at runtime, but TypeScript sees them as incompatible types
schemas: models as any,
},
paths,
});
Expand Down
3 changes: 2 additions & 1 deletion packages/stainless/src/stl.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as z from "./z";
import { openapiSpec } from "./openapiSpec";
import type { OpenAPIObject } from "zod-openapi/lib-types/openapi3-ts/dist/oas31";
import type { oas31 } from "zod-openapi";
type OpenAPIObject = oas31.OpenAPIObject;
import { fromZodError } from "zod-validation-error/v3";
import coerceParams from "./coerceParams";
export { openapiSpec };
Expand Down
29 changes: 12 additions & 17 deletions packages/stainless/src/z.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { extendZodWithOpenApi } from "zod-openapi";
// Use zod/v3 compatibility layer for easier migration
// zod-openapi v5 uses .meta() instead of .openapi(), no setup required
import "zod-openapi";
import {
z,
ParseContext,
SafeParseReturnType,
isValid,
ZodFirstPartyTypeKind,
} from "zod";
} from "zod/v3";
import { StlContext } from "./stl";
import { SelectTree } from "./parseSelect";
import { getSelects } from "./selects";
import { getIncludes, IncludablePaths } from "./includes";
import { pickBy } from "lodash/fp";
import { mapValues } from "lodash";

export * from "zod";
export * from "zod/v3";
export { selects, selectsSymbol, getSelects } from "./selects";
export {
includes,
Expand All @@ -22,21 +24,16 @@ export {
IncludablePaths,
} from "./includes";

/**
* TODO: try to come up with a better error message
* that you must import stl _before_ zod
* in any file that uses z.openapi(),
* including the file that calls stl.openapiSpec().
*/
extendZodWithOpenApi(z); // https://github.com/asteasolutions/zod-to-openapi#the-openapi-method
// zod-openapi v5 uses Zod's native .meta() method for OpenAPI metadata
// No setup required - importing "zod-openapi" above enables TypeScript types

//////////////////////////////////////////////////
//////////////////////////////////////////////////
////////////////// Metadata //////////////////////
//////////////////////////////////////////////////
//////////////////////////////////////////////////

declare module "zod" {
declare module "zod/v3" {
interface ZodType<Output, Def extends ZodTypeDef, Input = Output> {
withMetadata<M extends object>(metadata: M): ZodMetadata<this, M>;
}
Expand Down Expand Up @@ -228,7 +225,7 @@ export function extractDeepMetadata<
//////////////////////////////////////////////////
//////////////////////////////////////////////////

declare module "zod" {
declare module "zod/v3" {
interface ZodType<Output, Def extends ZodTypeDef, Input = Output> {
/**
* Marks this schema as includable via an `include[]` query param.
Expand Down Expand Up @@ -266,9 +263,7 @@ z.ZodType.prototype.includable = function includable(this: z.ZodTypeAny) {
return include && zodPathIsIncluded(path, include) ? data : undefined;
},
this.optional()
)
.openapi({ effectType: "input" })
.withMetadata({ stainless: { includable: true } });
).withMetadata({ stainless: { includable: true } });
};

export type isIncludable<T extends z.ZodTypeAny> = extractDeepMetadata<
Expand Down Expand Up @@ -301,7 +296,7 @@ function zodPathIsIncluded(
//////////////////////////////////////////////////
//////////////////////////////////////////////////

declare module "zod" {
declare module "zod/v3" {
// I don't know why TS errors without this, sigh
interface ZodTypeDef {}

Expand Down Expand Up @@ -438,7 +433,7 @@ z.ZodType.prototype.selectable = function selectable(this: z.ZodTypeAny) {
//////////////////////////////////////////////////
//////////////////////////////////////////////////

declare module "zod" {
declare module "zod/v3" {
interface ZodType<Output, Def extends ZodTypeDef, Input = Output> {
safeParseAsync(
data: unknown,
Expand Down
2 changes: 1 addition & 1 deletion packages/ts-to-zod/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@
"lodash": "^4.17.21",
"pkg-up": "~3.1.0",
"ts-morph": "^19.0.0",
"zod": "^3.25.76"
"zod": "^4.3.6"
}
}
51 changes: 25 additions & 26 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.