Skip to content

Commit 79f27b2

Browse files
Migrate to zod v4 (#398)
* feat: migrate from zod v3 to zod v4 * fix: fix depricated zod features * fix: fix comments --------- Co-authored-by: stasik1404 <skonashuk04@gmail.com>
1 parent 85982c2 commit 79f27b2

File tree

19 files changed

+2171
-2302
lines changed

19 files changed

+2171
-2302
lines changed

docs/api-reference/middlewares.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ import { validateMiddleware } from 'middlewares';
8686

8787
// Define your schema
8888
const schema = z.object({
89-
email: z.string().email('Email format is incorrect'),
89+
email: z.email('Email format is incorrect'),
9090
firstName: z.string().min(1, 'First name is required').max(100),
9191
lastName: z.string().min(1, 'Last name is required').max(100),
9292
age: z.number().int().positive().optional(),

docs/examples/api-public-docs/usage.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const EmptySchema = docsService.registerSchema('EmptyObject', z.object({}
4343
export const schema = z.object({
4444
firstName: z.string().min(1, 'Please enter First name').max(100),
4545
lastName: z.string().min(1, 'Please enter Last name').max(100),
46-
email: z.string().min(1, 'Please enter email').email('Email format is incorrect.'),
46+
email: z.email('Email format is incorrect.').min(1, 'Please enter email'),
4747
password: z.string().regex(
4848
PASSWORD_REGEXP,
4949
'The password must contain 6 or more characters with at least one letter (a-z) and one number (0-9).',

template/.cursor/rules/shared-packages.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ import { dbSchema } from './db.schema';
6767

6868
export const userSchema = dbSchema.extends({
6969
name: z.string().min(1),
70-
email: z.string().email(),
70+
email: z.email(),
7171
});
7272
```
7373

template/.cursor/rules/validation-schemas.mdc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ The middleware validates:
3434
- `ctx.request.body` - Request body
3535
- `ctx.request.files` - Uploaded formidable files
3636
- `ctx.query` - Query parameters
37-
- `ctx.params` - URL parameters
37+
- `ctx.params` - URL parameters
3838

3939
## Web/Frontend Validation
4040

@@ -81,7 +81,7 @@ import { dbSchema } from './db.schema';
8181
export const userSchema = dbSchema.extend({
8282
firstName: z.string(),
8383
lastName: z.string(),
84-
email: z.string().email(),
84+
email: z.email(),
8585
passwordHash: z.string().optional(),
8686
});
8787

@@ -102,13 +102,13 @@ export const updateUserSchema = userSchema
102102

103103
## Enums in Schemas
104104

105-
Enums are centralized in [packages/enums/src/](mdc:packages/enums/src/). Use `z.nativeEnum()` for validation:
105+
Enums are centralized in [packages/enums/src/](mdc:packages/enums/src/). Use `z.enum()` for validation:
106106

107107
```typescript
108108
import { TokenType } from 'enums';
109109

110110
export const tokenSchema = dbSchema.extend({
111-
type: z.nativeEnum(TokenType),
111+
type: z.enum(TokenType),
112112
});
113113
```
114114

template/apps/api/src/middlewares/validate.middleware.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { ZodError, ZodIssue, ZodSchema } from 'zod';
1+
import { ZodError, ZodType } from 'zod';
22

33
import { AppKoaContext, Next, ValidationErrors } from 'types';
44

55
const formatError = (zodError: ZodError): ValidationErrors => {
66
const errors: ValidationErrors = {};
77

8-
zodError.issues.forEach((error: ZodIssue) => {
8+
zodError.issues.forEach((error) => {
99
const key = error.path.join('.');
1010

1111
if (!errors[key]) {
@@ -18,7 +18,7 @@ const formatError = (zodError: ZodError): ValidationErrors => {
1818
return errors;
1919
};
2020

21-
const validate = (schema: ZodSchema) => async (ctx: AppKoaContext, next: Next) => {
21+
const validate = (schema: ZodType) => async (ctx: AppKoaContext, next: Next) => {
2222
const result = await schema.safeParseAsync({
2323
...ctx.request.body,
2424
...ctx.request.files,
@@ -28,7 +28,7 @@ const validate = (schema: ZodSchema) => async (ctx: AppKoaContext, next: Next) =
2828

2929
if (!result.success) ctx.throw(400, { clientErrors: formatError(result.error) });
3030

31-
ctx.validatedData = result.data;
31+
ctx.validatedData = result.data as object;
3232

3333
await next();
3434
};

template/apps/api/src/migrator/migration-log/migration-log.schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const schema = z.object({
99
error: z.string().optional(),
1010
errorStack: z.string().optional(),
1111
duration: z.string().optional(),
12-
migrationVersion: z.number(),
12+
migrationVersion: z.int(),
1313

1414
createdOn: z.date().optional(),
1515
updatedOn: z.date().optional(),

template/apps/api/src/migrator/migration-version/migration-version.schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { z } from 'zod';
33
const schema = z.object({
44
_id: z.string(),
55

6-
version: z.number(),
6+
version: z.int(),
77

88
createdOn: z.date().optional(),
99
updatedOn: z.date().optional(),

template/apps/api/src/resources/user/actions/list.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const schema = paginationSchema.extend({
2424
lastName: z.enum(['asc', 'desc']).optional(),
2525
createdOn: z.enum(['asc', 'desc']).default('asc'),
2626
})
27-
.default({}),
27+
.default({ createdOn: 'asc' }),
2828
});
2929

3030
type ValidatedData = z.infer<typeof schema>;

template/apps/api/src/services/google/google.service.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ import { User } from 'types';
1919

2020
const googleUserInfoSchema = z.object({
2121
sub: z.string().describe('Unique Google user ID'),
22-
email: z.string().email().describe('User email'),
22+
email: z.email().describe('User email'),
2323
email_verified: z.boolean().describe('Email verification status'),
2424
name: z.string().describe('User full name'),
25-
picture: z.string().url().describe('Profile picture URL').optional(),
25+
picture: z.url().describe('Profile picture URL').optional(),
2626
given_name: z.string().describe('First name'),
2727
family_name: z.string().describe('Last name'),
2828
});
@@ -34,7 +34,7 @@ const googleCallbackParamsSchema = z
3434
storedState: z.string(),
3535
codeVerifier: z.string(),
3636
})
37-
.refine((data) => data.state === data.storedState, { message: 'OAuth state mismatch' });
37+
.refine((data) => data.state === data.storedState, { error: 'OAuth state mismatch' });
3838

3939
export const googleClient = new Google(
4040
config.GOOGLE_CLIENT_ID!,
@@ -132,7 +132,7 @@ export const validateCallback = async (params: {
132132
const errorMessage = 'Failed to validate Google authentication data.';
133133

134134
logger.error(`[Google OAuth] ${errorMessage}`);
135-
logger.error(parsedParams.error.flatten().fieldErrors);
135+
logger.error(z.treeifyError(parsedParams.error).errors);
136136

137137
throw new Error(errorMessage);
138138
}
@@ -165,7 +165,7 @@ export const validateCallback = async (params: {
165165
const errorMessage = 'Failed to validate Google user info';
166166

167167
logger.error(`[Google OAuth] ${errorMessage}`);
168-
logger.error(parsedUserInfo.error.flatten().fieldErrors);
168+
logger.error(z.treeifyError(parsedUserInfo.error).errors);
169169

170170
throw new Error(errorMessage);
171171
}

template/apps/api/src/utils/config.util.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import process from 'node:process';
2-
import { ZodSchema } from 'zod';
2+
import { z, ZodType } from 'zod';
33

4-
const validateConfig = <T>(schema: ZodSchema): T => {
4+
const validateConfig = <T>(schema: ZodType<T>): T => {
55
const parsed = schema.safeParse(process.env);
66

77
if (!parsed.success) {
8-
// Allow the use of a console instance for logging before launching the application.
9-
console.error('❌ Invalid environment variables:', parsed.error.flatten().fieldErrors);
8+
console.error('❌ Invalid environment variables ❌');
9+
console.error(z.prettifyError(parsed.error));
1010

1111
throw new Error('Invalid environment variables');
1212
}

0 commit comments

Comments
 (0)