mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
refactor!: migrate class-validator to zod (#26597)
This commit is contained in:
@@ -318,7 +318,7 @@ export class AssetRepository {
|
||||
.execute();
|
||||
}
|
||||
|
||||
upsertMetadata(id: string, items: Array<{ key: string; value: object }>) {
|
||||
upsertMetadata(id: string, items: Array<{ key: string; value: Record<string, unknown> }>) {
|
||||
if (items.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ describe('getEnv', () => {
|
||||
describe('IMMICH_MEDIA_LOCATION', () => {
|
||||
it('should throw an error for relative paths', () => {
|
||||
process.env.IMMICH_MEDIA_LOCATION = './relative/path';
|
||||
expect(() => getEnv()).toThrowError('IMMICH_MEDIA_LOCATION must be an absolute path');
|
||||
expect(() => getEnv()).toThrowError('[IMMICH_MEDIA_LOCATION] Must be an absolute path');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -98,7 +98,7 @@ describe('getEnv', () => {
|
||||
|
||||
it('should throw an error for invalid value', () => {
|
||||
process.env.IMMICH_ALLOW_EXTERNAL_PLUGINS = 'invalid';
|
||||
expect(() => getEnv()).toThrowError('IMMICH_ALLOW_EXTERNAL_PLUGINS must be a boolean value');
|
||||
expect(() => getEnv()).toThrowError('[IMMICH_ALLOW_EXTERNAL_PLUGINS] Invalid option: expected one of');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -111,7 +111,7 @@ describe('getEnv', () => {
|
||||
|
||||
it('should throw an error for invalid value', () => {
|
||||
process.env.IMMICH_ALLOW_SETUP = 'invalid';
|
||||
expect(() => getEnv()).toThrowError('IMMICH_ALLOW_SETUP must be a boolean value');
|
||||
expect(() => getEnv()).toThrowError('[IMMICH_ALLOW_SETUP] Invalid option: expected one of');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,7 +134,7 @@ describe('getEnv', () => {
|
||||
|
||||
it('should validate DB_SSL_MODE', () => {
|
||||
process.env.DB_SSL_MODE = 'invalid';
|
||||
expect(() => getEnv()).toThrowError('DB_SSL_MODE must be one of the following values:');
|
||||
expect(() => getEnv()).toThrow(/\[DB_SSL_MODE\] Invalid option: expected one of/);
|
||||
});
|
||||
|
||||
it('should accept a valid DB_SSL_MODE', () => {
|
||||
@@ -278,7 +278,7 @@ describe('getEnv', () => {
|
||||
|
||||
it('should reject invalid trusted proxies', () => {
|
||||
process.env.IMMICH_TRUSTED_PROXIES = '10.1';
|
||||
expect(() => getEnv()).toThrow('IMMICH_TRUSTED_PROXIES must be an ip address, or ip address range');
|
||||
expect(() => getEnv()).toThrow('[IMMICH_TRUSTED_PROXIES] Must be an ip address or ip address range');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ import { DatabaseConnectionParams } from '@immich/sql-tools';
|
||||
import { RegisterQueueOptions } from '@nestjs/bullmq';
|
||||
import { Inject, Injectable, Optional } from '@nestjs/common';
|
||||
import { QueueOptions } from 'bullmq';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { validateSync } from 'class-validator';
|
||||
import { Request, Response } from 'express';
|
||||
import { HelmetOptions } from 'helmet';
|
||||
import { RedisOptions } from 'ioredis';
|
||||
@@ -13,7 +11,7 @@ import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { citiesFile, excludePaths, IWorker } from 'src/constants';
|
||||
import { Telemetry } from 'src/decorators';
|
||||
import { EnvDto } from 'src/dtos/env.dto';
|
||||
import { EnvSchema } from 'src/dtos/env.dto';
|
||||
import {
|
||||
DatabaseExtension,
|
||||
ImmichEnvironment,
|
||||
@@ -173,15 +171,16 @@ const resolveHelmetFile = (helmetFile: 'true' | 'false' | string | undefined) =>
|
||||
};
|
||||
|
||||
const getEnv = (): EnvData => {
|
||||
const dto = plainToInstance(EnvDto, process.env);
|
||||
const errors = validateSync(dto);
|
||||
if (errors.length > 0) {
|
||||
const messages = [`Invalid environment variables: `];
|
||||
for (const error of errors) {
|
||||
messages.push(` - ${error.property}=${error.value} (${Object.values(error.constraints || {}).join(', ')})`);
|
||||
const parseResult = EnvSchema.safeParse(process.env);
|
||||
if (!parseResult.success) {
|
||||
const messages = ['Invalid environment variables: '];
|
||||
for (const issue of parseResult.error.issues) {
|
||||
const path = issue.path.join('.');
|
||||
messages.push(` - [${path}] ${issue.message}`);
|
||||
}
|
||||
throw new Error(messages.join('\n'));
|
||||
}
|
||||
const dto = parseResult.data;
|
||||
|
||||
const includedWorkers = asSet(dto.IMMICH_WORKERS_INCLUDE, [ImmichWorker.Api, ImmichWorker.Microservices]);
|
||||
const excludedWorkers = asSet(dto.IMMICH_WORKERS_EXCLUDE, []);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ModuleRef, Reflector } from '@nestjs/core';
|
||||
import { ClassConstructor } from 'class-transformer';
|
||||
import _ from 'lodash';
|
||||
import { Socket } from 'socket.io';
|
||||
import { SystemConfig } from 'src/config';
|
||||
@@ -152,7 +151,7 @@ export class EventRepository {
|
||||
this.logger.setContext(EventRepository.name);
|
||||
}
|
||||
|
||||
setup({ services }: { services: ClassConstructor<unknown>[] }) {
|
||||
setup({ services }: { services: (new (...args: any[]) => unknown)[] }) {
|
||||
const reflector = this.moduleRef.get(Reflector, { strict: false });
|
||||
const items: Item<EmitEvent>[] = [];
|
||||
const worker = this.configRepository.getWorker();
|
||||
|
||||
@@ -2,7 +2,6 @@ import { getQueueToken } from '@nestjs/bullmq';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ModuleRef, Reflector } from '@nestjs/core';
|
||||
import { JobsOptions, Queue, Worker } from 'bullmq';
|
||||
import { ClassConstructor } from 'class-transformer';
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
import { JobConfig } from 'src/decorators';
|
||||
import { QueueJobResponseDto, QueueJobSearchDto } from 'src/dtos/queue.dto';
|
||||
@@ -34,7 +33,7 @@ export class JobRepository {
|
||||
this.logger.setContext(JobRepository.name);
|
||||
}
|
||||
|
||||
setup(services: ClassConstructor<unknown>[]) {
|
||||
setup(services: (new (...args: any[]) => unknown)[]) {
|
||||
const reflector = this.moduleRef.get(Reflector, { strict: false });
|
||||
|
||||
// discovery
|
||||
|
||||
@@ -11,7 +11,6 @@ import { resourceFromAttributes } from '@opentelemetry/resources';
|
||||
import { AggregationType } from '@opentelemetry/sdk-metrics';
|
||||
import { NodeSDK, contextBase } from '@opentelemetry/sdk-node';
|
||||
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
|
||||
import { ClassConstructor } from 'class-transformer';
|
||||
import { snakeCase, startCase } from 'lodash';
|
||||
import { MetricService } from 'nestjs-otel';
|
||||
import { copyMetadataFromFunctionToFunction } from 'nestjs-otel/lib/opentelemetry.utils';
|
||||
@@ -118,7 +117,7 @@ export class TelemetryRepository {
|
||||
this.repo = new MetricGroupRepository(metricService).configure({ enabled: metrics.has(ImmichTelemetry.Repo) });
|
||||
}
|
||||
|
||||
setup({ repositories }: { repositories: ClassConstructor<unknown>[] }) {
|
||||
setup({ repositories }: { repositories: (new (...args: any[]) => unknown)[] }) {
|
||||
const { telemetry } = this.configRepository.getEnv();
|
||||
const { metrics } = telemetry;
|
||||
if (!metrics.has(ImmichTelemetry.Repo)) {
|
||||
@@ -136,7 +135,7 @@ export class TelemetryRepository {
|
||||
}
|
||||
}
|
||||
|
||||
private wrap(Repository: ClassConstructor<unknown>) {
|
||||
private wrap(Repository: new (...args: any[]) => unknown) {
|
||||
const className = Repository.name;
|
||||
const descriptors = Object.getOwnPropertyDescriptors(Repository.prototype);
|
||||
const unit = 'ms';
|
||||
|
||||
Reference in New Issue
Block a user