diff --git a/mobile/openapi/lib/model/duplicate_detection_config.dart b/mobile/openapi/lib/model/duplicate_detection_config.dart index 4565a80c0e..0bc6091784 100644 --- a/mobile/openapi/lib/model/duplicate_detection_config.dart +++ b/mobile/openapi/lib/model/duplicate_detection_config.dart @@ -53,7 +53,7 @@ class DuplicateDetectionConfig { return DuplicateDetectionConfig( enabled: mapValueOfType(json, r'enabled')!, - maxDistance: mapValueOfType(json, r'maxDistance')!, + maxDistance: (mapValueOfType(json, r'maxDistance')!).toDouble(), ); } return null; diff --git a/mobile/openapi/lib/model/facial_recognition_config.dart b/mobile/openapi/lib/model/facial_recognition_config.dart index 8a3a5ab9c2..52400fd7e1 100644 --- a/mobile/openapi/lib/model/facial_recognition_config.dart +++ b/mobile/openapi/lib/model/facial_recognition_config.dart @@ -74,9 +74,9 @@ class FacialRecognitionConfig { return FacialRecognitionConfig( enabled: mapValueOfType(json, r'enabled')!, - maxDistance: mapValueOfType(json, r'maxDistance')!, + maxDistance: (mapValueOfType(json, r'maxDistance')!).toDouble(), minFaces: mapValueOfType(json, r'minFaces')!, - minScore: mapValueOfType(json, r'minScore')!, + minScore: (mapValueOfType(json, r'minScore')!).toDouble(), modelName: mapValueOfType(json, r'modelName')!, ); } diff --git a/mobile/openapi/lib/model/server_storage_response_dto.dart b/mobile/openapi/lib/model/server_storage_response_dto.dart index ab0f169e4b..89d97d32ea 100644 --- a/mobile/openapi/lib/model/server_storage_response_dto.dart +++ b/mobile/openapi/lib/model/server_storage_response_dto.dart @@ -84,7 +84,7 @@ class ServerStorageResponseDto { diskAvailableRaw: mapValueOfType(json, r'diskAvailableRaw')!, diskSize: mapValueOfType(json, r'diskSize')!, diskSizeRaw: mapValueOfType(json, r'diskSizeRaw')!, - diskUsagePercentage: mapValueOfType(json, r'diskUsagePercentage')!, + diskUsagePercentage: (mapValueOfType(json, r'diskUsagePercentage')!).toDouble(), diskUse: mapValueOfType(json, r'diskUse')!, diskUseRaw: mapValueOfType(json, r'diskUseRaw')!, ); diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index aa5cb33a59..78507452e8 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -8146,7 +8146,7 @@ "type": "boolean" }, "maxDistance": { - "format": "float", + "format": "double", "maximum": 0.1, "minimum": 0.001, "type": "number" @@ -8347,7 +8347,7 @@ "type": "boolean" }, "maxDistance": { - "format": "float", + "format": "double", "maximum": 2, "minimum": 0, "type": "number" @@ -8357,7 +8357,7 @@ "type": "integer" }, "minScore": { - "format": "float", + "format": "double", "maximum": 1, "minimum": 0, "type": "number" @@ -9797,7 +9797,7 @@ "type": "integer" }, "diskUsagePercentage": { - "format": "float", + "format": "double", "type": "number" }, "diskUse": { diff --git a/server/src/dtos/model-config.dto.ts b/server/src/dtos/model-config.dto.ts index 5dc8237414..dffacc793d 100644 --- a/server/src/dtos/model-config.dto.ts +++ b/server/src/dtos/model-config.dto.ts @@ -21,7 +21,7 @@ export class DuplicateDetectionConfig extends TaskConfig { @Min(0.001) @Max(0.1) @Type(() => Number) - @ApiProperty({ type: 'number', format: 'float' }) + @ApiProperty({ type: 'number', format: 'double' }) maxDistance!: number; } @@ -30,14 +30,14 @@ export class FacialRecognitionConfig extends ModelConfig { @Min(0) @Max(1) @Type(() => Number) - @ApiProperty({ type: 'number', format: 'float' }) + @ApiProperty({ type: 'number', format: 'double' }) minScore!: number; @IsNumber() @Min(0) @Max(2) @Type(() => Number) - @ApiProperty({ type: 'number', format: 'float' }) + @ApiProperty({ type: 'number', format: 'double' }) maxDistance!: number; @IsNumber() diff --git a/server/src/dtos/server-info.dto.ts b/server/src/dtos/server-info.dto.ts index 6afe8534c7..94a5b4df6e 100644 --- a/server/src/dtos/server-info.dto.ts +++ b/server/src/dtos/server-info.dto.ts @@ -21,7 +21,7 @@ export class ServerStorageResponseDto { @ApiProperty({ type: 'integer', format: 'int64' }) diskAvailableRaw!: number; - @ApiProperty({ type: 'number', format: 'float' }) + @ApiProperty({ type: 'number', format: 'double' }) diskUsagePercentage!: number; } diff --git a/server/src/utils/misc.ts b/server/src/utils/misc.ts index f5c0105c03..e0a2ed860e 100644 --- a/server/src/utils/misc.ts +++ b/server/src/utils/misc.ts @@ -6,7 +6,7 @@ import { SwaggerDocumentOptions, SwaggerModule, } from '@nestjs/swagger'; -import { SchemaObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface'; +import { ReferenceObject, SchemaObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface'; import _ from 'lodash'; import { writeFileSync } from 'node:fs'; import path from 'node:path'; @@ -111,6 +111,14 @@ function sortKeys(target: T): T { export const routeToErrorMessage = (methodName: string) => 'Failed to ' + methodName.replaceAll(/[A-Z]+/g, (letter) => ` ${letter.toLowerCase()}`); +const isSchema = (schema: string | ReferenceObject | SchemaObject): schema is SchemaObject => { + if (typeof schema === 'string' || '$ref' in schema) { + return false; + } + + return true; +}; + const patchOpenAPI = (document: OpenAPIObject) => { document.paths = sortKeys(document.paths); @@ -119,13 +127,23 @@ const patchOpenAPI = (document: OpenAPIObject) => { document.components.schemas = sortKeys(schemas); - for (const schema of Object.values(schemas)) { + for (const [schemaName, schema] of Object.entries(schemas)) { if (schema.properties) { schema.properties = sortKeys(schema.properties); - } - if (schema.required) { - schema.required = schema.required.sort(); + for (const [key, value] of Object.entries(schema.properties)) { + if (typeof value === 'string') { + continue; + } + + if (isSchema(value) && value.type === 'number' && value.format === 'float') { + throw new Error(`Invalid number format: ${schemaName}.${key}=float (use double instead). `); + } + } + + if (schema.required) { + schema.required = schema.required.sort(); + } } } }