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:
+402
-473
@@ -1,492 +1,423 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ArrayMaxSize, IsInt, IsPositive, IsString } from 'class-validator';
|
||||
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
||||
import { AssetEditAction } from 'src/dtos/editing.dto';
|
||||
import { createZodDto } from 'nestjs-zod';
|
||||
import { AssetResponseSchema } from 'src/dtos/asset-response.dto';
|
||||
import { AssetEditActionSchema } from 'src/dtos/editing.dto';
|
||||
import {
|
||||
AlbumUserRole,
|
||||
AssetOrder,
|
||||
AssetType,
|
||||
AssetVisibility,
|
||||
MemoryType,
|
||||
AlbumUserRoleSchema,
|
||||
AssetOrderSchema,
|
||||
AssetTypeSchema,
|
||||
AssetVisibilitySchema,
|
||||
MemoryTypeSchema,
|
||||
SyncEntityType,
|
||||
SyncRequestType,
|
||||
UserAvatarColor,
|
||||
UserMetadataKey,
|
||||
SyncEntityTypeSchema,
|
||||
SyncRequestTypeSchema,
|
||||
UserAvatarColorSchema,
|
||||
UserMetadataKeySchema,
|
||||
} from 'src/enum';
|
||||
import { UserMetadata } from 'src/types';
|
||||
import { ValidateBoolean, ValidateDate, ValidateEnum, ValidateUUID } from 'src/validation';
|
||||
import { isoDatetimeToDate } from 'src/validation';
|
||||
import z from 'zod';
|
||||
|
||||
export class AssetFullSyncDto {
|
||||
@ValidateUUID({ optional: true, description: 'Last asset ID (pagination)' })
|
||||
lastId?: string;
|
||||
const AssetFullSyncSchema = z
|
||||
.object({
|
||||
lastId: z.uuidv4().optional().describe('Last asset ID (pagination)'),
|
||||
updatedUntil: isoDatetimeToDate.describe('Sync assets updated until this date'),
|
||||
limit: z.int().min(1).describe('Maximum number of assets to return'),
|
||||
userId: z.uuidv4().optional().describe('Filter by user ID'),
|
||||
})
|
||||
.meta({ id: 'AssetFullSyncDto' });
|
||||
|
||||
@ValidateDate({ description: 'Sync assets updated until this date' })
|
||||
updatedUntil!: Date;
|
||||
const AssetDeltaSyncSchema = z
|
||||
.object({
|
||||
updatedAfter: isoDatetimeToDate.describe('Sync assets updated after this date'),
|
||||
userIds: z.array(z.uuidv4()).describe('User IDs to sync'),
|
||||
})
|
||||
.meta({ id: 'AssetDeltaSyncDto' });
|
||||
|
||||
@ApiProperty({ type: 'integer', description: 'Maximum number of assets to return' })
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
limit!: number;
|
||||
export class AssetFullSyncDto extends createZodDto(AssetFullSyncSchema) {}
|
||||
export class AssetDeltaSyncDto extends createZodDto(AssetDeltaSyncSchema) {}
|
||||
|
||||
@ValidateUUID({ optional: true, description: 'Filter by user ID' })
|
||||
userId?: string;
|
||||
}
|
||||
const AssetDeltaSyncResponseSchema = z
|
||||
.object({
|
||||
needsFullSync: z.boolean().describe('Whether full sync is needed'),
|
||||
upserted: z.array(AssetResponseSchema),
|
||||
deleted: z.array(z.string()).describe('Deleted asset IDs'),
|
||||
})
|
||||
.describe('Asset delta sync response')
|
||||
.meta({ id: 'AssetDeltaSyncResponseDto' });
|
||||
|
||||
export class AssetDeltaSyncDto {
|
||||
@ValidateDate({ description: 'Sync assets updated after this date' })
|
||||
updatedAfter!: Date;
|
||||
|
||||
@ValidateUUID({ each: true, description: 'User IDs to sync' })
|
||||
userIds!: string[];
|
||||
}
|
||||
|
||||
export class AssetDeltaSyncResponseDto {
|
||||
@ApiProperty({ description: 'Whether full sync is needed' })
|
||||
needsFullSync!: boolean;
|
||||
@ApiProperty({ description: 'Upserted assets' })
|
||||
upserted!: AssetResponseDto[];
|
||||
@ApiProperty({ description: 'Deleted asset IDs' })
|
||||
deleted!: string[];
|
||||
}
|
||||
export class AssetDeltaSyncResponseDto extends createZodDto(AssetDeltaSyncResponseSchema) {}
|
||||
|
||||
export const extraSyncModels: Function[] = [];
|
||||
|
||||
export const ExtraModel = (): ClassDecorator => {
|
||||
const ExtraModel = (): ClassDecorator => {
|
||||
// eslint-disable-next-line unicorn/consistent-function-scoping
|
||||
return (object: Function) => {
|
||||
extraSyncModels.push(object);
|
||||
};
|
||||
};
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncUserV1 {
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'User name' })
|
||||
name!: string;
|
||||
@ApiProperty({ description: 'User email' })
|
||||
email!: string;
|
||||
@ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', description: 'User avatar color' })
|
||||
avatarColor!: UserAvatarColor | null;
|
||||
@ApiProperty({ description: 'User deleted at' })
|
||||
deletedAt!: Date | null;
|
||||
@ApiProperty({ description: 'User has profile image' })
|
||||
hasProfileImage!: boolean;
|
||||
@ApiProperty({ description: 'User profile changed at' })
|
||||
profileChangedAt!: Date;
|
||||
}
|
||||
const SyncUserV1Schema = z
|
||||
.object({
|
||||
id: z.string().describe('User ID'),
|
||||
name: z.string().describe('User name'),
|
||||
email: z.string().describe('User email'),
|
||||
avatarColor: UserAvatarColorSchema.nullish(),
|
||||
deletedAt: isoDatetimeToDate.nullable().describe('User deleted at'),
|
||||
hasProfileImage: z.boolean().describe('User has profile image'),
|
||||
profileChangedAt: isoDatetimeToDate.describe('User profile changed at'),
|
||||
})
|
||||
.meta({ id: 'SyncUserV1' });
|
||||
|
||||
const SyncAuthUserV1Schema = SyncUserV1Schema.merge(
|
||||
z.object({
|
||||
isAdmin: z.boolean().describe('User is admin'),
|
||||
pinCode: z.string().nullable().describe('User pin code'),
|
||||
oauthId: z.string().describe('User OAuth ID'),
|
||||
storageLabel: z.string().nullable().describe('User storage label'),
|
||||
quotaSizeInBytes: z.int().nullable().describe('Quota size in bytes'),
|
||||
quotaUsageInBytes: z.int().describe('Quota usage in bytes'),
|
||||
}),
|
||||
).meta({ id: 'SyncAuthUserV1' });
|
||||
|
||||
const SyncUserDeleteV1Schema = z.object({ userId: z.string().describe('User ID') }).meta({ id: 'SyncUserDeleteV1' });
|
||||
|
||||
const SyncPartnerV1Schema = z
|
||||
.object({
|
||||
sharedById: z.string().describe('Shared by ID'),
|
||||
sharedWithId: z.string().describe('Shared with ID'),
|
||||
inTimeline: z.boolean().describe('In timeline'),
|
||||
})
|
||||
.meta({ id: 'SyncPartnerV1' });
|
||||
|
||||
const SyncPartnerDeleteV1Schema = z
|
||||
.object({
|
||||
sharedById: z.string().describe('Shared by ID'),
|
||||
sharedWithId: z.string().describe('Shared with ID'),
|
||||
})
|
||||
.meta({ id: 'SyncPartnerDeleteV1' });
|
||||
|
||||
const SyncAssetV1Schema = z
|
||||
.object({
|
||||
id: z.string().describe('Asset ID'),
|
||||
ownerId: z.string().describe('Owner ID'),
|
||||
originalFileName: z.string().describe('Original file name'),
|
||||
thumbhash: z.string().nullable().describe('Thumbhash'),
|
||||
checksum: z.string().describe('Checksum'),
|
||||
fileCreatedAt: isoDatetimeToDate.nullable().describe('File created at'),
|
||||
fileModifiedAt: isoDatetimeToDate.nullable().describe('File modified at'),
|
||||
localDateTime: isoDatetimeToDate.nullable().describe('Local date time'),
|
||||
duration: z.string().nullable().describe('Duration'),
|
||||
type: AssetTypeSchema,
|
||||
deletedAt: isoDatetimeToDate.nullable().describe('Deleted at'),
|
||||
isFavorite: z.boolean().describe('Is favorite'),
|
||||
visibility: AssetVisibilitySchema,
|
||||
livePhotoVideoId: z.string().nullable().describe('Live photo video ID'),
|
||||
stackId: z.string().nullable().describe('Stack ID'),
|
||||
libraryId: z.string().nullable().describe('Library ID'),
|
||||
width: z.int().nullable().describe('Asset width'),
|
||||
height: z.int().nullable().describe('Asset height'),
|
||||
isEdited: z.boolean().describe('Is edited'),
|
||||
})
|
||||
.meta({ id: 'SyncAssetV1' });
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAuthUserV1 extends SyncUserV1 {
|
||||
@ApiProperty({ description: 'User is admin' })
|
||||
isAdmin!: boolean;
|
||||
@ApiProperty({ description: 'User pin code' })
|
||||
pinCode!: string | null;
|
||||
@ApiProperty({ description: 'User OAuth ID' })
|
||||
oauthId!: string;
|
||||
@ApiProperty({ description: 'User storage label' })
|
||||
storageLabel!: string | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
quotaSizeInBytes!: number | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
quotaUsageInBytes!: number;
|
||||
}
|
||||
class SyncUserV1 extends createZodDto(SyncUserV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncAuthUserV1 extends createZodDto(SyncAuthUserV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncUserDeleteV1 extends createZodDto(SyncUserDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncPartnerV1 extends createZodDto(SyncPartnerV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncPartnerDeleteV1 extends createZodDto(SyncPartnerDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetV1 extends createZodDto(SyncAssetV1Schema) {}
|
||||
|
||||
const SyncAssetDeleteV1Schema = z
|
||||
.object({ assetId: z.string().describe('Asset ID') })
|
||||
.meta({ id: 'SyncAssetDeleteV1' });
|
||||
|
||||
const SyncAssetExifV1Schema = z
|
||||
.object({
|
||||
assetId: z.string().describe('Asset ID'),
|
||||
description: z.string().nullable().describe('Description'),
|
||||
exifImageWidth: z.int().nullable().describe('Exif image width'),
|
||||
exifImageHeight: z.int().nullable().describe('Exif image height'),
|
||||
fileSizeInByte: z.int().nullable().describe('File size in byte'),
|
||||
orientation: z.string().nullable().describe('Orientation'),
|
||||
dateTimeOriginal: isoDatetimeToDate.nullable().describe('Date time original'),
|
||||
modifyDate: isoDatetimeToDate.nullable().describe('Modify date'),
|
||||
timeZone: z.string().nullable().describe('Time zone'),
|
||||
latitude: z.number().meta({ format: 'double' }).nullable().describe('Latitude'),
|
||||
longitude: z.number().meta({ format: 'double' }).nullable().describe('Longitude'),
|
||||
projectionType: z.string().nullable().describe('Projection type'),
|
||||
city: z.string().nullable().describe('City'),
|
||||
state: z.string().nullable().describe('State'),
|
||||
country: z.string().nullable().describe('Country'),
|
||||
make: z.string().nullable().describe('Make'),
|
||||
model: z.string().nullable().describe('Model'),
|
||||
lensModel: z.string().nullable().describe('Lens model'),
|
||||
fNumber: z.number().meta({ format: 'double' }).nullable().describe('F number'),
|
||||
focalLength: z.number().meta({ format: 'double' }).nullable().describe('Focal length'),
|
||||
iso: z.int().nullable().describe('ISO'),
|
||||
exposureTime: z.string().nullable().describe('Exposure time'),
|
||||
profileDescription: z.string().nullable().describe('Profile description'),
|
||||
rating: z.int().nullable().describe('Rating'),
|
||||
fps: z.number().meta({ format: 'double' }).nullable().describe('FPS'),
|
||||
})
|
||||
.meta({ id: 'SyncAssetExifV1' });
|
||||
|
||||
const SyncAssetMetadataV1Schema = z
|
||||
.object({
|
||||
assetId: z.string().describe('Asset ID'),
|
||||
key: z.string().describe('Key'),
|
||||
value: z.record(z.string(), z.unknown()).describe('Value'),
|
||||
})
|
||||
.meta({ id: 'SyncAssetMetadataV1' });
|
||||
|
||||
const SyncAssetMetadataDeleteV1Schema = z
|
||||
.object({
|
||||
assetId: z.string().describe('Asset ID'),
|
||||
key: z.string().describe('Key'),
|
||||
})
|
||||
.meta({ id: 'SyncAssetMetadataDeleteV1' });
|
||||
|
||||
const SyncAssetEditV1Schema = z
|
||||
.object({
|
||||
id: z.string().describe('Edit ID'),
|
||||
assetId: z.string().describe('Asset ID'),
|
||||
action: AssetEditActionSchema,
|
||||
parameters: z.record(z.string(), z.unknown()).describe('Edit parameters'),
|
||||
sequence: z.int().describe('Edit sequence'),
|
||||
})
|
||||
.meta({ id: 'SyncAssetEditV1' });
|
||||
|
||||
const SyncAssetEditDeleteV1Schema = z
|
||||
.object({ editId: z.string().describe('Edit ID') })
|
||||
.meta({ id: 'SyncAssetEditDeleteV1' });
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncUserDeleteV1 {
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
}
|
||||
class SyncAssetDeleteV1 extends createZodDto(SyncAssetDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetExifV1 extends createZodDto(SyncAssetExifV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncAssetMetadataV1 extends createZodDto(SyncAssetMetadataV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncAssetMetadataDeleteV1 extends createZodDto(SyncAssetMetadataDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetEditV1 extends createZodDto(SyncAssetEditV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncAssetEditDeleteV1 extends createZodDto(SyncAssetEditDeleteV1Schema) {}
|
||||
|
||||
const SyncAlbumDeleteV1Schema = z
|
||||
.object({ albumId: z.string().describe('Album ID') })
|
||||
.meta({ id: 'SyncAlbumDeleteV1' });
|
||||
|
||||
const SyncAlbumUserDeleteV1Schema = z
|
||||
.object({
|
||||
albumId: z.string().describe('Album ID'),
|
||||
userId: z.string().describe('User ID'),
|
||||
})
|
||||
.meta({ id: 'SyncAlbumUserDeleteV1' });
|
||||
|
||||
const SyncAlbumUserV1Schema = z
|
||||
.object({
|
||||
albumId: z.string().describe('Album ID'),
|
||||
userId: z.string().describe('User ID'),
|
||||
role: AlbumUserRoleSchema,
|
||||
})
|
||||
.meta({ id: 'SyncAlbumUserV1' });
|
||||
|
||||
const SyncAlbumV1Schema = z
|
||||
.object({
|
||||
id: z.string().describe('Album ID'),
|
||||
ownerId: z.string().describe('Owner ID'),
|
||||
name: z.string().describe('Album name'),
|
||||
description: z.string().describe('Album description'),
|
||||
createdAt: isoDatetimeToDate.describe('Created at'),
|
||||
updatedAt: isoDatetimeToDate.describe('Updated at'),
|
||||
thumbnailAssetId: z.string().nullable().describe('Thumbnail asset ID'),
|
||||
isActivityEnabled: z.boolean().describe('Is activity enabled'),
|
||||
order: AssetOrderSchema,
|
||||
})
|
||||
.meta({ id: 'SyncAlbumV1' });
|
||||
|
||||
const SyncAlbumToAssetV1Schema = z
|
||||
.object({
|
||||
albumId: z.string().describe('Album ID'),
|
||||
assetId: z.string().describe('Asset ID'),
|
||||
})
|
||||
.meta({ id: 'SyncAlbumToAssetV1' });
|
||||
|
||||
const SyncAlbumToAssetDeleteV1Schema = z
|
||||
.object({
|
||||
albumId: z.string().describe('Album ID'),
|
||||
assetId: z.string().describe('Asset ID'),
|
||||
})
|
||||
.meta({ id: 'SyncAlbumToAssetDeleteV1' });
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncPartnerV1 {
|
||||
@ApiProperty({ description: 'Shared by ID' })
|
||||
sharedById!: string;
|
||||
@ApiProperty({ description: 'Shared with ID' })
|
||||
sharedWithId!: string;
|
||||
@ApiProperty({ description: 'In timeline' })
|
||||
inTimeline!: boolean;
|
||||
}
|
||||
class SyncAlbumDeleteV1 extends createZodDto(SyncAlbumDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncAlbumUserDeleteV1 extends createZodDto(SyncAlbumUserDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncAlbumUserV1 extends createZodDto(SyncAlbumUserV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncAlbumV1 extends createZodDto(SyncAlbumV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncAlbumToAssetV1 extends createZodDto(SyncAlbumToAssetV1Schema) {}
|
||||
@ExtraModel()
|
||||
class SyncAlbumToAssetDeleteV1 extends createZodDto(SyncAlbumToAssetDeleteV1Schema) {}
|
||||
|
||||
const SyncMemoryV1Schema = z
|
||||
.object({
|
||||
id: z.string().describe('Memory ID'),
|
||||
createdAt: isoDatetimeToDate.describe('Created at'),
|
||||
updatedAt: isoDatetimeToDate.describe('Updated at'),
|
||||
deletedAt: isoDatetimeToDate.nullable().describe('Deleted at'),
|
||||
ownerId: z.string().describe('Owner ID'),
|
||||
type: MemoryTypeSchema,
|
||||
data: z.record(z.string(), z.unknown()).describe('Data'),
|
||||
isSaved: z.boolean().describe('Is saved'),
|
||||
memoryAt: isoDatetimeToDate.describe('Memory at'),
|
||||
seenAt: isoDatetimeToDate.nullable().describe('Seen at'),
|
||||
showAt: isoDatetimeToDate.nullable().describe('Show at'),
|
||||
hideAt: isoDatetimeToDate.nullable().describe('Hide at'),
|
||||
})
|
||||
.meta({ id: 'SyncMemoryV1' });
|
||||
|
||||
const SyncMemoryDeleteV1Schema = z
|
||||
.object({ memoryId: z.string().describe('Memory ID') })
|
||||
.meta({ id: 'SyncMemoryDeleteV1' });
|
||||
|
||||
const SyncMemoryAssetV1Schema = z
|
||||
.object({
|
||||
memoryId: z.string().describe('Memory ID'),
|
||||
assetId: z.string().describe('Asset ID'),
|
||||
})
|
||||
.meta({ id: 'SyncMemoryAssetV1' });
|
||||
|
||||
const SyncMemoryAssetDeleteV1Schema = z
|
||||
.object({
|
||||
memoryId: z.string().describe('Memory ID'),
|
||||
assetId: z.string().describe('Asset ID'),
|
||||
})
|
||||
.meta({ id: 'SyncMemoryAssetDeleteV1' });
|
||||
|
||||
const SyncStackV1Schema = z
|
||||
.object({
|
||||
id: z.string().describe('Stack ID'),
|
||||
createdAt: isoDatetimeToDate.describe('Created at'),
|
||||
updatedAt: isoDatetimeToDate.describe('Updated at'),
|
||||
primaryAssetId: z.string().describe('Primary asset ID'),
|
||||
ownerId: z.string().describe('Owner ID'),
|
||||
})
|
||||
.meta({ id: 'SyncStackV1' });
|
||||
|
||||
const SyncStackDeleteV1Schema = z
|
||||
.object({ stackId: z.string().describe('Stack ID') })
|
||||
.meta({ id: 'SyncStackDeleteV1' });
|
||||
|
||||
const SyncPersonV1Schema = z
|
||||
.object({
|
||||
id: z.string().describe('Person ID'),
|
||||
createdAt: isoDatetimeToDate.describe('Created at'),
|
||||
updatedAt: isoDatetimeToDate.describe('Updated at'),
|
||||
ownerId: z.string().describe('Owner ID'),
|
||||
name: z.string().describe('Person name'),
|
||||
birthDate: isoDatetimeToDate.nullable().describe('Birth date'),
|
||||
isHidden: z.boolean().describe('Is hidden'),
|
||||
isFavorite: z.boolean().describe('Is favorite'),
|
||||
color: z.string().nullable().describe('Color'),
|
||||
faceAssetId: z.string().nullable().describe('Face asset ID'),
|
||||
})
|
||||
.meta({ id: 'SyncPersonV1' });
|
||||
|
||||
const SyncPersonDeleteV1Schema = z
|
||||
.object({ personId: z.string().describe('Person ID') })
|
||||
.meta({ id: 'SyncPersonDeleteV1' });
|
||||
|
||||
const SyncAssetFaceV1Schema = z
|
||||
.object({
|
||||
id: z.string().describe('Asset face ID'),
|
||||
assetId: z.string().describe('Asset ID'),
|
||||
personId: z.string().nullable().describe('Person ID'),
|
||||
imageWidth: z.int().describe('Image width'),
|
||||
imageHeight: z.int().describe('Image height'),
|
||||
boundingBoxX1: z.int().describe('Bounding box X1'),
|
||||
boundingBoxY1: z.int().describe('Bounding box Y1'),
|
||||
boundingBoxX2: z.int().describe('Bounding box X2'),
|
||||
boundingBoxY2: z.int().describe('Bounding box Y2'),
|
||||
sourceType: z.string().describe('Source type'),
|
||||
})
|
||||
.meta({ id: 'SyncAssetFaceV1' });
|
||||
|
||||
const SyncAssetFaceV2Schema = SyncAssetFaceV1Schema.extend({
|
||||
deletedAt: isoDatetimeToDate.nullable().describe('Face deleted at'),
|
||||
isVisible: z.boolean().describe('Is the face visible in the asset'),
|
||||
}).meta({ id: 'SyncAssetFaceV2' });
|
||||
|
||||
const SyncAssetFaceDeleteV1Schema = z
|
||||
.object({ assetFaceId: z.string().describe('Asset face ID') })
|
||||
.meta({ id: 'SyncAssetFaceDeleteV1' });
|
||||
|
||||
const SyncUserMetadataV1Schema = z
|
||||
.object({
|
||||
userId: z.string().describe('User ID'),
|
||||
key: UserMetadataKeySchema,
|
||||
value: z.record(z.string(), z.unknown()).describe('User metadata value'),
|
||||
})
|
||||
.meta({ id: 'SyncUserMetadataV1' });
|
||||
|
||||
const SyncUserMetadataDeleteV1Schema = z
|
||||
.object({
|
||||
userId: z.string().describe('User ID'),
|
||||
key: UserMetadataKeySchema,
|
||||
})
|
||||
.meta({ id: 'SyncUserMetadataDeleteV1' });
|
||||
|
||||
const SyncAckV1Schema = z.object({}).meta({ id: 'SyncAckV1' });
|
||||
const SyncResetV1Schema = z.object({}).meta({ id: 'SyncResetV1' });
|
||||
const SyncCompleteV1Schema = z.object({}).meta({ id: 'SyncCompleteV1' });
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncPartnerDeleteV1 {
|
||||
@ApiProperty({ description: 'Shared by ID' })
|
||||
sharedById!: string;
|
||||
@ApiProperty({ description: 'Shared with ID' })
|
||||
sharedWithId!: string;
|
||||
}
|
||||
|
||||
class SyncMemoryV1 extends createZodDto(SyncMemoryV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
@ApiProperty({ description: 'Original file name' })
|
||||
originalFileName!: string;
|
||||
@ApiProperty({ description: 'Thumbhash' })
|
||||
thumbhash!: string | null;
|
||||
@ApiProperty({ description: 'Checksum' })
|
||||
checksum!: string;
|
||||
@ApiProperty({ description: 'File created at' })
|
||||
fileCreatedAt!: Date | null;
|
||||
@ApiProperty({ description: 'File modified at' })
|
||||
fileModifiedAt!: Date | null;
|
||||
@ApiProperty({ description: 'Local date time' })
|
||||
localDateTime!: Date | null;
|
||||
@ApiProperty({ description: 'Duration' })
|
||||
duration!: string | null;
|
||||
@ValidateEnum({ enum: AssetType, name: 'AssetTypeEnum', description: 'Asset type' })
|
||||
type!: AssetType;
|
||||
@ApiProperty({ description: 'Deleted at' })
|
||||
deletedAt!: Date | null;
|
||||
@ApiProperty({ description: 'Is favorite' })
|
||||
isFavorite!: boolean;
|
||||
@ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', description: 'Asset visibility' })
|
||||
visibility!: AssetVisibility;
|
||||
@ApiProperty({ description: 'Live photo video ID' })
|
||||
livePhotoVideoId!: string | null;
|
||||
@ApiProperty({ description: 'Stack ID' })
|
||||
stackId!: string | null;
|
||||
@ApiProperty({ description: 'Library ID' })
|
||||
libraryId!: string | null;
|
||||
@ApiProperty({ type: 'integer', description: 'Asset width' })
|
||||
width!: number | null;
|
||||
@ApiProperty({ type: 'integer', description: 'Asset height' })
|
||||
height!: number | null;
|
||||
@ApiProperty({ description: 'Is edited' })
|
||||
isEdited!: boolean;
|
||||
}
|
||||
|
||||
class SyncMemoryDeleteV1 extends createZodDto(SyncMemoryDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetDeleteV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
class SyncMemoryAssetV1 extends createZodDto(SyncMemoryAssetV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetExifV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
@ApiProperty({ description: 'Description' })
|
||||
description!: string | null;
|
||||
@ApiProperty({ type: 'integer', description: 'Exif image width' })
|
||||
exifImageWidth!: number | null;
|
||||
@ApiProperty({ type: 'integer', description: 'Exif image height' })
|
||||
exifImageHeight!: number | null;
|
||||
@ApiProperty({ type: 'integer', description: 'File size in byte' })
|
||||
fileSizeInByte!: number | null;
|
||||
@ApiProperty({ description: 'Orientation' })
|
||||
orientation!: string | null;
|
||||
@ApiProperty({ description: 'Date time original' })
|
||||
dateTimeOriginal!: Date | null;
|
||||
@ApiProperty({ description: 'Modify date' })
|
||||
modifyDate!: Date | null;
|
||||
@ApiProperty({ description: 'Time zone' })
|
||||
timeZone!: string | null;
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'Latitude' })
|
||||
latitude!: number | null;
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'Longitude' })
|
||||
longitude!: number | null;
|
||||
@ApiProperty({ description: 'Projection type' })
|
||||
projectionType!: string | null;
|
||||
@ApiProperty({ description: 'City' })
|
||||
city!: string | null;
|
||||
@ApiProperty({ description: 'State' })
|
||||
state!: string | null;
|
||||
@ApiProperty({ description: 'Country' })
|
||||
country!: string | null;
|
||||
@ApiProperty({ description: 'Make' })
|
||||
make!: string | null;
|
||||
@ApiProperty({ description: 'Model' })
|
||||
model!: string | null;
|
||||
@ApiProperty({ description: 'Lens model' })
|
||||
lensModel!: string | null;
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'F number' })
|
||||
fNumber!: number | null;
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'Focal length' })
|
||||
focalLength!: number | null;
|
||||
@ApiProperty({ type: 'integer', description: 'ISO' })
|
||||
iso!: number | null;
|
||||
@ApiProperty({ description: 'Exposure time' })
|
||||
exposureTime!: string | null;
|
||||
@ApiProperty({ description: 'Profile description' })
|
||||
profileDescription!: string | null;
|
||||
@ApiProperty({ type: 'integer', description: 'Rating' })
|
||||
rating!: number | null;
|
||||
@ApiProperty({ type: 'number', format: 'double', description: 'FPS' })
|
||||
fps!: number | null;
|
||||
}
|
||||
|
||||
class SyncMemoryAssetDeleteV1 extends createZodDto(SyncMemoryAssetDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetEditV1 {
|
||||
id!: string;
|
||||
assetId!: string;
|
||||
|
||||
@ValidateEnum({ enum: AssetEditAction, name: 'AssetEditAction' })
|
||||
action!: AssetEditAction;
|
||||
parameters!: object;
|
||||
|
||||
@ApiProperty({ type: 'integer' })
|
||||
sequence!: number;
|
||||
}
|
||||
|
||||
class SyncStackV1 extends createZodDto(SyncStackV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetEditDeleteV1 {
|
||||
editId!: string;
|
||||
}
|
||||
|
||||
class SyncStackDeleteV1 extends createZodDto(SyncStackDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetMetadataV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
@ApiProperty({ description: 'Key' })
|
||||
key!: string;
|
||||
@ApiProperty({ description: 'Value' })
|
||||
value!: object;
|
||||
}
|
||||
|
||||
class SyncPersonV1 extends createZodDto(SyncPersonV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAssetMetadataDeleteV1 {
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
@ApiProperty({ description: 'Key' })
|
||||
key!: string;
|
||||
}
|
||||
|
||||
class SyncPersonDeleteV1 extends createZodDto(SyncPersonDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAlbumDeleteV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
}
|
||||
|
||||
class SyncAssetFaceV1 extends createZodDto(SyncAssetFaceV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAlbumUserDeleteV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumUserV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
@ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole', description: 'Album user role' })
|
||||
role!: AlbumUserRole;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
@ApiProperty({ description: 'Album name' })
|
||||
name!: string;
|
||||
@ApiProperty({ description: 'Album description' })
|
||||
description!: string;
|
||||
@ApiProperty({ description: 'Created at' })
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ description: 'Updated at' })
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ description: 'Thumbnail asset ID' })
|
||||
thumbnailAssetId!: string | null;
|
||||
@ApiProperty({ description: 'Is activity enabled' })
|
||||
isActivityEnabled!: boolean;
|
||||
@ValidateEnum({ enum: AssetOrder, name: 'AssetOrder' })
|
||||
order!: AssetOrder;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumToAssetV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAlbumToAssetDeleteV1 {
|
||||
@ApiProperty({ description: 'Album ID' })
|
||||
albumId!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncMemoryV1 {
|
||||
@ApiProperty({ description: 'Memory ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Created at' })
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ description: 'Updated at' })
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ description: 'Deleted at' })
|
||||
deletedAt!: Date | null;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
@ValidateEnum({ enum: MemoryType, name: 'MemoryType', description: 'Memory type' })
|
||||
type!: MemoryType;
|
||||
@ApiProperty({ description: 'Data' })
|
||||
data!: object;
|
||||
@ApiProperty({ description: 'Is saved' })
|
||||
isSaved!: boolean;
|
||||
@ApiProperty({ description: 'Memory at' })
|
||||
memoryAt!: Date;
|
||||
@ApiProperty({ description: 'Seen at' })
|
||||
seenAt!: Date | null;
|
||||
@ApiProperty({ description: 'Show at' })
|
||||
showAt!: Date | null;
|
||||
@ApiProperty({ description: 'Hide at' })
|
||||
hideAt!: Date | null;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncMemoryDeleteV1 {
|
||||
@ApiProperty({ description: 'Memory ID' })
|
||||
memoryId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncMemoryAssetV1 {
|
||||
@ApiProperty({ description: 'Memory ID' })
|
||||
memoryId!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncMemoryAssetDeleteV1 {
|
||||
@ApiProperty({ description: 'Memory ID' })
|
||||
memoryId!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncStackV1 {
|
||||
@ApiProperty({ description: 'Stack ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Created at' })
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ description: 'Updated at' })
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ description: 'Primary asset ID' })
|
||||
primaryAssetId!: string;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncStackDeleteV1 {
|
||||
@ApiProperty({ description: 'Stack ID' })
|
||||
stackId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncPersonV1 {
|
||||
@ApiProperty({ description: 'Person ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Created at' })
|
||||
createdAt!: Date;
|
||||
@ApiProperty({ description: 'Updated at' })
|
||||
updatedAt!: Date;
|
||||
@ApiProperty({ description: 'Owner ID' })
|
||||
ownerId!: string;
|
||||
@ApiProperty({ description: 'Person name' })
|
||||
name!: string;
|
||||
@ApiProperty({ description: 'Birth date' })
|
||||
birthDate!: Date | null;
|
||||
@ApiProperty({ description: 'Is hidden' })
|
||||
isHidden!: boolean;
|
||||
@ApiProperty({ description: 'Is favorite' })
|
||||
isFavorite!: boolean;
|
||||
@ApiProperty({ description: 'Color' })
|
||||
color!: string | null;
|
||||
@ApiProperty({ description: 'Face asset ID' })
|
||||
faceAssetId!: string | null;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncPersonDeleteV1 {
|
||||
@ApiProperty({ description: 'Person ID' })
|
||||
personId!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetFaceV1 {
|
||||
@ApiProperty({ description: 'Asset face ID' })
|
||||
id!: string;
|
||||
@ApiProperty({ description: 'Asset ID' })
|
||||
assetId!: string;
|
||||
@ApiProperty({ description: 'Person ID' })
|
||||
personId!: string | null;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
imageWidth!: number;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
imageHeight!: number;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
boundingBoxX1!: number;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
boundingBoxY1!: number;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
boundingBoxX2!: number;
|
||||
@ApiProperty({ type: 'integer' })
|
||||
boundingBoxY2!: number;
|
||||
@ApiProperty({ description: 'Source type' })
|
||||
sourceType!: string;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetFaceV2 extends SyncAssetFaceV1 {
|
||||
@ApiProperty({ description: 'Face deleted at' })
|
||||
deletedAt!: Date | null;
|
||||
@ApiProperty({ description: 'Is the face visible in the asset' })
|
||||
isVisible!: boolean;
|
||||
}
|
||||
class SyncAssetFaceV2 extends createZodDto(SyncAssetFaceV2Schema) {}
|
||||
|
||||
export function syncAssetFaceV2ToV1(faceV2: SyncAssetFaceV2): SyncAssetFaceV1 {
|
||||
const { deletedAt: _, isVisible: __, ...faceV1 } = faceV2;
|
||||
|
||||
return faceV1;
|
||||
}
|
||||
|
||||
@ExtraModel()
|
||||
export class SyncAssetFaceDeleteV1 {
|
||||
@ApiProperty({ description: 'Asset face ID' })
|
||||
assetFaceId!: string;
|
||||
}
|
||||
|
||||
class SyncAssetFaceDeleteV1 extends createZodDto(SyncAssetFaceDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncUserMetadataV1 {
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
@ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey', description: 'User metadata key' })
|
||||
key!: UserMetadataKey;
|
||||
@ApiProperty({ description: 'User metadata value' })
|
||||
value!: UserMetadata[UserMetadataKey];
|
||||
}
|
||||
|
||||
class SyncUserMetadataV1 extends createZodDto(SyncUserMetadataV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncUserMetadataDeleteV1 {
|
||||
@ApiProperty({ description: 'User ID' })
|
||||
userId!: string;
|
||||
@ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey', description: 'User metadata key' })
|
||||
key!: UserMetadataKey;
|
||||
}
|
||||
|
||||
class SyncUserMetadataDeleteV1 extends createZodDto(SyncUserMetadataDeleteV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncAckV1 {}
|
||||
|
||||
class SyncAckV1 extends createZodDto(SyncAckV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncResetV1 {}
|
||||
|
||||
class SyncResetV1 extends createZodDto(SyncResetV1Schema) {}
|
||||
@ExtraModel()
|
||||
export class SyncCompleteV1 {}
|
||||
class SyncCompleteV1 extends createZodDto(SyncCompleteV1Schema) {}
|
||||
|
||||
export type SyncItem = {
|
||||
[SyncEntityType.AuthUserV1]: SyncAuthUserV1;
|
||||
@@ -541,35 +472,33 @@ export type SyncItem = {
|
||||
[SyncEntityType.SyncResetV1]: SyncResetV1;
|
||||
};
|
||||
|
||||
export class SyncStreamDto {
|
||||
@ValidateEnum({ enum: SyncRequestType, name: 'SyncRequestType', each: true, description: 'Sync request types' })
|
||||
types!: SyncRequestType[];
|
||||
|
||||
@ValidateBoolean({ optional: true, description: 'Reset sync state' })
|
||||
reset?: boolean;
|
||||
}
|
||||
|
||||
export class SyncAckDto {
|
||||
@ValidateEnum({ enum: SyncEntityType, name: 'SyncEntityType', description: 'Sync entity type' })
|
||||
type!: SyncEntityType;
|
||||
@ApiProperty({ description: 'Acknowledgment ID' })
|
||||
ack!: string;
|
||||
}
|
||||
|
||||
export class SyncAckSetDto {
|
||||
@ApiProperty({ description: 'Acknowledgment IDs (max 1000)' })
|
||||
@ArrayMaxSize(1000)
|
||||
@IsString({ each: true })
|
||||
acks!: string[];
|
||||
}
|
||||
|
||||
export class SyncAckDeleteDto {
|
||||
@ValidateEnum({
|
||||
enum: SyncEntityType,
|
||||
name: 'SyncEntityType',
|
||||
optional: true,
|
||||
each: true,
|
||||
description: 'Sync entity types to delete acks for',
|
||||
const SyncStreamSchema = z
|
||||
.object({
|
||||
types: z.array(SyncRequestTypeSchema).describe('Sync request types'),
|
||||
reset: z.boolean().optional().describe('Reset sync state'),
|
||||
})
|
||||
types?: SyncEntityType[];
|
||||
}
|
||||
.meta({ id: 'SyncStreamDto' });
|
||||
|
||||
const SyncAckSchema = z
|
||||
.object({
|
||||
type: SyncEntityTypeSchema,
|
||||
ack: z.string().describe('Acknowledgment ID'),
|
||||
})
|
||||
.meta({ id: 'SyncAckDto' });
|
||||
|
||||
const SyncAckSetSchema = z
|
||||
.object({
|
||||
acks: z.array(z.string()).max(1000).describe('Acknowledgment IDs (max 1000)'),
|
||||
})
|
||||
.meta({ id: 'SyncAckSetDto' });
|
||||
|
||||
const SyncAckDeleteSchema = z
|
||||
.object({
|
||||
types: z.array(SyncEntityTypeSchema).optional().describe('Sync entity types to delete acks for'),
|
||||
})
|
||||
.meta({ id: 'SyncAckDeleteDto' });
|
||||
|
||||
export class SyncStreamDto extends createZodDto(SyncStreamSchema) {}
|
||||
export class SyncAckDto extends createZodDto(SyncAckSchema) {}
|
||||
export class SyncAckSetDto extends createZodDto(SyncAckSetSchema) {}
|
||||
export class SyncAckDeleteDto extends createZodDto(SyncAckDeleteSchema) {}
|
||||
|
||||
Reference in New Issue
Block a user