mirror of
https://github.com/immich-app/immich.git
synced 2025-05-31 12:16:20 -04:00
chore: lifecycle metadata (#9103)
feat(server): track endpoint lifecycle
This commit is contained in:
parent
6eb5d2e95e
commit
59caf1fce4
2
mobile/openapi/doc/AddUsersDto.md
generated
2
mobile/openapi/doc/AddUsersDto.md
generated
@ -9,7 +9,7 @@ import 'package:openapi/api.dart';
|
|||||||
Name | Type | Description | Notes
|
Name | Type | Description | Notes
|
||||||
------------ | ------------- | ------------- | -------------
|
------------ | ------------- | ------------- | -------------
|
||||||
**albumUsers** | [**List<AlbumUserAddDto>**](AlbumUserAddDto.md) | | [default to const []]
|
**albumUsers** | [**List<AlbumUserAddDto>**](AlbumUserAddDto.md) | | [default to const []]
|
||||||
**sharedUserIds** | **List<String>** | Deprecated in favor of albumUsers | [optional] [default to const []]
|
**sharedUserIds** | **List<String>** | This property was deprecated in v1.102.0 | [optional] [default to const []]
|
||||||
|
|
||||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||||
|
|
||||||
|
2
mobile/openapi/doc/AlbumResponseDto.md
generated
2
mobile/openapi/doc/AlbumResponseDto.md
generated
@ -24,7 +24,7 @@ Name | Type | Description | Notes
|
|||||||
**owner** | [**UserResponseDto**](UserResponseDto.md) | |
|
**owner** | [**UserResponseDto**](UserResponseDto.md) | |
|
||||||
**ownerId** | **String** | |
|
**ownerId** | **String** | |
|
||||||
**shared** | **bool** | |
|
**shared** | **bool** | |
|
||||||
**sharedUsers** | [**List<UserResponseDto>**](UserResponseDto.md) | Deprecated in favor of albumUsers | [default to const []]
|
**sharedUsers** | [**List<UserResponseDto>**](UserResponseDto.md) | This property was deprecated in v1.102.0 | [default to const []]
|
||||||
**startDate** | [**DateTime**](DateTime.md) | | [optional]
|
**startDate** | [**DateTime**](DateTime.md) | | [optional]
|
||||||
**updatedAt** | [**DateTime**](DateTime.md) | |
|
**updatedAt** | [**DateTime**](DateTime.md) | |
|
||||||
|
|
||||||
|
2
mobile/openapi/doc/MemoryLaneResponseDto.md
generated
2
mobile/openapi/doc/MemoryLaneResponseDto.md
generated
@ -9,7 +9,7 @@ import 'package:openapi/api.dart';
|
|||||||
Name | Type | Description | Notes
|
Name | Type | Description | Notes
|
||||||
------------ | ------------- | ------------- | -------------
|
------------ | ------------- | ------------- | -------------
|
||||||
**assets** | [**List<AssetResponseDto>**](AssetResponseDto.md) | | [default to const []]
|
**assets** | [**List<AssetResponseDto>**](AssetResponseDto.md) | | [default to const []]
|
||||||
**title** | **String** | |
|
**title** | **String** | This property was deprecated in v1.100.0 |
|
||||||
**yearsAgo** | **int** | |
|
**yearsAgo** | **int** | |
|
||||||
|
|
||||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||||
|
4
mobile/openapi/doc/MetadataSearchDto.md
generated
4
mobile/openapi/doc/MetadataSearchDto.md
generated
@ -36,7 +36,7 @@ Name | Type | Description | Notes
|
|||||||
**page** | **num** | | [optional]
|
**page** | **num** | | [optional]
|
||||||
**personIds** | **List<String>** | | [optional] [default to const []]
|
**personIds** | **List<String>** | | [optional] [default to const []]
|
||||||
**previewPath** | **String** | | [optional]
|
**previewPath** | **String** | | [optional]
|
||||||
**resizePath** | **String** | | [optional]
|
**resizePath** | **String** | This property was deprecated in v1.100.0 | [optional]
|
||||||
**size** | **num** | | [optional]
|
**size** | **num** | | [optional]
|
||||||
**state** | **String** | | [optional]
|
**state** | **String** | | [optional]
|
||||||
**takenAfter** | [**DateTime**](DateTime.md) | | [optional]
|
**takenAfter** | [**DateTime**](DateTime.md) | | [optional]
|
||||||
@ -47,7 +47,7 @@ Name | Type | Description | Notes
|
|||||||
**type** | [**AssetTypeEnum**](AssetTypeEnum.md) | | [optional]
|
**type** | [**AssetTypeEnum**](AssetTypeEnum.md) | | [optional]
|
||||||
**updatedAfter** | [**DateTime**](DateTime.md) | | [optional]
|
**updatedAfter** | [**DateTime**](DateTime.md) | | [optional]
|
||||||
**updatedBefore** | [**DateTime**](DateTime.md) | | [optional]
|
**updatedBefore** | [**DateTime**](DateTime.md) | | [optional]
|
||||||
**webpPath** | **String** | | [optional]
|
**webpPath** | **String** | This property was deprecated in v1.100.0 | [optional]
|
||||||
**withArchived** | **bool** | | [optional] [default to false]
|
**withArchived** | **bool** | | [optional] [default to false]
|
||||||
**withDeleted** | **bool** | | [optional]
|
**withDeleted** | **bool** | | [optional]
|
||||||
**withExif** | **bool** | | [optional]
|
**withExif** | **bool** | | [optional]
|
||||||
|
2
mobile/openapi/lib/model/add_users_dto.dart
generated
2
mobile/openapi/lib/model/add_users_dto.dart
generated
@ -19,7 +19,7 @@ class AddUsersDto {
|
|||||||
|
|
||||||
List<AlbumUserAddDto> albumUsers;
|
List<AlbumUserAddDto> albumUsers;
|
||||||
|
|
||||||
/// Deprecated in favor of albumUsers
|
/// This property was deprecated in v1.102.0
|
||||||
List<String> sharedUserIds;
|
List<String> sharedUserIds;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
2
mobile/openapi/lib/model/album_response_dto.dart
generated
2
mobile/openapi/lib/model/album_response_dto.dart
generated
@ -84,7 +84,7 @@ class AlbumResponseDto {
|
|||||||
|
|
||||||
bool shared;
|
bool shared;
|
||||||
|
|
||||||
/// Deprecated in favor of albumUsers
|
/// This property was deprecated in v1.102.0
|
||||||
List<UserResponseDto> sharedUsers;
|
List<UserResponseDto> sharedUsers;
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -20,6 +20,7 @@ class MemoryLaneResponseDto {
|
|||||||
|
|
||||||
List<AssetResponseDto> assets;
|
List<AssetResponseDto> assets;
|
||||||
|
|
||||||
|
/// This property was deprecated in v1.100.0
|
||||||
String title;
|
String title;
|
||||||
|
|
||||||
int yearsAgo;
|
int yearsAgo;
|
||||||
|
@ -279,6 +279,7 @@ class MetadataSearchDto {
|
|||||||
///
|
///
|
||||||
String? previewPath;
|
String? previewPath;
|
||||||
|
|
||||||
|
/// This property was deprecated in v1.100.0
|
||||||
///
|
///
|
||||||
/// Please note: This property should have been non-nullable! Since the specification file
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
/// does not include a default value (using the "default:" property), however, the generated
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
@ -369,6 +370,7 @@ class MetadataSearchDto {
|
|||||||
///
|
///
|
||||||
DateTime? updatedBefore;
|
DateTime? updatedBefore;
|
||||||
|
|
||||||
|
/// This property was deprecated in v1.100.0
|
||||||
///
|
///
|
||||||
/// Please note: This property should have been non-nullable! Since the specification file
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
/// does not include a default value (using the "default:" property), however, the generated
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
|
2
mobile/openapi/test/add_users_dto_test.dart
generated
2
mobile/openapi/test/add_users_dto_test.dart
generated
@ -21,7 +21,7 @@ void main() {
|
|||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
// Deprecated in favor of albumUsers
|
// This property was deprecated in v1.102.0
|
||||||
// List<String> sharedUserIds (default value: const [])
|
// List<String> sharedUserIds (default value: const [])
|
||||||
test('to test the property `sharedUserIds`', () async {
|
test('to test the property `sharedUserIds`', () async {
|
||||||
// TODO
|
// TODO
|
||||||
|
2
mobile/openapi/test/album_response_dto_test.dart
generated
2
mobile/openapi/test/album_response_dto_test.dart
generated
@ -96,7 +96,7 @@ void main() {
|
|||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
// Deprecated in favor of albumUsers
|
// This property was deprecated in v1.102.0
|
||||||
// List<UserResponseDto> sharedUsers (default value: const [])
|
// List<UserResponseDto> sharedUsers (default value: const [])
|
||||||
test('to test the property `sharedUsers`', () async {
|
test('to test the property `sharedUsers`', () async {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -21,6 +21,7 @@ void main() {
|
|||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This property was deprecated in v1.100.0
|
||||||
// String title
|
// String title
|
||||||
test('to test the property `title`', () async {
|
test('to test the property `title`', () async {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -156,6 +156,7 @@ void main() {
|
|||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This property was deprecated in v1.100.0
|
||||||
// String resizePath
|
// String resizePath
|
||||||
test('to test the property `resizePath`', () async {
|
test('to test the property `resizePath`', () async {
|
||||||
// TODO
|
// TODO
|
||||||
@ -211,6 +212,7 @@ void main() {
|
|||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This property was deprecated in v1.100.0
|
||||||
// String webpPath
|
// String webpPath
|
||||||
test('to test the property `webpPath`', () async {
|
test('to test the property `webpPath`', () async {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -6616,7 +6616,7 @@
|
|||||||
},
|
},
|
||||||
"sharedUserIds": {
|
"sharedUserIds": {
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
"description": "Deprecated in favor of albumUsers",
|
"description": "This property was deprecated in v1.102.0",
|
||||||
"items": {
|
"items": {
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -6721,7 +6721,7 @@
|
|||||||
},
|
},
|
||||||
"sharedUsers": {
|
"sharedUsers": {
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
"description": "Deprecated in favor of albumUsers",
|
"description": "This property was deprecated in v1.102.0",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/UserResponseDto"
|
"$ref": "#/components/schemas/UserResponseDto"
|
||||||
},
|
},
|
||||||
@ -8433,6 +8433,7 @@
|
|||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
|
"description": "This property was deprecated in v1.100.0",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"yearsAgo": {
|
"yearsAgo": {
|
||||||
@ -8640,6 +8641,7 @@
|
|||||||
},
|
},
|
||||||
"resizePath": {
|
"resizePath": {
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
|
"description": "This property was deprecated in v1.100.0",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"size": {
|
"size": {
|
||||||
@ -8682,6 +8684,7 @@
|
|||||||
},
|
},
|
||||||
"webpPath": {
|
"webpPath": {
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
|
"description": "This property was deprecated in v1.100.0",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"withArchived": {
|
"withArchived": {
|
||||||
|
@ -162,7 +162,7 @@ export type AlbumResponseDto = {
|
|||||||
owner: UserResponseDto;
|
owner: UserResponseDto;
|
||||||
ownerId: string;
|
ownerId: string;
|
||||||
shared: boolean;
|
shared: boolean;
|
||||||
/** Deprecated in favor of albumUsers */
|
/** This property was deprecated in v1.102.0 */
|
||||||
sharedUsers: UserResponseDto[];
|
sharedUsers: UserResponseDto[];
|
||||||
startDate?: string;
|
startDate?: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
@ -202,7 +202,7 @@ export type AlbumUserAddDto = {
|
|||||||
};
|
};
|
||||||
export type AddUsersDto = {
|
export type AddUsersDto = {
|
||||||
albumUsers: AlbumUserAddDto[];
|
albumUsers: AlbumUserAddDto[];
|
||||||
/** Deprecated in favor of albumUsers */
|
/** This property was deprecated in v1.102.0 */
|
||||||
sharedUserIds?: string[];
|
sharedUserIds?: string[];
|
||||||
};
|
};
|
||||||
export type ApiKeyResponseDto = {
|
export type ApiKeyResponseDto = {
|
||||||
@ -273,6 +273,7 @@ export type MapMarkerResponseDto = {
|
|||||||
};
|
};
|
||||||
export type MemoryLaneResponseDto = {
|
export type MemoryLaneResponseDto = {
|
||||||
assets: AssetResponseDto[];
|
assets: AssetResponseDto[];
|
||||||
|
/** This property was deprecated in v1.100.0 */
|
||||||
title: string;
|
title: string;
|
||||||
yearsAgo: number;
|
yearsAgo: number;
|
||||||
};
|
};
|
||||||
@ -637,6 +638,7 @@ export type MetadataSearchDto = {
|
|||||||
page?: number;
|
page?: number;
|
||||||
personIds?: string[];
|
personIds?: string[];
|
||||||
previewPath?: string;
|
previewPath?: string;
|
||||||
|
/** This property was deprecated in v1.100.0 */
|
||||||
resizePath?: string;
|
resizePath?: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
state?: string;
|
state?: string;
|
||||||
@ -648,6 +650,7 @@ export type MetadataSearchDto = {
|
|||||||
"type"?: AssetTypeEnum;
|
"type"?: AssetTypeEnum;
|
||||||
updatedAfter?: string;
|
updatedAfter?: string;
|
||||||
updatedBefore?: string;
|
updatedBefore?: string;
|
||||||
|
/** This property was deprecated in v1.100.0 */
|
||||||
webpPath?: string;
|
webpPath?: string;
|
||||||
withArchived?: boolean;
|
withArchived?: boolean;
|
||||||
withDeleted?: boolean;
|
withDeleted?: boolean;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"test:watch": "vitest --watch",
|
"test:watch": "vitest --watch",
|
||||||
"test:cov": "vitest --coverage",
|
"test:cov": "vitest --coverage",
|
||||||
"typeorm": "typeorm",
|
"typeorm": "typeorm",
|
||||||
|
"lifecycle": "node ./dist/utils/lifecycle.js",
|
||||||
"typeorm:migrations:create": "typeorm migration:create",
|
"typeorm:migrations:create": "typeorm migration:create",
|
||||||
"typeorm:migrations:generate": "typeorm migration:generate -d ./dist/database.config.js",
|
"typeorm:migrations:generate": "typeorm migration:generate -d ./dist/database.config.js",
|
||||||
"typeorm:migrations:run": "typeorm migration:run -d ./dist/database.config.js",
|
"typeorm:migrations:run": "typeorm migration:run -d ./dist/database.config.js",
|
||||||
|
@ -3,6 +3,11 @@ import { readFileSync } from 'node:fs';
|
|||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import { Version } from 'src/utils/version';
|
import { Version } from 'src/utils/version';
|
||||||
|
|
||||||
|
export const NEXT_RELEASE = 'NEXT_RELEASE';
|
||||||
|
export const LIFECYCLE_EXTENSION = 'x-immich-lifecycle';
|
||||||
|
export const DEPRECATED_IN_PREFIX = 'This property was deprecated in ';
|
||||||
|
export const ADDED_IN_PREFIX = 'This property was added in ';
|
||||||
|
|
||||||
export const SALT_ROUNDS = 10;
|
export const SALT_ROUNDS = 10;
|
||||||
|
|
||||||
const { version } = JSON.parse(readFileSync('./package.json', 'utf8'));
|
const { version } = JSON.parse(readFileSync('./package.json', 'utf8'));
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { SetMetadata } from '@nestjs/common';
|
import { SetMetadata, applyDecorators } from '@nestjs/common';
|
||||||
import { OnEvent } from '@nestjs/event-emitter';
|
import { OnEvent } from '@nestjs/event-emitter';
|
||||||
import { OnEventOptions } from '@nestjs/event-emitter/dist/interfaces';
|
import { OnEventOptions } from '@nestjs/event-emitter/dist/interfaces';
|
||||||
|
import { ApiExtension, ApiOperation, ApiProperty, ApiTags } from '@nestjs/swagger';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { ADDED_IN_PREFIX, DEPRECATED_IN_PREFIX, LIFECYCLE_EXTENSION } from 'src/constants';
|
||||||
import { ServerAsyncEvent, ServerEvent } from 'src/interfaces/event.interface';
|
import { ServerAsyncEvent, ServerEvent } from 'src/interfaces/event.interface';
|
||||||
import { setUnion } from 'src/utils/set';
|
import { setUnion } from 'src/utils/set';
|
||||||
|
|
||||||
@ -128,3 +130,31 @@ export const GenerateSql = (...options: GenerateSqlQueries[]) => SetMetadata(GEN
|
|||||||
|
|
||||||
export const OnServerEvent = (event: ServerEvent | ServerAsyncEvent, options?: OnEventOptions) =>
|
export const OnServerEvent = (event: ServerEvent | ServerAsyncEvent, options?: OnEventOptions) =>
|
||||||
OnEvent(event, { suppressErrors: false, ...options });
|
OnEvent(event, { suppressErrors: false, ...options });
|
||||||
|
|
||||||
|
type LifecycleRelease = 'NEXT_RELEASE' | string;
|
||||||
|
type LifecycleMetadata = {
|
||||||
|
addedAt?: LifecycleRelease;
|
||||||
|
deprecatedAt?: LifecycleRelease;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EndpointLifecycle = ({ addedAt, deprecatedAt }: LifecycleMetadata) => {
|
||||||
|
const decorators: MethodDecorator[] = [ApiExtension(LIFECYCLE_EXTENSION, { addedAt, deprecatedAt })];
|
||||||
|
if (deprecatedAt) {
|
||||||
|
decorators.push(
|
||||||
|
ApiTags('Deprecated'),
|
||||||
|
ApiOperation({ deprecated: true, description: DEPRECATED_IN_PREFIX + deprecatedAt }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return applyDecorators(...decorators);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PropertyLifecycle = ({ addedAt, deprecatedAt }: LifecycleMetadata) => {
|
||||||
|
const decorators: PropertyDecorator[] = [];
|
||||||
|
decorators.push(ApiProperty({ description: ADDED_IN_PREFIX + addedAt }));
|
||||||
|
if (deprecatedAt) {
|
||||||
|
decorators.push(ApiProperty({ deprecated: true, description: DEPRECATED_IN_PREFIX + deprecatedAt }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return applyDecorators(...decorators);
|
||||||
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { ArrayNotEmpty, IsEnum, IsString } from 'class-validator';
|
import { ArrayNotEmpty, IsEnum, IsString } from 'class-validator';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { PropertyLifecycle } from 'src/decorators';
|
||||||
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
|
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { UserResponseDto, mapUser } from 'src/dtos/user.dto';
|
import { UserResponseDto, mapUser } from 'src/dtos/user.dto';
|
||||||
@ -25,7 +26,7 @@ export class AlbumUserAddDto {
|
|||||||
export class AddUsersDto {
|
export class AddUsersDto {
|
||||||
@ValidateUUID({ each: true, optional: true })
|
@ValidateUUID({ each: true, optional: true })
|
||||||
@ArrayNotEmpty()
|
@ArrayNotEmpty()
|
||||||
@ApiProperty({ deprecated: true, description: 'Deprecated in favor of albumUsers' })
|
@PropertyLifecycle({ deprecatedAt: 'v1.102.0' })
|
||||||
sharedUserIds?: string[];
|
sharedUserIds?: string[];
|
||||||
|
|
||||||
@ArrayNotEmpty()
|
@ArrayNotEmpty()
|
||||||
@ -119,7 +120,7 @@ export class AlbumResponseDto {
|
|||||||
updatedAt!: Date;
|
updatedAt!: Date;
|
||||||
albumThumbnailAssetId!: string | null;
|
albumThumbnailAssetId!: string | null;
|
||||||
shared!: boolean;
|
shared!: boolean;
|
||||||
@ApiProperty({ deprecated: true, description: 'Deprecated in favor of albumUsers' })
|
@PropertyLifecycle({ deprecatedAt: 'v1.102.0' })
|
||||||
sharedUsers!: UserResponseDto[];
|
sharedUsers!: UserResponseDto[];
|
||||||
albumUsers!: AlbumUserResponseDto[];
|
albumUsers!: AlbumUserResponseDto[];
|
||||||
hasSharedLink!: boolean;
|
hasSharedLink!: boolean;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { PropertyLifecycle } from 'src/decorators';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { ExifResponseDto, mapExif } from 'src/dtos/exif.dto';
|
import { ExifResponseDto, mapExif } from 'src/dtos/exif.dto';
|
||||||
import { PersonWithFacesResponseDto, mapFacesWithoutPerson, mapPerson } from 'src/dtos/person.dto';
|
import { PersonWithFacesResponseDto, mapFacesWithoutPerson, mapPerson } from 'src/dtos/person.dto';
|
||||||
@ -131,7 +132,7 @@ export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): As
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MemoryLaneResponseDto {
|
export class MemoryLaneResponseDto {
|
||||||
@ApiProperty({ deprecated: true })
|
@PropertyLifecycle({ deprecatedAt: 'v1.100.0' })
|
||||||
title!: string;
|
title!: string;
|
||||||
|
|
||||||
@ApiProperty({ type: 'integer' })
|
@ApiProperty({ type: 'integer' })
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { IsEnum, IsInt, IsNotEmpty, IsString, Max, Min } from 'class-validator';
|
import { IsEnum, IsInt, IsNotEmpty, IsString, Max, Min } from 'class-validator';
|
||||||
|
import { PropertyLifecycle } from 'src/decorators';
|
||||||
import { AlbumResponseDto } from 'src/dtos/album.dto';
|
import { AlbumResponseDto } from 'src/dtos/album.dto';
|
||||||
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
import { AssetResponseDto } from 'src/dtos/asset-response.dto';
|
||||||
import { AssetOrder } from 'src/entities/album.entity';
|
import { AssetOrder } from 'src/entities/album.entity';
|
||||||
@ -163,13 +164,13 @@ export class MetadataSearchDto extends BaseSearchDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@Optional()
|
@Optional()
|
||||||
@ApiProperty({ deprecated: true })
|
@PropertyLifecycle({ deprecatedAt: 'v1.100.0' })
|
||||||
resizePath?: string;
|
resizePath?: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@Optional()
|
@Optional()
|
||||||
@ApiProperty({ deprecated: true })
|
@PropertyLifecycle({ deprecatedAt: 'v1.100.0' })
|
||||||
webpPath?: string;
|
webpPath?: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
|
93
server/src/utils/lifecycle.ts
Normal file
93
server/src/utils/lifecycle.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import { OpenAPIObject } from '@nestjs/swagger';
|
||||||
|
import { SchemaObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
import { ADDED_IN_PREFIX, DEPRECATED_IN_PREFIX, LIFECYCLE_EXTENSION, NEXT_RELEASE } from 'src/constants';
|
||||||
|
import { Version } from 'src/utils/version';
|
||||||
|
|
||||||
|
const outputPath = resolve(process.cwd(), '../open-api/immich-openapi-specs.json');
|
||||||
|
const spec = JSON.parse(readFileSync(outputPath).toString()) as OpenAPIObject;
|
||||||
|
|
||||||
|
type Items = {
|
||||||
|
oldEndpoints: Endpoint[];
|
||||||
|
newEndpoints: Endpoint[];
|
||||||
|
oldProperties: Property[];
|
||||||
|
newProperties: Property[];
|
||||||
|
};
|
||||||
|
type Endpoint = { url: string; method: string; endpoint: any };
|
||||||
|
type Property = { schema: string; property: string };
|
||||||
|
|
||||||
|
const metadata: Record<string, Items> = {};
|
||||||
|
const trackVersion = (version: string) => {
|
||||||
|
if (!metadata[version]) {
|
||||||
|
metadata[version] = {
|
||||||
|
oldEndpoints: [],
|
||||||
|
newEndpoints: [],
|
||||||
|
oldProperties: [],
|
||||||
|
newProperties: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return metadata[version];
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [url, methods] of Object.entries(spec.paths)) {
|
||||||
|
for (const [method, endpoint] of Object.entries(methods) as Array<[string, any]>) {
|
||||||
|
const deprecatedAt = endpoint[LIFECYCLE_EXTENSION]?.deprecatedAt;
|
||||||
|
if (deprecatedAt) {
|
||||||
|
trackVersion(deprecatedAt).oldEndpoints.push({ url, method, endpoint });
|
||||||
|
}
|
||||||
|
|
||||||
|
const addedAt = endpoint[LIFECYCLE_EXTENSION]?.addedAt;
|
||||||
|
if (addedAt) {
|
||||||
|
trackVersion(addedAt).newEndpoints.push({ url, method, endpoint });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [schemaName, schema] of Object.entries(spec.components?.schemas || {})) {
|
||||||
|
for (const [propertyName, property] of Object.entries((schema as SchemaObject).properties || {})) {
|
||||||
|
const propertySchema = property as SchemaObject;
|
||||||
|
if (propertySchema.description?.startsWith(DEPRECATED_IN_PREFIX)) {
|
||||||
|
const deprecatedAt = propertySchema.description.replace(DEPRECATED_IN_PREFIX, '').trim();
|
||||||
|
trackVersion(deprecatedAt).oldProperties.push({ schema: schemaName, property: propertyName });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propertySchema.description?.startsWith(ADDED_IN_PREFIX)) {
|
||||||
|
const addedAt = propertySchema.description.replace(ADDED_IN_PREFIX, '').trim();
|
||||||
|
trackVersion(addedAt).newProperties.push({ schema: schemaName, property: propertyName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedVersions = Object.keys(metadata).sort((a, b) => {
|
||||||
|
if (a === NEXT_RELEASE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b === NEXT_RELEASE) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const versionA = Version.fromString(a);
|
||||||
|
const versionB = Version.fromString(b);
|
||||||
|
return versionB.compareTo(versionA);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const version of sortedVersions) {
|
||||||
|
const { oldEndpoints, newEndpoints, oldProperties, newProperties } = metadata[version];
|
||||||
|
console.log(`\nChanges in ${version}`);
|
||||||
|
console.log('---------------------');
|
||||||
|
for (const { url, method, endpoint } of oldEndpoints) {
|
||||||
|
console.log(`- Deprecated ${method.toUpperCase()} ${url} (${endpoint.operationId})`);
|
||||||
|
}
|
||||||
|
for (const { url, method, endpoint } of newEndpoints) {
|
||||||
|
console.log(`- Added ${method.toUpperCase()} ${url} (${endpoint.operationId})`);
|
||||||
|
}
|
||||||
|
for (const { schema, property } of oldProperties) {
|
||||||
|
console.log(`- Deprecated ${schema}.${property}`);
|
||||||
|
}
|
||||||
|
for (const { schema, property } of newProperties) {
|
||||||
|
console.log(`- Added ${schema}.${property}`);
|
||||||
|
}
|
||||||
|
}
|
@ -61,4 +61,12 @@ export class Version implements IVersion {
|
|||||||
const [bool, type] = this.compare(version);
|
const [bool, type] = this.compare(version);
|
||||||
return bool > 0 ? type : VersionType.EQUAL;
|
return bool > 0 ? type : VersionType.EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compareTo(other: Version) {
|
||||||
|
if (this.isEqual(other)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.isNewerThan(other) ? 1 : -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user