chore(server): update zod to 4.4.3 and nestjs-zod to 5.5.0 (#30532)

This commit is contained in:
Timon
2026-08-24 10:59:22 +02:00
committed by GitHub
parent cbf5d83a69
commit 2feb889b9c
8 changed files with 39 additions and 26 deletions
+2 -2
View File
@@ -94,7 +94,7 @@
"nestjs-cls": "^6.0.0",
"nestjs-kysely": "3.1.2",
"nestjs-otel": "^8.0.0",
"nestjs-zod": "^5.3.0",
"nestjs-zod": "^5.5.0",
"nodemailer": "^9.0.0",
"openid-client": "^6.3.3",
"pg": "^8.11.3",
@@ -116,7 +116,7 @@
"ua-parser-js": "^2.0.0",
"uuid": "^14.0.0",
"validator": "^13.12.0",
"zod": "4.3.6"
"zod": "4.4.3"
},
"devDependencies": {
"@eslint/js": "^10.0.0",
+10 -3
View File
@@ -1,7 +1,7 @@
import { createZodDto } from 'nestjs-zod';
import { HistoryBuilder } from 'src/decorators';
import { AssetMetadataUpsertItemSchema } from 'src/dtos/asset.dto';
import { AssetVisibilitySchema } from 'src/enum';
import { ApiCustomExtension, AssetVisibilitySchema } from 'src/enum';
import { isoDatetimeToDate, JsonParsed, stringToBool } from 'src/validation';
import z from 'zod';
@@ -40,8 +40,15 @@ const AssetMediaBaseSchema = z.object({
fileModifiedAt: isoDatetimeToDate.describe('File modification date'),
duration: z.coerce.number().int().min(0).optional().describe('Duration in milliseconds (for videos)'),
filename: z.string().optional().describe('Filename'),
/** The properties below are added to correctly generate the API docs and client SDKs. Validation should be handled in the controller. */
[UploadFieldName.ASSET_DATA]: z.any().describe('Asset file data').meta({ type: 'string', format: 'binary' }),
/**
* The properties below are added to correctly generate the API docs and client SDKs. Validation should be handled
* in the controller. File parts never reach the request body, so they must be optional here
*/
[UploadFieldName.ASSET_DATA]: z
.any()
.optional()
.describe('Asset file data')
.meta({ type: 'string', format: 'binary', [ApiCustomExtension.Required]: true }),
});
const AssetMediaCreateSchema = AssetMediaBaseSchema.extend({
+6 -9
View File
@@ -36,15 +36,12 @@ import z from 'zod';
const { Admin, User, Public } = ConfigVisibility;
const configBool = z
.preprocess((val) => {
if (val === 'true') {
return true;
}
if (val === 'false') {
return false;
}
return val;
}, z.boolean())
.preprocess(
(val) => z.stringbool({ truthy: ['true'], falsy: ['false'], case: 'sensitive' }).safeParse(val).data ?? val,
z.boolean(),
)
.nonoptional()
.meta({ type: 'boolean' });
const cronExpressionSchema = z
+1
View File
@@ -31,6 +31,7 @@ const DownloadArchiveSchema = z
// which would limit this DTO to a maximum of 1000 assets.
assetIds: z
.preprocess((val) => (typeof val === 'string' ? val.split(',') : val), z.array(z.uuidv4()))
.nonoptional()
.describe('Asset IDs'),
edited: z
.preprocess((val) => {
+1
View File
@@ -603,6 +603,7 @@ export enum ApiCustomExtension {
AdminOnly = 'x-immich-admin-only',
History = 'x-immich-history',
State = 'x-immich-state',
Required = 'x-immich-required',
}
export enum MetadataKey {
+10
View File
@@ -211,6 +211,16 @@ const patchOpenAPI = (document: OpenAPIObject) => {
for (const schema of Object.values(schemas)) {
delete (schema as Record<string, unknown>).id;
// documents a property as required even though it is optional during body validation
for (const [key, value] of Object.entries(schema.properties ?? {})) {
if (!(ApiCustomExtension.Required in value)) {
continue;
}
delete (value as Record<string, unknown>)[ApiCustomExtension.Required];
(schema.required ??= []).push(key);
}
}
document.components.schemas = sortKeys(schemas);